/* ============================================================
   Collection — feuille de style principale
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Baloo+2:wght@500;700;800&family=Inter:wght@400;500;600&display=swap');

/* CSS officiel pokemon-cards-css (simeydotme, GPL-3.0) vendorisé tel quel dans cards/
   (seuls les chemins /img/ ont été adaptés). Voir la section « glue » plus bas. */
@import url('cards/base.css');
@import url('cards.css');
@import url('cards/basic.css');
@import url('cards/regular-holo.css');
@import url('cards/cosmos-holo.css');
@import url('cards/reverse-holo.css');
@import url('cards/amazing-rare.css');
@import url('cards/rainbow-holo.css');
@import url('cards/secret-rare.css');
@import url('cards/v-regular.css');
@import url('cards/v-max.css');
@import url('cards/v-star.css');
@import url('cards/radiant-holo.css');

:root {
  --color-bg:          #F2F4F8;
  --color-card:        #FFFFFF;
  --color-text:        #1F2937;
  --color-heading:     #15233D;
  --color-muted:       #6B7280;
  --color-border:      #E2E4E9;
  --color-error:       #B3261E;
  --color-error-bg:    #FBEAE9;
  --color-success:     #1E7B34;
  --color-success-bg:  #EAF6EC;
  --radius:            14px;
  --font-heading:      'Baloo 2', sans-serif;
  --font-body:         'Inter', sans-serif;
  --topbar-h:          60px;
  --accent:            #2563EB;
  --accent-dark:       #1D4ED8;
}

[data-couleur="bleu"]   { --accent: #2563EB; --accent-dark: #1D4ED8; }
[data-couleur="vert"]   { --accent: #059669; --accent-dark: #047857; }
[data-couleur="rouge"]  { --accent: #DC2626; --accent-dark: #B91C1C; }
[data-couleur="violet"] { --accent: #9333EA; --accent-dark: #7E22CE; }
[data-couleur="orange"] { --accent: #EA580C; --accent-dark: #C2410C; }
[data-couleur="rose"]   { --accent: #DB2777; --accent-dark: #BE185D; }
[data-couleur="jaune"]  { --accent: #CA8A04; --accent-dark: #A16207; }
[data-couleur="cyan"]   { --accent: #0891B2; --accent-dark: #0E7490; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-body);
  background: var(--color-bg);
  color: var(--color-text);
  min-height: 100vh;
}
h1, h2, h3, .titre { font-family: var(--font-heading); color: var(--color-heading); }
a { color: var(--accent); }
button { font-family: inherit; }

.conteneur {
  max-width: 1100px;
  margin: 0 auto;
  padding: 1.5rem 1rem 3rem;
}
.conteneur-centre { text-align: center; padding-top: 3rem; }
.msg-etroit { max-width: 400px; margin: 1rem auto; }
.masque { display: none !important; }
.form-nouveau-profil { max-width: 420px; margin: 0 auto; text-align: left; }

/* ── Boutons ─────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .65rem 1.2rem;
  border-radius: 999px;
  border: none;
  font-weight: 600;
  font-size: .95rem;
  cursor: pointer;
  text-decoration: none;
  transition: transform .1s ease, box-shadow .15s ease;
}
.btn:active { transform: scale(.97); }
.btn-primaire { background: var(--accent); color: #fff; box-shadow: 0 4px 14px -4px var(--accent); }
.btn-primaire:hover { background: var(--accent-dark); }
.btn-secondaire { background: #fff; color: var(--color-text); border: 1px solid var(--color-border); }
.btn-danger { background: var(--color-error-bg); color: var(--color-error); }
.btn-petit { padding: .4rem .8rem; font-size: .82rem; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ── Formulaires ─────────────────────────────────────────── */
.champ { margin-bottom: 1rem; display: flex; flex-direction: column; gap: .35rem; }
.champ label { font-weight: 600; font-size: .88rem; }
.champ input, .champ select, .champ textarea {
  padding: .6rem .7rem;
  border: 1px solid var(--color-border);
  border-radius: 10px;
  font-family: inherit;
  font-size: .95rem;
  background: #fff;
}
.champ small { color: var(--color-muted); font-size: .8rem; }
.msg { padding: .7rem 1rem; border-radius: 10px; font-size: .9rem; margin-bottom: 1rem; }
.msg-erreur { background: var(--color-error-bg); color: var(--color-error); }
.msg-succes { background: var(--color-success-bg); color: var(--color-success); }

.carte-panneau {
  background: var(--color-card);
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  padding: 1.25rem;
  margin-bottom: 1.25rem;
}

table.table-liste { width: 100%; border-collapse: collapse; }
table.table-liste th, table.table-liste td {
  text-align: left; padding: .6rem .5rem; border-bottom: 1px solid var(--color-border); font-size: .9rem;
}
table.table-liste th { color: var(--color-muted); font-weight: 600; font-size: .8rem; text-transform: uppercase; }
.cellule-actions { display: flex; gap: .4rem; flex-wrap: wrap; }
.cellule-actions form { display: inline; }

/* ── Topbar ──────────────────────────────────────────────── */
.topbar {
  height: var(--topbar-h);
  display: flex; align-items: center; gap: 1.5rem;
  padding: 0 1.25rem;
  background: var(--color-heading);
  color: #fff;
  position: sticky; top: 0; z-index: 50;
}
.topbar-titre {
  display: flex; align-items: center; gap: .5rem;
  color: #fff; text-decoration: none;
  font-family: var(--font-heading); font-weight: 800; font-size: 1.15rem;
}
.topbar-nav { display: flex; gap: .25rem; margin-left: auto; }
.topbar-lien {
  color: rgba(255,255,255,.8); text-decoration: none; padding: .5rem .8rem; border-radius: 8px; font-size: .9rem; font-weight: 500;
}
.topbar-lien:hover, .topbar-lien.actif { background: rgba(255,255,255,.12); color: #fff; }
.topbar-prefs { padding: .5rem .55rem; font-size: 1.05rem; }
.topbar-depense { font-size: .85rem; font-weight: 600; color: #ffd76a; white-space: nowrap; }
.topbar-profil {
  display: flex; align-items: center; gap: .5rem;
  color: #fff; text-decoration: none;
  padding: .3rem .7rem .3rem .3rem;
  border-radius: 999px;
  background: rgba(255,255,255,.1);
  font-size: .85rem;
}
.topbar-avatar {
  width: 28px; height: 28px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); font-size: 1rem;
}

/* ── Écran de profils ────────────────────────────────────── */
.profils-grille {
  display: flex; flex-wrap: wrap; gap: 1.5rem; justify-content: center; margin: 2rem 0;
}
.profil-tuile {
  background: none; border: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: .6rem;
  color: var(--color-text);
  padding: .5rem;
  border-radius: 12px;
}
.profil-tuile:hover .profil-avatar { transform: scale(1.06); box-shadow: 0 0 0 4px #fff, 0 0 0 6px var(--accent); }
.profil-avatar {
  width: 96px; height: 96px; border-radius: 16px;
  display: flex; align-items: center; justify-content: center;
  font-size: 2.6rem;
  background: var(--accent);
  transition: transform .15s ease, box-shadow .15s ease;
}
.profil-nom { font-weight: 600; }
.profil-tuile-ajout .profil-avatar { background: #fff; border: 2px dashed var(--color-border); color: var(--color-muted); }

/* ── Accueil / choix de collection ──────────────────────────*/
.collections-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1.25rem;
}
.collection-tuile {
  background: var(--color-card); border-radius: var(--radius); border: 1px solid var(--color-border);
  padding: 1.25rem; text-decoration: none; color: var(--color-text);
  display: flex; flex-direction: column; gap: .5rem;
  transition: transform .15s ease, box-shadow .15s ease;
}
.collection-tuile:hover { transform: translateY(-3px); box-shadow: 0 10px 24px -12px rgba(0,0,0,.25); }
.collection-tuile h3 { margin: 0; }
.collection-progres { height: 8px; border-radius: 999px; background: var(--color-border); overflow: hidden; }
.collection-progres > span { display: block; height: 100%; width: 0; background: var(--accent); transition: width .4s ease; }
.collection-actions { display: flex; gap: .5rem; margin-top: .4rem; flex-wrap: wrap; }
.collection-theme { color: var(--color-muted); font-size: .85rem; margin: -.3rem 0 0; }

/* ── Tirage / pack opening ──────────────────────────────────*/
.tirage-zone { text-align: center; padding: 2rem 0; }

/* ── Ouverture d'un paquet tiré : le paquet fermé attend un clic, se secoue puis éclate
   (app.js enchaîne sur la révélation des cartes à la fin de « paquet-disparait »). ── */
.paquet-ouverture {
  display: flex; flex-direction: column; align-items: center; gap: 1.1rem;
  margin: 1.6rem auto; width: fit-content; cursor: pointer; user-select: none;
}
.paquet-ouverture-corps { transition: transform .2s ease; }
.paquet-ouverture:hover .paquet-ouverture-corps { transform: scale(1.04) rotate(-1.5deg); }
.paquet-ouverture-img {
  display: block; max-height: 45vh; max-width: min(90vw, 420px);
  filter: drop-shadow(0 18px 30px rgba(0,0,0,.35));
}
.paquet-ouverture-defaut {
  width: min(64vw, 270px); aspect-ratio: 3 / 4; border-radius: 14px;
  background: linear-gradient(150deg, var(--accent), var(--accent-dark));
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .8rem;
  color: #fff; padding: 1rem; text-align: center;
  box-shadow: 0 18px 30px rgba(0,0,0,.35);
}
.paquet-ouverture-defaut span { font-size: 4rem; }
.paquet-ouverture-hint { margin: 0; font-weight: 600; }
.paquet-ouverture--ouvre { pointer-events: none; }
.paquet-ouverture--ouvre .paquet-ouverture-hint { opacity: 0; transition: opacity .3s ease; }
.paquet-ouverture--ouvre .paquet-ouverture-corps {
  animation: paquet-secoue .3s ease-in-out 3, paquet-disparait .45s ease-in .9s forwards;
}
@keyframes paquet-secoue {
  0%, 100% { transform: rotate(0deg) scale(1); }
  25% { transform: rotate(-4deg) scale(1.04); }
  75% { transform: rotate(4deg) scale(1.04); }
}
@keyframes paquet-disparait {
  0%   { transform: scale(1);    opacity: 1; filter: brightness(1); }
  60%  { transform: scale(1.28); opacity: 1; filter: brightness(1.7); }
  100% { transform: scale(1.65); opacity: 0; filter: brightness(2.4); }
}

/* ── Fenêtre de choix des paquets (accueil) ── */
.paquets-modal { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; padding: 1rem; }
.paquets-modal-fond { position: absolute; inset: 0; background: rgba(10, 14, 25, .55); backdrop-filter: blur(3px); }
.paquets-modal-boite {
  position: relative; background: #fff; border-radius: 16px;
  width: min(92vw, 760px); max-height: 86vh; overflow-y: auto;
  padding: 1.2rem 1.4rem 1.5rem;
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, .5);
}
.paquets-modal-entete { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: 1rem; }
.paquets-modal-entete h2 { margin: 0; font-size: 1.15rem; }
.paquets-modal-fermer {
  border: none; background: transparent; font: inherit; font-size: 1.25rem;
  cursor: pointer; line-height: 1; padding: .35rem .55rem; border-radius: 8px;
}
.paquets-modal-fermer:hover { background: rgba(0, 0, 0, .08); }
.paquets-liste { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; }
.paquet-tuile {
  display: flex; flex-direction: column; align-items: center; gap: .5rem;
  width: 205px; padding: 1rem; border-radius: 14px;
  border: 2px solid var(--color-border); background: #fff;
  cursor: pointer; font: inherit; text-align: center;
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.paquet-tuile:hover:not(:disabled) {
  transform: translateY(-4px); border-color: var(--accent);
  box-shadow: 0 14px 30px -12px rgba(0, 0, 0, .35);
}
.paquet-tuile:disabled { opacity: .55; cursor: not-allowed; filter: grayscale(.6); }
.paquet-visuel { width: 125px; height: 150px; display: flex; align-items: center; justify-content: center; }
.paquet-visuel img { max-width: 100%; max-height: 100%; object-fit: contain; filter: drop-shadow(0 8px 14px rgba(0, 0, 0, .25)); }
.paquet-visuel-defaut {
  width: 100%; height: 100%; border-radius: 12px; font-size: 3.2rem;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(150deg, var(--accent), var(--accent-dark));
}
.paquet-libelle { font-weight: 700; }
.paquet-prix { font-weight: 700; border-radius: 999px; padding: .15rem .75rem; font-size: .85rem; }
.paquet-prix--gratuit { background: var(--color-success-bg); color: var(--color-success); }
.paquet-prix--payant { background: #fff3cd; color: #7a5b00; }
.paquet-note { font-size: .78rem; opacity: .75; }
.paquet-note--epuise { color: var(--color-error); opacity: 1; font-weight: 600; }
.paquet-mini { max-width: 46px; max-height: 60px; }
.tirage-actions { margin-top: 2rem; display: flex; gap: .75rem; justify-content: center; }
.tirage-overlay {
  position: fixed; inset: 0; background: rgba(15,17,23,.85);
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 1.5rem;
  z-index: 200; padding: 2rem;
}
.tirage-overlay[hidden] { display: none; }
.tirage-fermer {
  position: absolute; top: 1.25rem; right: 1.25rem;
  background: rgba(255,255,255,.12); color: #fff; border: none; border-radius: 999px;
  width: 40px; height: 40px; font-size: 1.2rem; cursor: pointer;
}
.paquet-carte-slot { width: 240px; height: 180px; margin: 0 auto; }   /* horizontal 1024×768 */
.paquet-carte-slot.paquet-carte-slot--vertical   { width: 180px; height: 240px; }
.paquet-carte-slot.paquet-carte-slot--carre      { width: 200px; height: 200px; }
.paquet-carte-slot.paquet-carte-slot--rond       { width: 200px; height: 200px; }

/* ============================================================
   Cartes à collectionner — GLUE d'intégration pokemon-cards-css.
   La 3D, les effets et les variables sont gérés par le CSS vendorisé (cards/) sur la
   structure .card > .card__translater > .card__rotator > .card__front. Ici : formats du
   site (via --card-aspect), calage dans les conteneurs, couches internes, interface.
   ============================================================ */
.card.carte {
  /* valeurs par défaut des variables attendues par cards/base.css (app.js les anime) */
  --pointer-x: 50%; --pointer-y: 50%;
  --pointer-from-center: 0; --pointer-from-top: .5; --pointer-from-left: .5;
  --card-opacity: 0;
  --rotate-x: 0deg; --rotate-y: 0deg;
  --background-x: 50%; --background-y: 50%;
  --card-scale: 1; --translate-x: 0px; --translate-y: 0px;
  /* legacy (parallaxe du calque) */
  --mx: 50%; --my: 50%;
  /* nos cartes n'ont pas le gabarit Pokémon : les découpes (fenêtre d'illustration…)
     couvrent toute la carte */
  --clip: inset(0); --clip-invert: inset(0);
  --clip-stage: inset(0); --clip-stage-invert: inset(0);
  --clip-trainer: inset(0); --clip-borders: inset(0);
  width: 100%;
  position: relative;
  cursor: grab;
}
/* Formats du site : on pilote la variable d'aspect du projet d'origine. */
.card.carte--horizontal { --card-aspect: 1024 / 768; }
.card.carte--vertical   { --card-aspect: 768 / 1024; }
.card.carte--carre      { --card-aspect: 1 / 1; }
.card.carte--rond       { --card-aspect: 1 / 1; --card-radius: 50%; }
/* La carte remplit la hauteur donnée par son conteneur (zones, pioche…). */
.card.carte .card__translater, .card.carte .card__rotator { width: 100%; height: 100%; }
/* Transitions douces hors interaction (le JS pose les variables sans spring). */
.card.interactive:not(.interacting) .card__rotator { transition: transform .5s ease, box-shadow .4s ease; }
.card.interactive:not(.interacting) .card__shine,
.card.interactive:not(.interacting) .card__glare { transition: opacity .4s ease; }
/* Face avant utilisable aussi hors rotator (recto du tirage) */
.card__front { display: grid; width: 100%; height: 100%; position: relative; }
.card__front > * { grid-area: 1 / 1; }
/* Couches internes de la face avant */
.carte-fond { position: absolute; inset: 0; }
.carte-image {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
/* Interface (numéro, légende) au-dessus des effets, réinitialisée des styles génériques
   que cards/base.css applique à tous les descendants du rotator (.card__rotator *). */
.card.carte .carte-ui {
  position: absolute; inset: 0; pointer-events: none;
  transform: translateZ(1.5px);
  overflow: hidden; border-radius: var(--card-radius);
}
.card.carte .carte-ui * {
  width: auto; height: auto; display: revert; grid-area: auto;
  aspect-ratio: auto; border-radius: revert; overflow: revert;
}
.carte-legende {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: .5rem .6rem;
  background: linear-gradient(0deg, rgba(0,0,0,.72), transparent);
  color: #fff;
  display: flex; flex-direction: column; gap: .15rem;
}
.carte-legende-nom { font-size: .78rem; font-weight: 600; }
.carte-legende-desc {
  font-size: .68rem; font-weight: 400; line-height: 1.3;
  color: rgba(255,255,255,.88);
  max-height: 4.5em; overflow-y: auto;
}
.carte-numero {
  position: absolute; top: .4rem; right: .5rem;
  background: rgba(0,0,0,.55); color: #fff; font-size: .7rem; font-weight: 700;
  border-radius: 999px; padding: .1rem .5rem;
}
/* Fonds unis.
   'std' = AUCUN fond : les zones transparentes du PNG laissent voir la page / l'arrière-plan
   (un dégradé ne serait de toute façon jamais visible derrière une image opaque en object-fit:cover
   — il ne servait qu'à remplir de gris les parties transparentes, ce qui n'est pas voulu). */
.fond-std       { background: none; }
.fond-alt1      { background: linear-gradient(160deg, #FDE9D9, #F7C99B); }
.fond-alt2      { background: linear-gradient(160deg, #D9F0E6, #9FD9BF); }

/* ============================================================
   Effets holographiques : code OFFICIEL pokemon-cards-css (importé en tête de feuille).
   data-rarity sur .card sélectionne l'effet (voir fondsCatalogue → fondRarity). app.js pose
   les variables --pointer-*, --rotate-*, --background-*, --card-opacity, --mask, --foil,
   --seedx/--seedy/--cosmosbg. Ci-dessous : fonds de base + halo paramétrable par carte.
   ============================================================ */

/* Fonds de base sous l'image. AUCUN fond pour la famille holo : ce dégradé n'était visible que
   dans les zones TRANSPARENTES du PNG (une image opaque le couvre entièrement en object-fit:cover)
   — il y peignait donc une boîte bleu-gris au repos. Transparent → la page se voit au travers.
   L'effet holographique vient des couches shine/glare (data-rarity), pas de .carte-fond. */
.fond-holo, .fond-reverse, .fond-amazing, .fond-rainbow,
.fond-v, .fond-vmax, .fond-vstar, .fond-radiant {
  background: none;
}
/* Gold et cosmos gardent un fond coloré VOLONTAIRE (métal doré / ciel étoilé) qui fait partie
   de l'effet ; mettre `background: none` ici si l'on veut aussi les rendre transparents. */
.fond-gold   { background: linear-gradient(160deg, #6a5326, #b8942f 45%, #f6e29a 60%, #8a6d2b); }
.fond-cosmos { background: #0b1030; }

/* Halo (glare) paramétrable par carte : même formule que cards/base.css, avec
   --halo-k (contraste, 1 = réglage 60 %) et --halo-r (taille, 150 % = réglage 45 %),
   posés par app.js depuis data-halo-contraste / data-halo-taille. Aux valeurs par
   défaut, le rendu est identique à l'original. */
.card.carte .card__glare {
  background-image: radial-gradient(
    var(--halo-r, 150%) var(--halo-r, 150%) at var(--pointer-x) var(--pointer-y),
    hsla(0, 0%, 100%, calc(0.8 * var(--halo-k, 1))) 10%,
    hsla(0, 0%, 100%, calc(0.65 * var(--halo-k, 1))) 20%,
    hsla(0, 0%, 0%, calc(0.5 * var(--halo-k, 1))) 90%
  );
}

/* ── Animation « veille » des cartes holo : au repos (sans survol), un léger balayage
   lumineux périodique signale qu'une carte est holographique — indispensable quand
   l'animation au survol est désactivée (préférence par profil), utile aussi sinon.
   Elle anime les variables du modèle pokemon-cards-css, ce qui exige @property
   (interpolation typée) : app.js pose la classe holo-anim sur <html> quand le navigateur
   le gère. Les animations CSS priment sur les styles inline → le balayage l'emporte au
   repos et cesse dès que .interacting rend la main aux variables posées par app.js. ── */
@property --card-opacity { syntax: '<number>'; inherits: true; initial-value: 0; }
@property --pointer-x { syntax: '<percentage>'; inherits: true; initial-value: 50%; }
@property --pointer-y { syntax: '<percentage>'; inherits: true; initial-value: 50%; }
@property --background-x { syntax: '<percentage>'; inherits: true; initial-value: 50%; }
@property --background-y { syntax: '<percentage>'; inherits: true; initial-value: 50%; }
@property --pointer-from-left { syntax: '<number>'; inherits: true; initial-value: 0.5; }
@property --pointer-from-top { syntax: '<number>'; inherits: true; initial-value: 0.5; }
@property --pointer-from-center { syntax: '<number>'; inherits: true; initial-value: 0; }

@media (prefers-reduced-motion: no-preference) {
  html.holo-anim .card.carte--brillant:not(.interacting),
  html.holo-anim .zone-puzzle-grille[data-groupe-init]:not(.interacting):not([data-effet="aucun"]) {
    /* --seedx (aléa par carte posé par app.js) désynchronise les cartes entre elles */
    animation: holo-veille 4.5s ease-in-out infinite;
    animation-delay: calc(var(--seedx, .5) * -4.5s);
  }
}
@keyframes holo-veille {
  0% {
    --card-opacity: 0;
    --pointer-x: 18%; --pointer-y: 28%;
    --background-x: 40%; --background-y: 40%;
    --pointer-from-left: .18; --pointer-from-top: .28; --pointer-from-center: .65;
  }
  15%, 55% { --card-opacity: .65; }
  75%, 100% {
    --card-opacity: 0;
    --pointer-x: 82%; --pointer-y: 72%;
    --background-x: 60%; --background-y: 60%;
    --pointer-from-left: .82; --pointer-from-top: .72; --pointer-from-center: .65;
  }
}

/* Masque personnalisé : nos masques sont des images noir/gris/blanc → mode luminance
   (noir = pas d'effet, blanc = effet total, gris = proportionnel). */
.card.masked .card__shine,
.card.masked .card__shine:before,
.card.masked .card__shine:after {
  -webkit-mask-source-type: luminance;
  mask-mode: luminance;
}
/* base.css ne masque QUE le shine. Le glare (halo, mix-blend-mode: overlay) restait non masqué :
   son dégradé quasi-blanc débordait sur les zones TRANSPARENTES du PNG et y peignait une boîte
   claire par-dessus la page (visible en zoom/survol, quand --card-opacity > 0). On le masque
   donc AUSSI avec la forme du masque → l'effet holo reste confiné à l'illustration, la
   transparence est respectée. (Ne concerne que les cartes à masque : .card.masked.) */
.card.masked .card__glare,
.card.masked .card__glare:after {
  -webkit-mask-image: var(--mask);
  mask-image: var(--mask);
  -webkit-mask-size: cover;
  mask-size: cover;
  -webkit-mask-position: center center;
  mask-position: center center;
  -webkit-mask-source-type: luminance;
  mask-mode: luminance;
}

/* Calque PNG optionnel : texture de reflet ajoutée au-dessus de l'image (ex : foil holographique
   personnalisé). Se déplace légèrement avec le pointeur (parallax) via --mx/--my. */
.carte-calque {
  position: absolute; inset: -12%; width: 124%; height: 124%; object-fit: cover;
  pointer-events: none; opacity: .4;
  transform: translate(calc((var(--mx, 50%) - 50%) * .5), calc((var(--my, 50%) - 50%) * .5));
  transition: opacity .3s ease;
}
.card.interacting .carte-calque { opacity: .6; }

/* ── Animation de révélation (tirage de paquet) ─────────────*/
.carte-flip-wrap { width: 100%; height: 100%; perspective: 900px; }
.carte-flip-inner {
  position: relative; width: 100%; height: 100%;
  transform-style: preserve-3d;
  transition: transform .8s cubic-bezier(.3,.1,.2,1);
}
.carte-flip-wrap.carte-flip-wrap--revele .carte-flip-inner { transform: rotateY(180deg); }
.carte-face {
  position: absolute; inset: 0; border-radius: 12px; overflow: hidden;
  backface-visibility: hidden;
  box-shadow: 0 6px 16px -8px rgba(0,0,0,.4);
}
.carte-face--recto { transform: rotateY(180deg); }

.carte-verso {
  position: absolute; inset: 0;
  background: linear-gradient(135deg, var(--accent), var(--accent-dark));
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-family: var(--font-heading); font-weight: 800; font-size: 1.4rem;
  backface-visibility: hidden;
}

/* ============================================================
   Album : livre avec pages tournables
   ============================================================ */
/* Le livre occupe tout l'espace disponible : la double page a un ratio 1.5 (2 faces 3/4) ;
   sa largeur = hauteur restante de la fenêtre (100vh − topbar − barre − navigation −
   crédit ≈ 215px) × 1.5, plafonnée à la largeur de l'écran. */
.album-livre {
  perspective: 2600px;
  max-width: none;
  /* Gouttières latérales (--bord-l) réservées aux bandes de navigation : la largeur est
     augmentée d'autant pour que la taille des pages reste inchangée sur grand écran ;
     box-sizing:border-box → le padding rogne le contenu (la reliure), pas le total. */
  --bord-l: clamp(26px, 4%, 50px);
  width: min(100%, calc((100vh - 215px) * 1.5 + 2 * var(--bord-l)));
  padding: 0 var(--bord-l);
  margin: 0 auto; position: relative;
}
/* Niveaux d'affichage (sélecteur « Affichage » de la barre de l'album) — data-zoom /
   data-mode / data-face posés par app.js et mémorisés par appareil (localStorage).
   « Pleine largeur » : le livre prend toute la largeur et dépasse la hauteur de l'écran
   → on défile verticalement. « Une page » : une seule face affichée à la fois (page plus
   grande, confort des petites résolutions) ; la navigation avance face par face. */
.album-livre[data-zoom="double-large"],
.album-livre[data-zoom="simple-large"] { width: 100%; }
.album-livre[data-zoom="simple"] { width: min(100%, calc((100vh - 215px) * .75 + 2 * var(--bord-l))); }
.album-livre[data-mode="simple"][data-face="gauche"] .album-face[data-cote="droite"],
.album-livre[data-mode="simple"][data-face="droite"] .album-face[data-cote="gauche"] { display: none; }
.album-livre[data-mode="simple"] .album-face { border-left: none; }
.album-zoom { display: inline-flex; align-items: center; gap: .45rem; font-size: .85rem; font-weight: 500; }
.album-zoom select {
  padding: .3rem .5rem; border-radius: 8px; border: 1px solid var(--color-border);
  background: #fff; font: inherit; font-size: .85rem;
}

/* Vue album : conteneur pleine largeur, barre compacte à la place du titre. */
.conteneur--album { max-width: none; padding-top: .6rem; padding-bottom: 1rem; }
.album-barre { display: flex; justify-content: space-between; align-items: center; margin-bottom: .5rem; }
/* Dans l'album, une carte n'affiche que son nom (la description reste visible au zoom). */
/* (spécificité > .card.carte .carte-ui * qui fait un display: revert) */
.album-face .card.carte .carte-ui .carte-legende-desc { display: none; }
/* Nom et description sur des lignes séparées (le revert ci-dessus les remettait en inline). */
.card.carte .carte-ui .carte-legende { display: flex; flex-direction: column; }
.card.carte .carte-ui .carte-legende-nom,
.card.carte .carte-ui .carte-legende-desc { display: block; }
/* Pas d'ombre portée au repos (elle casse la jointure des morceaux conjoints) ;
   sur les morceaux de puzzle, jamais d'ombre, même au survol. */
.card.carte:not(.interacting) .card__rotator { box-shadow: none; }
.zone-piece .card__rotator { box-shadow: none; }
.album-reliure {
  display: flex; align-items: stretch; background: #fff; border-radius: 10px;
  box-shadow: 0 20px 50px -20px rgba(0,0,0,.4); overflow: hidden;
}
/* Format de page fixe façon papier (portrait, ratio 3/4) : chaque face du livre a les
   mêmes proportions, quel que soit le nombre de vignettes qu'elle contient. */
/* Page au format papier portrait 3/4 (cf. maquettes des modèles). */
.album-face {
  flex: 1; aspect-ratio: 3 / 4; min-width: 0;
  padding: 0; position: relative; overflow: hidden;
  border-left: 1px solid var(--color-border);
  display: block;
}
.album-face:first-child { border-left: none; }
/* Canevas à COORDONNÉES FIXES : .album-face-corps remplit toute la face (portrait 3/4).
   Le fond, la grille des cartes et les surimpressions (entête + textes) partagent
   EXACTEMENT ce même repère → les cartes tombent au même endroit du fond quelle que soit
   la résolution, et éditer titre/textes ne déplace jamais la grille. (Ce corps est aussi
   le nœud remplacé par app.js au tourne-page.) */
.album-face-corps { position: absolute; inset: 0; container-type: inline-size; }
.album-page-entete {
  position: absolute; top: 0; left: 0; right: 0; z-index: 2;
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 1.6cqw 2cqw 3.5cqw; pointer-events: none;
  background: linear-gradient(180deg, rgba(255,255,255,.6), transparent);
}
/* Titre et numéro proportionnels à la largeur de la page (comme le reste du canevas). */
.album-page-entete h3 { font-size: max(10px, 2.9cqw); }
.album-page-numero { color: var(--color-muted); font-size: max(8px, 2.1cqw); }

/* Fond personnalisé de page : image 3/4 mappée EXACTEMENT sur la face 3/4 (object-fit:fill
   → un point à (x %, y %) de l'image tombe toujours à (x %, y %) de la page, à toute
   résolution). Le voile de lisibilité le recouvre. Tout est en absolu, inset:0. */
.album-page-fond-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: fill; z-index: 0;
}
.album-page-fond-voile {
  position: absolute; inset: 0; z-index: 0;
  background: rgba(255,255,255,0);
}
/* Textes de page (haut/bas) : SURIMPRESSION — n'affectent jamais la grille. Léger fond de
   lisibilité car ils flottent au-dessus de la page. */
/* TAILLE DE TEXTE PROPORTIONNELLE À LA PAGE : les faces/grilles de l'album sont des
   containers (inline-size) → 1cqw = 1 % de la largeur de la page. Les tailles de base
   sont en cqw (calées sur le rendu historique : page ≈ 610px ↔ 1rem ≈ 2.6cqw) et les
   tailles internes (titres, marges) en em → tout le bloc suit la taille de la page,
   quel que soit l'écran ou le niveau de zoom choisi. max(8px, …) = plancher de secours
   sur très petit écran (le débordement éventuel est géré par la pastille [suite]). */
.album-page-texte {
  position: absolute; left: 0; right: 0; z-index: 2;
  max-height: 42%; overflow-y: auto;
  padding: 2cqw; font-size: max(7px, 1.75cqw); line-height: 1.45; color: var(--color-text, #1a1a1a);
  text-shadow: 0 1px 2px rgba(255,255,255,.75);
}
.album-page-texte:not(.album-page-texte--bas) { top: 7cqw; }
.album-page-texte--bas {
  bottom: 0;
  background: linear-gradient(0deg, rgba(255,255,255,.6), transparent);
}
.album-page-texte > :first-child { margin-top: 0; }
.album-page-texte > :last-child { margin-bottom: 0; }
.album-page-texte h1, .album-page-texte h2, .album-page-texte h3 { margin: .45em 0 .35em; line-height: 1.2; }
.album-page-texte h1 { font-size: 1.4em; }
.album-page-texte h2 { font-size: 1.28em; }
.album-page-texte h3 { font-size: 1.16em; }
.album-page-texte p, .album-page-texte ul, .album-page-texte ol { margin: .4em 0; }
.album-page-texte ul, .album-page-texte ol { padding-left: 1.45em; }
.album-page-texte a { color: var(--accent); }
.album-page-texte img { max-width: 100%; height: auto; border-radius: 6px; }
.album-page-texte code { background: rgba(0,0,0,.06); padding: .06em .35em; border-radius: 4px; }

/* ============================================================
   Zones de page (cf. maquettes) : la page (portrait 3/4) contient une grille cols×rows.
   TOUTES les cartes d'une grille ont LA MÊME TAILLE, dérivée d'une unité commune :
     --carte-l = grand côté (1024)  ·  --carte-c = petit côté (768) = l × 768/1024
   horizontal = l × c   ·   vertical = c × l   ·   carré / rond = c × c
   L'unité est relative à la largeur de la grille (container query). */
.album-grille {
  flex: 1; min-height: 0;
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), 1fr);
  grid-template-rows: repeat(var(--rows, 3), 1fr);
  gap: .55rem;
  container-type: inline-size;
  --carte-l: 29cqw;
  --carte-c: calc(29cqw * 768 / 1024);
}
/* Grille de la VUE ALBUM : verrouillée sur tout le canevas de la page (mêmes bords que le
   fond). SANS marge ni écart → les cases sont des fractions EXACTES de la page (largeur/cols
   × hauteur/rows), et l'unité --carte-l = 29cqw = 29 % pile de la largeur de page (le
   content-box de la grille = la page entière) : position/taille des cartes exactement
   calculables et identiques à toute résolution, indépendantes de l'entête/textes (en
   surimpression). Les cartes sont centrées dans leur case. */
.album-grille--page {
  position: absolute; inset: 0; z-index: 1;
  flex: none;
  gap: 0; padding: 0;
}
.album-emplacement { position: relative; min-width: 0; min-height: 0; }

/* --- Tailles uniformes des cartes (et cadres) dans la grille --- */
.album-grille .carte--horizontal { width: var(--carte-l); height: var(--carte-c); }
.album-grille .carte--vertical   { width: var(--carte-c); height: var(--carte-l); }
.album-grille .carte--carre,
.album-grille .carte--rond       { width: var(--carte-c); height: var(--carte-c); }

/* Modèles « ronds + texte » (zt_rond_texte*) : grille à 6 colonnes, 2 unités [2 ronds empilés
   + carte texte] par ligne. On réduit l'unité de carte pour que les ronds (768×768) tiennent
   dans une colonne (1/6 de page) avec un peu de marge ; les zones texte (2×2) remplissent leur
   case. Doit suivre .album-grille pour surcharger --carte-l/--carte-c (même spécificité). */
.album-grille--rt { --carte-l: 19cqw; --carte-c: calc(19cqw * 768 / 1024); }
/* Ces modèles (ronds + texte) démarrent leurs cases dès la 1re rangée : on décale la grille
   vers le bas pour laisser une bande en haut où le titre (surimpression .album-page-entete)
   ne chevauche plus les cases. Le décalage réduit seulement la hauteur (les cartes sont en
   cqw = largeur), donc leur taille est inchangée. Sans effet en admin (grille non positionnée). */
.album-grille--rt { top: 8%; }

/* --- Zone libre : contenu centré --- */
.zone--libre { display: flex; align-items: center; justify-content: center; overflow: hidden; }

/* --- Cartes rondes : centrées dans leur case comme les autres, légende SOUS le cercle --- */
.zone-rond { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .3rem; width: 100%; height: 100%; }
/* Rond : RIEN sur l'image (ni nom, ni description, ni numéro) — tout est affiché SOUS le
   cercle (.carte-sous-legende). !important + spécificité pour battre les règles génériques
   qui remettent la légende en display:flex. Vaut aussi en zoom. */
.card.carte--rond .carte-ui .carte-legende,
.card.carte--rond .carte-ui .carte-numero { display: none !important; }
.carte-sous-legende {
  display: flex; flex-direction: column; gap: .1rem; text-align: center;
  max-width: 100%; padding: 0 .25rem; min-height: 0; overflow: hidden;
}
.carte-sous-nom  { font-weight: 600; font-size: max(8px, 2.1cqw); color: var(--color-heading); }
.carte-sous-desc { font-size: max(7px, 1.85cqw); line-height: 1.25; color: var(--color-muted); overflow: hidden; }

/* Cadre au format de la carte pour les états non collés (placeholder / bouton coller) */
.zone-cadre { position: relative; display: flex; }
.zone-cadre.fmt-horizontal { width: var(--carte-l); height: var(--carte-c); }
.zone-cadre.fmt-vertical   { width: var(--carte-c); height: var(--carte-l); }
.zone-cadre.fmt-carre,
.zone-cadre.fmt-rond       { width: var(--carte-c); height: var(--carte-c); }
.zone-cadre > .emplacement-vide, .zone-cadre > .form-coller { width: 100%; height: 100%; }
.zone-cadre.fmt-rond .emplacement-vide { border-radius: 50%; }

/* Texte Markdown d'une zone libre : aucun fond propre (fond de page visible). */
.zone-texte {
  width: 100%; height: 100%; overflow-y: auto;
  padding: .25em .15em; margin: 5px;
  /* proportionnel à la page (cf. .album-page-texte) */
  font-size: max(7px, 1.7cqw); line-height: 1.4; text-align: left;
  display: flex; flex-direction: column; justify-content: flex-start; /* défaut : haut */
}
/* Alignement vertical du texte dans sa case (directive [haut]/[centre]/[bas]). */
.zone-texte.zone-v-haut   { justify-content: flex-start; }
.zone-texte.zone-v-centre { justify-content: center; }
.zone-texte.zone-v-bas    { justify-content: flex-end; }
/* Espaceur : une ligne vide « supplémentaire » du Markdown = un saut vertical. */
.md-espace { height: 1.15em; flex: 0 0 auto; }
.zone-texte > :first-child { margin-top: 0; }
.zone-texte > :last-child { margin-bottom: 0; }

/* Débordement d'une boîte de texte/média dans l'album — zones libres ET blocs de texte de niveau
   page (fond_texte haut/milieu/bas) : on clippe (pas de défilement), on pose une pastille
   « [suite] » en bas à droite ; un clic ouvre le texte complet en zoom (SANS rotation,
   contrairement aux cartes-images). Hors album (admin), le scroll reste possible. */
.zone-texte, .page-bande-texte { position: relative; }
.album-face .zone-texte,
.album-face .album-page-texte,
.album-face .page-bande-texte { overflow: hidden; }
.boite-deborde { cursor: pointer; }
/* Un contenu qui déborde se lit depuis le DÉBUT : on force l'alignement en haut même si la case
   est paramétrée centrée / en bas (sinon le texte « commence trop haut », coupé par le haut). */
.zone-texte.boite-deborde, .page-bande-texte.boite-deborde { justify-content: flex-start; }
.boite-deborde::after {
  content: "[suite]";
  position: absolute; right: 3px; bottom: 2px;
  font-family: var(--font-body);
  /* proportionnelle à la page, comme le texte qu'elle complète */
  font-size: max(8px, 1.65cqw); font-weight: 700; line-height: 1.35;
  color: #fff; background: var(--accent);
  padding: 0 .35em; border-radius: 6px;
  pointer-events: auto; cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
}
/* Panneau de zoom d'une boîte de texte/média : plein texte, défilable, aucune inclinaison. */
.zoom-texte {
  max-width: min(760px, 92vw); max-height: 86vh; overflow-y: auto;
  background: var(--color-card); color: var(--color-text);
  border-radius: var(--radius); padding: 1.6rem 1.9rem;
  box-shadow: 0 30px 90px -20px rgba(0, 0, 0, .85);
  font-family: var(--font-body); font-size: 1.02rem; line-height: 1.6;
  text-align: left; cursor: auto;
}
.zoom-texte > :first-child { margin-top: 0; }
.zoom-texte > :last-child { margin-bottom: 0; }
.zoom-texte img, .zoom-texte video { max-width: 100%; height: auto; }
.zoom-texte .zone-media { width: 100%; }
.zone-texte h1, .zone-texte h2, .zone-texte h3 { margin: .4em 0 .25em; font-size: 1.15em; }
.zone-texte p, .zone-texte ul, .zone-texte ol { margin: .4em 0; }
.zone-texte ul, .zone-texte ol { padding-left: 1.4em; }
.zone-texte img { max-width: 100%; height: auto; border-radius: 6px; }

/* --- Zone puzzle : morceaux conjoints (aucun espace), coins arrondis sur l'ensemble.
   La grille interne fait EXACTEMENT pcols × prows morceaux au format imposé par le
   modèle (pfmt-vertical : morceaux 768×1024 ; pfmt-horizontal : 1024×768). --- */
.zone--puzzle { overflow: visible; display: flex; align-items: center; justify-content: center; }
.zone-puzzle-grille {
  display: grid;
  grid-template-columns: repeat(var(--pcols, 1), 1fr);
  grid-template-rows: repeat(var(--prows, 1), 1fr);
  gap: 0;
  border-radius: 12px; overflow: hidden;
}
.zone-puzzle-grille.pfmt-vertical {
  width: calc(var(--pcols, 1) * var(--carte-c));
  height: calc(var(--prows, 1) * var(--carte-l));
}
.zone-puzzle-grille.pfmt-horizontal {
  width: calc(var(--pcols, 1) * var(--carte-l));
  height: calc(var(--prows, 1) * var(--carte-c));
}
.zone-piece { position: relative; min-width: 0; min-height: 0; }
.zone-piece .carte { width: 100%; height: 100%; aspect-ratio: auto; --card-radius: 0; }
.zone-piece .emplacement-vide { width: 100%; height: 100%; border-radius: 0; }
.zone-piece .form-coller { width: 100%; height: 100%; }
/* Photo continue, sans trace d'assemblage :
   - pas de fond dégradé sous les morceaux (aux échelles non entières, l'antialiasing du
     bord de chaque photo laissait transparaître ~1px du dégradé clair → lignes/ombres
     « haut-gauche / bas-droite » qui trahissaient les coutures) ;
   - la photo déborde de 1px pour souder les bords entre morceaux ;
   - pas de calque parallaxe par morceau (il bougerait indépendamment). */
.zone-piece .carte-fond { background: none; }
/* Image d'un morceau : remplit EXACTEMENT sa case (object-fit: fill, inset 0) — comme le
   masque du groupe (composite en « fill » sur les mêmes cases). Ainsi image et masque se
   superposent au pixel près, quels que soient leurs ratios natifs (avec « cover » ils se
   décalent dès que le ratio d'un morceau ≠ celui de sa case). */
.zone-piece .carte-image { inset: 0; width: 100%; height: 100%; object-fit: fill; }
.zone-piece .carte-calque { display: none; }

/* --- Un groupe conjoint se comporte comme UNE SEULE carte : la rotation 3D est portée
   par la grille entière, et une couche d'effet unique (.groupe-effet, shine/glare du CSS
   officiel, rareté du 1er morceau) recouvre tout l'assemblage. Les rotations et effets
   individuels des morceaux sont désactivés. Variables posées par app.js sur la grille. --- */
.zone--puzzle { perspective: 900px; }
.zoom-overlay { perspective: 1400px; }
.zone-puzzle-grille {
  position: relative;
  isolation: isolate;
  transform: rotateY(var(--rotate-x, 0deg)) rotateX(var(--rotate-y, 0deg));
  will-change: transform;
}
.zone-puzzle-grille:not(.interacting) { transition: transform .5s ease; }
.zone-puzzle-grille:not(.interacting) .groupe-effet .card__shine,
.zone-puzzle-grille:not(.interacting) .groupe-effet .card__glare { transition: opacity .4s ease; }

/* Morceaux : AUCUN effet individuel (opacité d'effet forcée à 0, shine/glare masqués,
   rotation et ombre supprimées) — sinon on voit les coutures entre les images. */
.zone-puzzle-grille .zone-piece .card { --card-opacity: 0 !important; }
.zone-puzzle-grille .zone-piece .card__shine,
.zone-puzzle-grille .zone-piece .card__glare { display: none !important; }
.zone-puzzle-grille .zone-piece .card__rotator { transform: none !important; box-shadow: none !important; }

/* Couche d'effet UNIQUE du groupe : holo + halo INDÉPENDANTS DU RATIO (le CSS officiel est
   calibré pour une carte portrait et produit une bande décalée sur un panorama). Pilotée par
   les variables du pointeur posées sur la grille (--pointer-*, --background-*, --card-opacity). */
.groupe-effet {
  position: absolute; inset: 0; z-index: 5;
  pointer-events: none; overflow: hidden; border-radius: inherit;
  /* base.css applique aspect-ratio: var(--card-aspect) (0.718) à TOUT .card → la couche
     d'effet serait contrainte à un ratio portrait au lieu de remplir la boîte du groupe,
     ce qui décale le shine/masque par rapport aux images. On neutralise ici (cascade à tout
     le sous-arbre : shine, glare, cases masquées). */
  --card-aspect: auto;
  aspect-ratio: auto;
  /* raretés officielles sur un groupe : découpes portrait neutralisées, coins droits */
  --card-radius: 0;
  --clip: inset(0); --clip-invert: inset(0);
  --clip-stage: inset(0); --clip-stage-invert: inset(0);
  --clip-trainer: inset(0); --clip-borders: inset(0);
}
/* Filet de sécurité : aucune contrainte de ratio sur les couches d'effet du groupe. */
.groupe-effet .card__shine, .groupe-effet .card__glare,
.groupe-shine-grille, .groupe-effet-cell { aspect-ratio: auto; }
.groupe-effet .card__shine::before,
.groupe-effet .card__shine::after,
.groupe-effet .card__glare::after { width: 100%; height: 100%; }
.groupe-effet .card__shine,
.groupe-effet .card__glare {
  position: absolute; inset: 0;
  border-radius: 0;
}
/* Shine tempéré : à pleine opacité, le color-dodge crame les photos claires et masque
   l'image ; on plafonne pour que l'image reste toujours lisible sous l'effet. */
.groupe-effet .card__shine { opacity: calc(var(--card-opacity, 0) * .5); }
.groupe-effet .card__glare { opacity: calc(var(--card-opacity, 0) * .8); }
/* Holo du groupe : recette « rare holo » OFFICIELLE (bandes + scanlines fusionnées en
   overlay, puis le filtre assombrissant de base.css), indépendante du ratio — sans le
   clip-path portrait-only. Couleurs = variables --red/--violet… de cards.css (héritées
   via la classe .card de la couche). */
.groupe-effet:not([data-rarity]) .card__shine {
  background-image:
    repeating-linear-gradient(110deg,
      var(--violet), var(--blue), var(--green), var(--yellow), var(--red),
      var(--violet), var(--blue), var(--green), var(--yellow), var(--red),
      var(--violet), var(--blue), var(--green), var(--yellow), var(--red)),
    repeating-linear-gradient(90deg, black 0px, black 2px, #666 2px, #666 4px);
  background-position:
    calc(((50% - var(--background-x, 50%)) * 2.6) + 50%) calc(((50% - var(--background-y, 50%)) * 3.5) + 50%),
    center center;
  background-size: 400% 400%, cover;
  background-blend-mode: overlay;
  filter: brightness(.85) contrast(2.75) saturate(.65);
  mix-blend-mode: color-dodge;
}
/* Halo du groupe : formule officielle, paramétrée comme les cartes (--halo-k / --halo-r).
   Uniquement en repli : une rareté configurée fournit son propre glare. */
.groupe-effet:not([data-rarity]) .card__glare {
  background-image: radial-gradient(
    var(--halo-r, 150%) var(--halo-r, 150%) at var(--pointer-x, 50%) var(--pointer-y, 50%),
    hsla(0, 0%, 100%, calc(.8 * var(--halo-k, 1))) 10%,
    hsla(0, 0%, 100%, calc(.65 * var(--halo-k, 1))) 20%,
    hsla(0, 0%, 0%, calc(.5 * var(--halo-k, 1))) 90%);
  mix-blend-mode: overlay;
}

/* Interface des morceaux (numéro, nom, description) : masquée dans l'album et le zoom —
   les badges « #31 #32 … » et bandeaux par morceau trahissent l'assemblage. Le nom
   s'affiche au niveau du GROUPE (pastille compacte). En ADMIN, on garde les numéros
   pour identifier les emplacements. */
.zone-piece .carte-ui { display: none !important; }
.album-grille--admin .zone-piece .carte-ui { display: block !important; }
.zone-piece .carte-legende { display: none !important; }
.groupe-legende {
  position: absolute; left: .6rem; bottom: .6rem; z-index: 6;
  max-width: 75%;
  padding: .3rem .75rem; border-radius: 14px;
  background: rgba(0, 0, 0, .6); color: #fff;
  font-size: .8rem; font-weight: 600;
  pointer-events: none;
  display: flex; flex-direction: column; gap: .15rem;
}
.groupe-legende-desc { display: none; font-weight: 400; font-size: .78rem; color: rgba(255,255,255,.92); }
.zoom-overlay .groupe-legende-desc { display: block; font-size: .95rem; line-height: 1.4; }
.zoom-overlay .groupe-legende { font-size: 1.15rem; padding: .5rem 1.1rem; left: 1rem; bottom: 1rem; }

.emplacement-vide {
  border-radius: 12px;
  border: 2px dashed var(--color-border);
  display: flex; align-items: center; justify-content: center;
  color: var(--color-border); font-size: 1.6rem;
  background: repeating-linear-gradient(45deg, #ffffff40 0 8px, #FAFBFD85 8px 16px);
}
.emplacement-vide.emplacement-vide--dispo {
  border-color: var(--accent); color: var(--accent); cursor: pointer; font-family: inherit;
  position: relative; overflow: hidden; flex-direction: column; padding: 0;
}
.emplacement-apercu { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; padding: 10%; opacity: .35; }
.emplacement-coller-texte {
  position: relative; z-index: 1; background: var(--accent); color: #fff;
  font-size: .75rem; font-weight: 700; padding: .3rem .6rem; border-radius: 999px;
}
.form-coller { width: 100%; height: 100%; }
.form-coller button { width: 100%; height: 100%; }
.album-page-vide { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--color-muted); font-style: italic; }
.emplacement-actions { display: flex; gap: .35rem; margin-top: .4rem; justify-content: center; flex-wrap: wrap; }
.emplacement-actions form { display: inline; }
.form-ajout-carte { scroll-margin-top: 80px; }
.modifier-carte-mise-en-page { display: flex; gap: 2rem; flex-wrap: wrap; }
.modifier-carte-apercu { width: 180px; flex-shrink: 0; }
.modifier-carte-form { flex: 1; min-width: 260px; }
.calques-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 1.25rem; }
.calque-tuile { text-align: center; }
.calque-apercu {
  width: 100%; aspect-ratio: 5/7; object-fit: cover; border-radius: 10px;
  background: repeating-conic-gradient(#e5e7eb 0% 25%, #fff 0% 50%) 0 0 / 16px 16px;
  margin-bottom: .4rem;
}

.album-nav {
  display: flex; align-items: center; justify-content: center; gap: 1rem; margin-top: 1rem;
}
.album-nav-info { color: var(--color-muted); font-size: .9rem; }

/* Animation de tourne-page : une FEUILLE à deux faces pivote autour de la reliure. Le RECTO
   montre la page qui s'en va, le VERSO la nouvelle page du côté opposé qui arrive → on voit
   bien l'ancienne page disparaître ET la nouvelle apparaître de l'autre côté (app.js échange
   le contenu sous la feuille à mi-parcours). */
.album-page-tournante {
  position: absolute; inset: 0; z-index: 10;
  transform-origin: left center;
  transform-style: preserve-3d;
  transition: transform .8s cubic-bezier(.36,.1,.2,1);
  will-change: transform;
}
.album-page-tournante.tourne-arriere { transform-origin: right center; }
.album-page-tournante.en-cours { transform: rotateY(-180deg); }
.album-page-tournante.tourne-arriere.en-cours { transform: rotateY(180deg); }
.album-page-tournante .tourne-recto,
.album-page-tournante .tourne-verso {
  position: absolute; inset: 0;
  backface-visibility: hidden;
  background: var(--color-card); border-radius: 6px; overflow: hidden;
  box-shadow: 0 0 40px -6px rgba(0,0,0,.45);
}
.album-page-tournante .tourne-verso { transform: rotateY(180deg); }
/* léger dégradé d'ombre du papier qui se courbe */
.album-page-tournante .tourne-recto::after,
.album-page-tournante .tourne-verso::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(90deg, rgba(0,0,0,.22), rgba(0,0,0,0) 55%, rgba(255,255,255,.18));
}

/* ── Pioche (cartes non collées) ────────────────────────────*/
.album-entete-actions { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.pioche-liste { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 1rem; }
.pioche-item { display: flex; flex-direction: column; gap: .4rem; align-items: center; }
.pioche-quantite { font-size: .78rem; color: var(--color-muted); }

@media (max-width: 720px) {
  .album-reliure { flex-direction: column; }
  .album-face { border-left: none; border-top: 1px solid var(--color-border); }
  .album-face:first-child { border-top: none; }
  .topbar-nav { display: none; }
}

/* Aperçu de l'image de fond dans l'éditeur de page (admin) */
.apercu-fond-page { display: block; max-width: 260px; width: 100%; border-radius: 8px; margin-bottom: .5rem; border: 1px solid var(--color-border); }
.case-inline { display: flex; align-items: center; gap: .4rem; font-weight: 400; margin-bottom: .5rem; }
.case-inline input { width: auto; }

/* Sécurité admin (MFA / TOTP) + connexion */
.profil-tuile-statique { cursor: default; }
.profil-tuile-statique:hover .profil-avatar { transform: none; box-shadow: none; }
.liste-statut { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .4rem; }
.qr-zone { display: inline-block; padding: .6rem; background: #fff; border: 1px solid var(--color-border); border-radius: 10px; margin: .5rem 0; }
.qr-zone img, .qr-zone canvas { display: block; }
.totp-cle { display: inline-block; font-size: 1.05rem; letter-spacing: .12em; background: rgba(0,0,0,.06); padding: .35rem .6rem; border-radius: 6px; margin-top: .3rem; }

/* ── Laboratoire d'effets (admin) ─────────────────────────── */
.labo { display: grid; grid-template-columns: 320px 1fr; gap: 1.5rem; align-items: start; }
@media (max-width: 760px) { .labo { grid-template-columns: 1fr; } }
.labo-apercu { position: sticky; top: calc(var(--topbar-h) + 1rem); }
.labo-apercu .carte { max-width: 320px; margin: 0 auto; }
.labo-astuce { text-align: center; color: var(--color-muted); font-size: .82rem; margin-top: .6rem; }
.labo-grille-reglages { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem 1rem; margin: .5rem 0 1rem; }
@media (max-width: 520px) { .labo-grille-reglages { grid-template-columns: 1fr; } }
.labo-grille-reglages label { display: flex; flex-direction: column; gap: .2rem; font-size: .8rem; font-weight: 600; }
.labo-grille-reglages output { color: var(--accent); font-weight: 700; font-variant-numeric: tabular-nums; }
.labo-grille-reglages input[type="range"] { width: 100%; }
.labo-palette { display: flex; gap: .4rem; flex-wrap: wrap; }
.labo-palette input[type="color"] { width: 40px; height: 34px; padding: 0; border: 1px solid var(--color-border); border-radius: 6px; background: none; cursor: pointer; }
#sortie { font-family: ui-monospace, monospace; font-size: .78rem; }

/* ── Galerie d'effets (admin) ─────────────────────────────── */
.galerie-effets { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 1.6rem; margin-top: 1rem; }
.galerie-item { display: flex; flex-direction: column; align-items: center; gap: .5rem; }
.galerie-item .carte { width: 100%; max-width: 210px; }
.galerie-cle { font-size: .78rem; color: var(--color-muted); }

/* Vignettes sources (image / masque / foil) dans la galerie d'effets */
.galerie-source { width: 100%; max-width: 210px; aspect-ratio: 3/4; object-fit: cover; border-radius: 12px; border: 1px solid var(--color-border); }
.galerie-source--damier { background: repeating-conic-gradient(#e9edf3 0 25%, #fff 0 50%) 0 0 / 20px 20px; }

/* ── Grille d'admin des zones (page non contrainte : rangées automatiques) ── */
.album-grille--admin { flex: none; grid-template-rows: none; grid-auto-rows: auto; gap: .9rem .6rem; }
.zone-boite { width: 100%; }
.zone-boite.zone--libre {
  aspect-ratio: 1 / 1;
  background: rgba(37,99,235,.06); border: 1px dashed var(--color-border); border-radius: 12px;
}
.zone-boite.zone--puzzle { /* ratio w/h posé via data-ratio (JS) */ }
.zone-vide-actions { display: flex; gap: .6rem; }
.zone-btn-rond {
  width: 52px; height: 52px; border-radius: 50% !important;
  font-size: 1.2rem; text-decoration: none;
  display: flex; align-items: center; justify-content: center;
}

/* ── Aperçus des modèles de page (formulaire « Ajouter une page ») ── */
.dispo-choix { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 1rem; }
.dispo-option { display: flex; flex-direction: column; gap: .4rem; align-items: center; cursor: pointer; position: relative; }
.dispo-option input { position: absolute; opacity: 0; pointer-events: none; }
.dispo-apercu {
  width: 100%; aspect-ratio: 3 / 4;
  background: #F6D84A; border-radius: 10px; padding: 7%;
  display: flex; flex-direction: column; gap: 4%;
  border: 3px solid transparent; transition: border-color .15s ease, box-shadow .15s ease;
}
.dispo-option input:checked ~ .dispo-apercu { border-color: var(--accent); box-shadow: 0 6px 18px -8px var(--accent); }
.dispo-option input:focus-visible ~ .dispo-apercu { outline: 2px solid var(--accent-dark); }
.dispo-barre { height: 6.5%; background: #1a1a1a; border-radius: 2px; flex-shrink: 0; }
.dispo-mini {
  flex: 1; min-height: 0;
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), 1fr);
  grid-template-rows: repeat(var(--rows, 3), 1fr);
  gap: 4%;
  container-type: inline-size;
  --carte-l: 31cqw;
  --carte-c: calc(31cqw * 768 / 1024);
}
.dispo-zone { border-radius: 4px; min-width: 0; min-height: 0; }
.dispo-zone--libre { background: #45AEDE; }
.dispo-zone--puzzle { display: flex; align-items: center; justify-content: center; background: transparent; }
.dispo-zone--puzzle .zone-puzzle-grille { border-radius: 4px; gap: 2px; background: #7CC74F; }
.dispo-piece { background: #7CC74F; min-width: 0; min-height: 0; }
.dispo-nom { font-size: .78rem; text-align: center; line-height: 1.25; }

/* ── Zoom sur une carte (album) : tilt + reflets dans l'overlay ── */
.zoom-overlay {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(10, 12, 20, .82);
  display: flex; align-items: center; justify-content: center;
}
/* Ombre portée UNIQUEMENT sur l'élément zoomé lui-même (carte seule ou grille de groupe) —
   surtout pas sur les morceaux : chaque pièce projetterait son ombre sur ses voisines et
   dessinerait des bandes sombres le long des jointures. */
.zoom-overlay > .carte,
.zoom-overlay > .zone-puzzle-grille { box-shadow: 0 30px 90px -20px rgba(0,0,0,.85); }
.zoom-overlay .zone-piece .carte { box-shadow: none !important; }
/* Zoom : la carte s'affiche à sa taille native (1024 × 768 / 768 × 1024 / 768 × 768),
   réduite seulement si la fenêtre est plus petite. */
.zoom-overlay > .carte--horizontal { width: min(1024px, 92vw, calc(92vh * 1024 / 768)); }
.zoom-overlay > .carte--vertical   { width: auto; height: min(1024px, 92vh, calc(92vw * 1024 / 768)); }
.zoom-overlay > .carte--carre,
.zoom-overlay > .carte--rond       { width: min(768px, 85vw, 85vh); }
/* Textes lisibles à la taille native */
.zoom-overlay .carte-legende { padding: .9rem 1rem; gap: .35rem; }
.zoom-overlay .carte-legende-nom  { font-size: 1.25rem; }
.zoom-overlay .carte-legende-desc { font-size: 1rem; line-height: 1.45; max-height: 9em; }
.zoom-overlay .carte-numero { font-size: 1rem; padding: .2rem .7rem; }
.zoom-fermer {
  position: absolute; top: 1rem; right: 1.2rem;
  width: 44px; height: 44px; border-radius: 50%; border: none;
  background: rgba(255,255,255,.18); color: #fff; font-size: 1.3rem; cursor: pointer;
}
.zoom-fermer:hover { background: rgba(255,255,255,.32); }

/* Alignement des blocs Markdown (syntaxe -> texte <- / -> texte ->) */
.md-centre { text-align: center; }
.md-droite { text-align: right; }

/* Bande de séparation (--- / *** / ___ sur une ligne) → <hr class="md-hr"> */
.md-hr {
  border: 0; height: max(2px, .35cqw); margin: .9em 0;
  background: linear-gradient(90deg, transparent, currentColor, transparent);
  opacity: .45;
  flex: 0 0 auto;   /* .zone-texte est un flex column : sans ça la barre (3px) est écrasée par flex-shrink et devient invisible hors zoom */
}
/* Surlignage <mark> : fond jaune autour du texte */
mark {
  background: #fff3a0; color: inherit;
  padding: 0 .18em; border-radius: .18em;
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
}
/* Texte coloré : <rouge>…</rouge>, <bleu>…</bleu>, etc. (classes, pas de style inline / CSP) */
.md-c-rouge  { color: #e03131; }
.md-c-orange { color: #e8590c; }
.md-c-jaune  { color: #f08c00; }
.md-c-vert   { color: #2f9e44; }
.md-c-bleu   { color: #1971c2; }
.md-c-violet { color: #7048e8; }
.md-c-rose   { color: #e64980; }
.md-c-gris   { color: #868e96; }

/* ── Banque de cartes (admin) ─────────────────────────────── */
.banque-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 1.2rem; }
.banque-item { display: flex; flex-direction: column; gap: .45rem; }
.banque-item .carte { max-width: 100%; }
.banque-statut { font-size: .74rem; color: var(--color-muted); }
.banque-statut--place { color: var(--color-success); font-weight: 600; }

/* Panneau d'assignation d'une carte à un emplacement */
.assigner-liste { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 1rem; }
.assigner-item { display: flex; flex-direction: column; gap: .4rem; align-items: stretch; }
.assigner-item button { width: 100%; }

/* Crédit effets holographiques */
.credit-holo { font-size: .75rem; color: var(--color-muted); text-align: center; margin-top: 1rem; }
.credit-holo a { color: var(--color-muted); }

/* ── Bords cliquables du livre : page précédente / suivante ── */
.album-bord {
  position: absolute; top: 0; bottom: 0; width: var(--bord-l);
  border: none; z-index: 20; cursor: pointer;
  background: transparent; color: transparent;
  font-size: 3rem; line-height: 1; font-family: inherit;
  display: flex; align-items: center; justify-content: center;
  transition: background .2s ease, color .2s ease;
}
.album-bord--gauche { left: 0; border-radius: 10px 0 0 10px; }
.album-bord--droite { right: 0; border-radius: 0 10px 10px 0; }
.album-bord--gauche:hover { color: #fff; background: linear-gradient(to right, rgba(0,0,0,.35), transparent); }
.album-bord--droite:hover { color: #fff; background: linear-gradient(to left, rgba(0,0,0,.35), transparent); }
.album-bord[disabled] { display: none; }

/* Sélecteur d'effet d'un groupe conjoint (admin) */
.groupe-effet-form { display: flex; align-items: center; gap: .4rem; width: 100%; margin: .4rem 0 .2rem; }
.groupe-effet-form label { font-size: .78rem; font-weight: 600; white-space: nowrap; }
.groupe-effet-form select { flex: 1; padding: .3rem .5rem; border: 1px solid var(--color-border); border-radius: 8px; font-size: .82rem; }

/* ── Édition : barre d'actions + navigation entre pages ── */
.edition-actions { display: flex; gap: .5rem; flex-wrap: wrap; }
.edition-nav-pages {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin: .2rem 0 1rem; flex-wrap: wrap;
}
.edition-nav-pages .btn[aria-disabled="true"] { opacity: .4; pointer-events: none; }

/* ── Liste des pages : réordonnancement par glisser-déposer ── */
.table-pages tbody tr { cursor: default; }
.poignee-glisser { cursor: grab; color: var(--color-muted); font-size: 1.2rem; user-select: none; width: 1.5rem; text-align: center; }
.table-pages tr.en-glisse { opacity: .45; background: var(--color-success-bg); }
.page-numero-cell { font-weight: 700; color: var(--color-heading); }

/* ── Lecteurs média dans les zones/textes Markdown ── */
.zone-media { display: block; width: 100%; margin: .5rem 0; border-radius: 10px; }
.zone-audio { height: 40px; }
.zone-video { max-height: 60vh; background: #000; }

/* ============================================================
   Modèles à zones sur 3 rangées (z1…z6) — layout en BANDES (page 1200×1600) :
   grille de 3 colonnes × 6 lignes (bande 133 / rangée 400 / bande / rangée / bande /
   rangée). Les zones et les bandes de texte sont posées par grid-column/grid-row (data-gcol
   / data-grow appliqués en JS, CSP oblige). Un puzzle qui s'étend sur 2 rangées traverse la
   bande du milieu (span 3 lignes). Les blocs de texte ne chevauchent plus les cases.
   ============================================================ */
.page-bandes {
  position: absolute; inset: 0; z-index: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 133fr 400fr 133fr 400fr 133fr 400fr;   /* = 1200×1600 : 133/400/… */
  container-type: inline-size;                                /* pour cqw des cartes */
  --carte-l: 29cqw;                                           /* grand côté = 348px @1200 */
  --carte-c: calc(29cqw * 768 / 1024);                        /* petit côté = 261px @1200 */
}
.page-bande-texte {
  overflow: hidden; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; justify-content: center;
  padding: 0 2.5cqw;
  /* proportionnel à la page (cf. .album-page-texte) */
  font-size: max(7px, 1.75cqw); line-height: 1.4;
  text-shadow: 0 1px 2px rgba(255,255,255,.75);
}
.page-bande-texte > :first-child { margin-top: 0; }
.page-bande-texte > :last-child  { margin-bottom: 0; }
.page-bande-texte h1, .page-bande-texte h2, .page-bande-texte h3 { margin: .25em 0; line-height: 1.15; }
.page-bandes .album-emplacement { position: relative; min-width: 0; min-height: 0; }
.page-bandes .zone--libre { display: flex; align-items: center; justify-content: center; overflow: hidden; }
/* Cartes centrées dans une case 400×400 : carré/rond utilisent le GRAND côté (348). */
.page-bandes .carte--horizontal,
.page-bandes .zone-cadre.fmt-horizontal { width: var(--carte-l); height: var(--carte-c); }
.page-bandes .carte--vertical,
.page-bandes .zone-cadre.fmt-vertical   { width: var(--carte-c); height: var(--carte-l); }
.page-bandes .carte--carre,
.page-bandes .carte--rond,
.page-bandes .zone-cadre.fmt-carre,
.page-bandes .zone-cadre.fmt-rond       { width: var(--carte-l); height: var(--carte-l); }

/* Masque des groupes : shine découpé en une case DOM par morceau (alignement pixel du masque
   avec l'image, en object-fit:fill). Le halo (glare) reste une couche unique. */
.groupe-shine-grille { position: absolute; inset: 0; z-index: 1; display: grid; }
.groupe-effet-cell { position: relative; overflow: hidden; }
.groupe-effet-cell .card__shine { position: absolute; inset: 0; }

/* ============================================================
   Couverture / dos — l'album démarre FERMÉ et s'ouvre au clic
   ============================================================ */
.album-couverture {
  position: absolute; top: 0; bottom: 0; left: 50%;
  transform: translateX(-50%);
  aspect-ratio: 3 / 4;
  border-radius: 6px 12px 12px 6px; overflow: hidden;
  display: flex; align-items: flex-end;
  background: linear-gradient(135deg, var(--accent), var(--accent-dark));
  color: #fff; z-index: 30;
  box-shadow: 0 24px 60px -20px rgba(0,0,0,.6), inset 10px 0 18px -10px rgba(0,0,0,.5);
  transform-origin: left center;
  transition: transform .65s cubic-bezier(.4,.05,.2,1), opacity .5s ease, visibility .5s;
  backface-visibility: hidden;
  container-type: inline-size;
}
.album-couverture--avant { cursor: pointer; }
.album-couv-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.album-couv-voile { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(0,0,0,.1), rgba(0,0,0,.05) 55%, rgba(0,0,0,.1)); }
.album-couverture:not(.a-image) .album-couv-voile { background: none; }
.album-couv-texte { position: relative; z-index: 1; width: 100%; padding: 2rem 1.5rem; text-align: center; }
.album-couv-titre { color: #fff; font-size: clamp(1.3rem, 4cqw, 2.4rem); margin: 0 0 .3rem; text-shadow: 0 2px 12px rgba(0,0,0,.55); }
.album-couv-theme, .album-couv-desc { margin: 0 0 1rem; opacity: .92; }
.album-couv-hint { display: inline-block; padding: .5rem 1.1rem; border-radius: 999px; background: rgba(255,255,255,.22); font-weight: 600; font-size: .9rem; }
.album-couverture--avant:hover .album-couv-hint { background: rgba(255,255,255,.36); }
.album-couv-hint--fin { background: rgba(255,255,255,.14); cursor: default; }

/* États : on bascule en opacité/visibilité (transition possible) plutôt qu'en display. */
.album-livre .album-couverture { opacity: 0; visibility: hidden; pointer-events: none; }
.album-livre[data-etat="ferme-avant"]   .album-couverture--avant,
.album-livre[data-etat="ferme-arriere"] .album-couverture--arriere { opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(-50%); }
/* Couverture masquée = pivotée « ouverte » (effet livre qui s'ouvre) */
.album-livre[data-etat="ouvert"] .album-couverture--avant,
.album-livre[data-etat="ferme-arriere"] .album-couverture--avant { transform: translateX(-50%) perspective(1800px) rotateY(-105deg); }
.album-livre[data-etat="ouvert"] .album-couverture--arriere,
.album-livre[data-etat="ferme-avant"] .album-couverture--arriere { transform: translateX(-50%) perspective(1800px) rotateY(105deg); transform-origin: right center; }
/* Reliure : cachée (mais garde sa place → hauteur du livre stable) quand l'album est fermé. */
.album-livre[data-etat="ferme-avant"]   .album-reliure,
.album-livre[data-etat="ferme-arriere"] .album-reliure { opacity: 0; visibility: hidden; pointer-events: none; }
.album-livre[data-etat="ferme-avant"]   .album-bord,
.album-livre[data-etat="ferme-arriere"] .album-bord { display: none; }
.album-reliure { transition: opacity .5s ease .1s; }
