/* ── style.css — refondu sur tokens.css ───────────────────────────────────── */
@import url('tokens.css');

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

html, body {
  height: 100%;
  /* iOS Safari régression : `overflow-x: clip` parfois ignoré quand un descendant
     a une transform/translateX qui dépasse. Doubler avec hidden (les deux ne
     créent pas de scroll-y grâce à overflow-y: hidden explicite). position:
     relative pour bien établir le contexte de containment. !important pour
     bloquer toute règle plus tardive qui voudrait restaurer le scroll. */
  position: relative;
  max-width: 100%;
  width: 100%;
  overflow-x: hidden !important;
  overflow-y: hidden;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
}

body::before {
  content: "";
  position: fixed; inset: 0;
  pointer-events: none;
  background-image: radial-gradient(circle, rgba(10,10,10,0.06) 1px, transparent 1px);
  background-size: 22px 22px;
  z-index: 0;
}

.app {
  position: relative; z-index: 1;
  max-width: 1180px;
  margin: 0 auto;
  padding: 20px 28px 16px;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* ── Header ──────────────────────────────────────────────────────────────── */
.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
  gap: var(--space-3);
}

.header-actions { display: flex; gap: var(--space-2); align-items: center; }

.btn-collection, .btn-nav {
  font-family: var(--font-display);
  font-size: 14px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  padding: 9px 16px;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
  flex-shrink: 0;
  white-space: nowrap;
  cursor: pointer;
}
.btn-collection:hover, .btn-collection:focus-visible,
.btn-nav:hover, .btn-nav:focus-visible {
  transform: translate(-2px, -2px);
  box-shadow: 5px 5px 0 0 var(--ink);
}
.btn-nav .ico { display: inline-flex; }
/* Bouton icône seule (ex : paramètres rouage) : carré, sans texte */
.btn-nav.btn-icon-only {
  padding: 9px 11px;
  font-family: inherit;
}

.site-title {
  font-family: var(--font-display);
  font-size: clamp(18px, 3.8vw, 44px);
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
  flex: 1 1 0;
  /* min-width: 0 indispensable sinon flex items refusent de shrink en dessous
     de leur largeur de contenu (par défaut min-width: auto). Pas d'overflow
     hidden (tronquait l'emoji avec son drop-shadow vertical). */
  min-width: 0;
  display: flex;
  align-items: center;
}
/* ── Réduire les animations (accessibilité, opt-in via paramètres) ────── */
html.reduce-motion *,
html.reduce-motion *::before,
html.reduce-motion *::after {
  animation-duration: 0.001s !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001s !important;
}

/* ══════════════════════════════════════════════════════════════════════════
   MENU PARAMÈTRES — refonte en blocs néobrut colorés
   ────────────────────────────────────────────────────────────────────────── */

/* Modal principal ─────────────────────────────────────────────────────── */
.settings-backdrop {
  position: fixed;
  inset: 0;
  z-index: 600;
  background: rgba(10,10,10,0.7);
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-3);
}
.settings-backdrop.show { display: flex; }
.settings-modal {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-lg);
  max-width: 540px;
  width: 100%;
  max-height: 92vh;
  overflow: hidden;        /* le scroll est délégué à .settings-scroll */
  display: flex;
  flex-direction: column;
}
.settings-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--border-thick);
  background: var(--yellow);
  flex-shrink: 0;          /* header ne se compresse pas */
}
/* Wrapper interne qui scrolle — évite le bug "header sticky qui détache
   au sur-défilement" dans un container flex. */
.settings-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;  /* coupe la chaîne de scroll vers la page */
}
.settings-title {
  font-family: var(--font-display);
  font-size: clamp(20px, 3vw, 28px);
  text-transform: uppercase;
  letter-spacing: -0.01em;
  margin: 0;
}
.settings-close,
.feedback-close,
.feedback-back {
  width: 36px;
  height: 36px;
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  font-family: var(--font-display);
  font-size: 16px;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.settings-close:hover,
.feedback-close:hover,
.feedback-back:hover { transform: translate(-2px, -2px); box-shadow: 5px 5px 0 0 var(--ink); }

.settings-body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Bloc — carte néobrut colorée ────────────────────────────────────────── */
.settings-block {
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  background: var(--paper);
  display: flex;
  flex-direction: column;
}
.settings-block-head {
  padding: 8px 14px;
  border-bottom: var(--border-thick);
  background: var(--ink);
  color: var(--paper);
}
.settings-block-title {
  font-family: var(--font-display);
  font-size: clamp(13px, 1.4vw, 15px);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0;
  line-height: 1.1;
}
.settings-block-body {
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Variantes de fond par bloc — pastel doux qui évoque la fonction */
.settings-block--player   { background: #d8f3dc; }   /* vert pastel — identité */
.settings-block--prefs    { background: #ffe9c2; }   /* sable — préférences */
.settings-block--data     { background: #d6e0ff; }   /* bleu pastel — utilitaire */
.settings-block--feedback { background: #ead4ff; }   /* violet pastel — créatif */
.settings-block--donate   { padding: 0; border: 0; box-shadow: none; background: transparent; }

/* Champs — label + input/toggle ──────────────────────────────────────── */
.settings-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.settings-field--toggle {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.settings-label {
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  line-height: 1;
}
.settings-input {
  font-family: var(--font-body);
  font-size: 15px;
  padding: 8px 10px;
  border: var(--border-thick);
  background: var(--paper);
  outline: none;
  width: 100%;
  box-sizing: border-box;
}
.settings-input:focus {
  background: var(--white);
  box-shadow: var(--sh-sm);
}

/* Toggle néobrut (checkbox stylée) ───────────────────────────────────── */
.settings-toggle {
  appearance: none;
  -webkit-appearance: none;
  box-sizing: border-box;
  width: 52px;
  height: 28px;
  background: var(--paper);
  border: var(--border-thick);
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
  transition: background var(--dur-fast);
  margin: 0;
}
.settings-toggle::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 4px;
  width: 14px;
  height: 14px;
  background: var(--ink);
  transform: translateY(-50%);
  transition: left var(--dur-fast);
}
.settings-toggle:checked { background: var(--green); }
.settings-toggle:checked::after { left: calc(100% - 18px); }

/* Préférences en grid 2-col compactée ────────────────────────────────── */
.settings-prefs-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  padding: 14px;
}
.settings-pref-card {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--paper);
  border: var(--border-thick);
  cursor: pointer;
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.settings-pref-card:hover { transform: translate(-1px, -1px); box-shadow: var(--sh-sm); }
.settings-pref-emoji { font-size: 20px; line-height: 1; }
.settings-pref-label {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
}
@media (max-width: 420px) {
  .settings-prefs-grid { grid-template-columns: 1fr; }
}

/* Hints + Actions ────────────────────────────────────────────────────── */
.settings-hint {
  font-family: var(--font-mono);
  font-size: 11px;
  opacity: 0.75;
  line-height: 1.45;
  margin: 0;
}
.settings-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Trio Classements (toggle + 2 boutons sur 1 ligne) ──────────────────── */
.settings-lb-row {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr;
  gap: 8px;
  align-items: stretch;
}
.settings-lb-toggle {
  /* Hérite de .settings-pref-card mais en variante "wide" : le label peut prendre
     deux lignes ; le toggle reste à droite sans réduire le label. */
  grid-template-columns: auto 1fr auto;
  align-items: center;
}
.settings-lb-toggle .settings-pref-label {
  white-space: normal;
  line-height: 1.2;
}
@media (max-width: 480px) {
  .settings-lb-row {
    grid-template-columns: 1fr 1fr;
  }
  .settings-lb-toggle { grid-column: 1 / -1; }
}

/* Trio Sauvegarde (Export/Import/Reset sur 1 ligne) ──────────────────── */
.settings-save-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
@media (max-width: 480px) {
  .settings-save-row { grid-template-columns: 1fr 1fr; }
  .settings-save-row > #settings-reset { grid-column: 1 / -1; }
}

/* Boutons ─────────────────────────────────────────────────────────────── */
.settings-btn {
  font-family: var(--font-display);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 9px 14px;
  background: var(--paper);
  color: var(--ink);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  cursor: pointer;
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.settings-btn:hover:not(:disabled) {
  transform: translate(-2px, -2px);
  box-shadow: 5px 5px 0 0 var(--ink);
}
.settings-btn:active:not(:disabled) {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 0 var(--ink);
}
.settings-btn:disabled { opacity: 0.55; cursor: not-allowed; }
.settings-btn--block { width: 100%; text-align: center; }
.settings-btn--danger { background: var(--red); color: var(--paper); }
.settings-btn--primary { background: var(--ink); color: var(--paper); }

/* Bouton multiligne : 2 spans empilés, hauteur identique aux cartes adjacentes */
.settings-btn--multiline {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 8px 10px;
  line-height: 1.15;
  min-height: 56px;
  text-align: center;
}
.settings-btn--multiline > span:first-child { font-size: 12px; }
.settings-btn--multiline > span:last-child  {
  font-size: 10px;
  letter-spacing: 0.06em;
  opacity: 0.8;
}

/* CTA Feedback (gros bouton dans le bloc violet) ─────────────────────── */
.settings-feedback-cta {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 12px 14px;
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  color: var(--ink);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.settings-feedback-cta:hover {
  transform: translate(-2px, -2px);
  box-shadow: 5px 5px 0 0 var(--ink);
}
.settings-feedback-cta-emoji {
  font-size: 28px; line-height: 1;
  font-family: 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif;
}
.settings-feedback-cta-text { display: flex; flex-direction: column; gap: 2px; }
.settings-feedback-cta-title {
  font-family: var(--font-display);
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.15;
}
.settings-feedback-cta-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  opacity: 0.65;
}
.settings-feedback-cta-arrow {
  font-family: var(--font-display);
  font-size: 22px;
  transition: transform var(--dur-fast);
}
.settings-feedback-cta:hover .settings-feedback-cta-arrow { transform: translateX(4px); }

/* Footer À propos — minimal, gris doux ──────────────────────────────── */
.settings-footer {
  border-top: 2px dashed rgba(10,10,10,0.25);
  padding-top: 12px;
  margin-top: 4px;
}
.settings-about {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  margin: 0;
  text-align: center;
  opacity: 0.75;
}
.settings-about a { color: var(--ink); text-decoration: underline; }

/* ══════════════════════════════════════════════════════════════════════════
   SOUS-MODAL FEEDBACK
   ────────────────────────────────────────────────────────────────────────── */
.feedback-backdrop {
  position: fixed;
  inset: 0;
  z-index: 650;             /* au-dessus du modal Paramètres (600) */
  background: rgba(10,10,10,0.78);
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-3);
}
.feedback-backdrop.show { display: flex; }
.feedback-modal {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-lg);
  max-width: 520px;
  width: 100%;
  max-height: 92vh;
  overflow: hidden;        /* scroll délégué au wrapper .settings-scroll interne */
  display: flex;
  flex-direction: column;
}
.feedback-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--border-thick);
  background: #ead4ff;       /* violet pastel cohérent avec le bloc d'origine */
  flex-shrink: 0;
}
.feedback-title {
  font-family: var(--font-display);
  font-size: clamp(18px, 2.6vw, 24px);
  text-transform: uppercase;
  letter-spacing: -0.01em;
  margin: 0;
  text-align: center;
}
.feedback-body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Chips type ─────────────────────────────────────────────────────────── */
.feedback-types { border: 0; padding: 0; margin: 0; }
.feedback-types legend {
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 8px;
  padding: 0;
}
.feedback-types-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.feedback-type-chip {
  position: relative;
  cursor: pointer;
}
.feedback-type-chip input { position: absolute; opacity: 0; pointer-events: none; }
.feedback-type-content {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 10px 8px;
  border: var(--border-thick);
  background: var(--paper);
  font-family: var(--font-display);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  transition: transform var(--dur-fast), box-shadow var(--dur-fast), background var(--dur-fast);
}
.feedback-type-chip input:checked + .feedback-type-content {
  background: var(--ink);
  color: var(--paper);
  box-shadow: var(--sh-sm);
  transform: translate(-1px, -1px);
}
.feedback-type-chip input:focus-visible + .feedback-type-content {
  outline: 3px solid var(--violet);
  outline-offset: 2px;
}

/* Textarea ───────────────────────────────────────────────────────────── */
.feedback-field { display: flex; flex-direction: column; gap: 6px; }
.feedback-textarea {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  padding: 10px 12px;
  border: var(--border-thick);
  background: var(--paper);
  outline: none;
  resize: vertical;
  min-height: 120px;
  width: 100%;
  box-sizing: border-box;
}
.feedback-textarea:focus { background: var(--white); box-shadow: var(--sh-sm); }
.feedback-counter {
  font-family: var(--font-mono);
  font-size: 11px;
  opacity: 0.7;
  margin: 0;
  text-align: right;
}

/* Contexte (details) ─────────────────────────────────────────────────── */
.feedback-context {
  border: 2px dashed rgba(10,10,10,0.3);
  padding: 8px 12px;
  background: var(--paper-2);
}
.feedback-context summary {
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  list-style: none;
}
.feedback-context summary::before {
  content: '+ ';
  display: inline-block;
  width: 14px;
  font-family: var(--font-mono);
}
.feedback-context[open] summary::before { content: '− '; }
.feedback-context-preview {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-all;
  margin: 8px 0 0 0;
  opacity: 0.85;
}

/* Actions feedback ───────────────────────────────────────────────────── */
.feedback-actions { display: flex; flex-direction: column; gap: 8px; }
.feedback-status {
  font-family: var(--font-mono);
  font-size: 12px;
  margin: 0;
  min-height: 1em;
  text-align: center;
}
.feedback-status--ok  { color: var(--green-2); }
.feedback-status--err { color: var(--red); }

/* ══════════════════════════════════════════════════════════════════════════
   BADGES JOUEUR — chip dans la status bar + modal de sélection
   Réutilise les gradients tier-or/argent/bronze de .dcard .badge (stats.html).
   ────────────────────────────────────────────────────────────────────────── */

/* Chip "badge actif" dans la status bar des classements ──────────────── */
.player-badge {
  display: inline-flex; align-items: center; gap: 6px;
  height: 26px; padding: 0 10px 0 8px;
  border: 2px solid var(--ink);
  font-family: var(--font-display);
  font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase;
  cursor: pointer;
  opacity: 1;                                    /* pas de fade comme le reste de la bar */
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
  box-shadow: 2px 2px 0 0 var(--ink);
  line-height: 1;
}
.player-badge:hover { transform: translate(-1px, -1px); box-shadow: 4px 4px 0 0 var(--ink); }
.player-badge-icon {
  width: 14px; height: 14px;
  color: currentColor;                           /* hérite de la couleur du chip (tier-fg) */
}
.player-badge-text { white-space: nowrap; }

/* Tiers — gradients identiques à .dcard .badge.tier-* (stats.html) */
.player-badge.tier-or {
  background: linear-gradient(135deg,#8a6508 0%,#e8b015 35%,#fff2a8 50%,#d49a0c 65%,#704f06 100%);
  color: #3a2a00;
  text-shadow: 0 1px 0 rgba(255,240,180,.5);
}
.player-badge.tier-argent {
  background: linear-gradient(135deg,#6e6e6e 0%,#c9c9c9 35%,#ffffff 50%,#b8b8b8 65%,#5e5e5e 100%);
  color: var(--ink);
}
.player-badge.tier-bronze {
  background: linear-gradient(135deg,#7a3f12 0%,#c87a35 35%,#f3c98a 50%,#a85e22 65%,#6a3410 100%);
  color: #fff4e3;
  text-shadow: 0 1px 0 rgba(0,0,0,.35);
}

/* CTA "+ Choisir un badge" si aucun badge actif ──────────────────────── */
.player-badge-empty {
  display: inline-flex; align-items: center;
  height: 26px; padding: 0 10px;
  background: transparent;
  border: 2px dashed rgba(10,10,10,0.45);
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.04em;
  cursor: pointer;
  opacity: 0.85;
  transition: background var(--dur-fast), border-color var(--dur-fast);
  line-height: 1;
}
.player-badge-empty:hover {
  background: var(--paper-2);
  border-color: var(--ink);
}

/* Texte muet dans la status bar (pour "non connecté·e", etc.) */
.lb-status-mute { opacity: 0.7; }

/* Modal Mes badges ───────────────────────────────────────────────────── */
.badge-picker-backdrop {
  position: fixed; inset: 0;
  z-index: 620;                                  /* > settings (600), < feedback (650) */
  background: rgba(10,10,10,0.78);
  display: none; align-items: center; justify-content: center;
  padding: var(--space-3);
}
.badge-picker-backdrop.show { display: flex; }
.badge-picker-modal {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-lg);
  max-width: 540px;
  width: 100%;
  max-height: 92vh;
  overflow: hidden;                              /* scroll délégué à .settings-scroll */
  display: flex; flex-direction: column;
}
.badge-picker-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--border-thick);
  background: var(--yellow);
  flex-shrink: 0;
}
.badge-picker-title {
  font-family: var(--font-display);
  font-size: clamp(18px, 2.6vw, 24px);
  text-transform: uppercase;
  letter-spacing: -0.01em;
  margin: 0;
}
.badge-picker-close {
  width: 36px; height: 36px;
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  font-family: var(--font-display);
  font-size: 16px;
  cursor: pointer;
  display: grid; place-items: center;
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.badge-picker-close:hover { transform: translate(-2px, -2px); box-shadow: 5px 5px 0 0 var(--ink); }

.badge-picker-body {
  padding: var(--space-4);
  display: flex; flex-direction: column; gap: var(--space-4);
}

/* Notif "tu as perdu ton badge" ──────────────────────────────────────── */
.badge-picker-notif {
  background: var(--orange);
  border: var(--border-thick);
  padding: 10px 14px;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.4;
  box-shadow: var(--sh-sm);
}

.badge-picker-section { display: flex; flex-direction: column; gap: 10px; }
.badge-picker-sub {
  font-family: var(--font-display);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 0;
  border-bottom: 3px solid var(--ink);
  padding-bottom: 6px;
}
.badge-picker-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}
@media (min-width: 480px) {
  .badge-picker-grid { grid-template-columns: 1fr 1fr; }
}

/* Carte badge dans le picker (disponible OU verrouillée) ─────────────── */
.badge-pick-card {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: var(--border-thick);
  background: var(--paper);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  color: var(--ink);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
  box-shadow: var(--sh-sm);
}
.badge-pick-card:hover:not(.is-locked) {
  transform: translate(-2px, -2px);
  box-shadow: 5px 5px 0 0 var(--ink);
}
.badge-pick-card.tier-or {
  background: linear-gradient(135deg,#8a6508 0%,#e8b015 35%,#fff2a8 50%,#d49a0c 65%,#704f06 100%);
  color: #3a2a00;
}
.badge-pick-card.tier-argent {
  background: linear-gradient(135deg,#6e6e6e 0%,#c9c9c9 35%,#ffffff 50%,#b8b8b8 65%,#5e5e5e 100%);
  color: var(--ink);
}
.badge-pick-card.tier-bronze {
  background: linear-gradient(135deg,#7a3f12 0%,#c87a35 35%,#f3c98a 50%,#a85e22 65%,#6a3410 100%);
  color: #fff4e3;
}
.badge-pick-card.is-current {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}
.badge-pick-card.is-locked {
  background: var(--paper-2);
  cursor: not-allowed;
  opacity: 0.55;
  filter: grayscale(0.8);
  box-shadow: 2px 2px 0 0 rgba(10,10,10,0.4);
}
.badge-pick-icon {
  width: 22px; height: 22px;
  color: currentColor;                            /* suit la couleur de texte du tier */
}
.badge-pick-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.badge-pick-title {
  font-family: var(--font-display);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1.15;
}
.badge-pick-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  opacity: 0.78;
  text-transform: none;
}
.badge-pick-check {
  width: 20px; height: 20px;
  color: currentColor;
}

.badge-picker-empty {
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.5;
  text-align: center;
  padding: 24px 12px;
  background: var(--paper-2);
  border: 2px dashed rgba(10,10,10,0.3);
  opacity: 0.85;
}

.badge-picker-actions {
  border-top: 2px dashed rgba(10,10,10,0.25);
  padding-top: 12px;
}

/* Bouton de donation néobrut — pleine largeur, accent jaune chaleureux.
   Animation "breathing" loop subtile pour attirer l'œil sans agressivité.
   transform-origin décalé pour un sway légèrement asymétrique (plus naturel).
   Désactivée au hover/active pour ne pas conflicter avec les transforms ciblés.
   Respecte automatiquement html.reduce-motion (règle globale). */
@keyframes donate-breathe {
  0%, 100% { transform: rotate(-0.7deg) translateY(0)    scale(1);     }
  50%      { transform: rotate( 0.9deg) translateY(-2px) scale(1.022); }
}
.settings-donate {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px;
  background: var(--yellow, #ffe066);
  border: var(--border-thick);
  box-shadow: 5px 5px 0 rgba(10,10,10,0.4);
  text-decoration: none; color: var(--ink);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
  animation: donate-breathe 3.4s ease-in-out infinite;
  transform-origin: 28% 60%;  /* pivote autour de l'emoji ☕ */
  will-change: transform;
}
.settings-donate:hover,
.settings-donate:active,
.settings-donate:focus-visible {
  animation: none;
}
.settings-donate:hover {
  transform: translate(-2px, -2px);
  box-shadow: 7px 7px 0 rgba(10,10,10,0.5);
}
.settings-donate:active {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 rgba(10,10,10,0.4);
}
.settings-donate-emoji {
  font-size: 32px; line-height: 1;
  font-family: 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif;
  flex-shrink: 0;
}
.settings-donate-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.settings-donate-title {
  font-family: var(--font-display); font-size: 17px;
  letter-spacing: 0.01em; text-transform: uppercase;
  line-height: 1.1;
}
.settings-donate-sub {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.06em; opacity: 0.75;
}

/* Emoji "Classical Building" 🏛️ utilisé avant les titres de page —
   stroke fin pour détacher du fond + grosse ombre portée en bas-droite
   (façon tampon néobrut). Légèrement superposé au début du titre. */
.site-emoji {
  display: inline-block;
  position: relative;
  z-index: 2;               /* passe au-dessus du fond coloré du .accent */
  font-size: 1.15em;
  line-height: 1;
  vertical-align: middle;
  margin-right: -0.3em;     /* mord franchement le titre qui suit */
  transform: rotate(-6deg) translateY(-0.05em);
  filter:
    /* Stroke ~2 px (cardinales + diagonales pour combler) */
    drop-shadow( 2px  0   0 var(--ink))
    drop-shadow(-2px  0   0 var(--ink))
    drop-shadow( 0    2px 0 var(--ink))
    drop-shadow( 0   -2px 0 var(--ink))
    drop-shadow( 1.5px  1.5px 0 var(--ink))
    drop-shadow(-1.5px  1.5px 0 var(--ink))
    drop-shadow( 1.5px -1.5px 0 var(--ink))
    drop-shadow(-1.5px -1.5px 0 var(--ink))
    /* Grosse ombre portée d'un côté (en bas-droite) — effet néobrut */
    drop-shadow(5px 5px 0 var(--ink));
  flex-shrink: 0;
}

.site-title .accent {
  /* fond + texte définis dynamiquement par applyRandomTitleColor() ;
     var(--blue) en fallback avant que le JS s'exécute */
  background: var(--blue);
  color: var(--paper);
  padding: 1px 8px;
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  display: inline-block;
  transform: rotate(-1deg);
  margin-left: 6px;
  text-transform: uppercase;
  transition: background-color var(--dur-base), color var(--dur-base);
  user-select: none;
}
.site-title .accent:hover {
  transform: rotate(-1deg) translate(-1px, -1px);
  box-shadow: 5px 5px 0 0 var(--ink);
}

/* ── Icon utility ────────────────────────────────────────────────────────── */
.ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.ico-svg { display: block; }

/* ── Main grid ───────────────────────────────────────────────────────────── */
.main {
  display: grid;
  grid-template-columns: clamp(200px, calc((100dvh - 142px) * 0.75 + 42px), 48%) 1fr;
  grid-template-rows: 1fr;
  gap: var(--space-4);
  flex: 1;
  min-height: 0;
  overflow: visible;
}

/* ── Card stack ──────────────────────────────────────────────────────────── */
.card-stack {
  position: relative;
  height: 100%;
  min-height: 0;
}

.deputy-card-shadow {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--white);
  border: var(--border-thick);
  box-shadow: var(--sh-lg);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  /* overflow: hidden pour clipper les tampons agrandis qui peuvent dépasser
     du cadre du shadow (sinon on voit un « fantôme » de tampon par-dessus
     le titre quand la card principale swipe-out et révèle le shadow). */
  overflow: hidden;
  /* Container query context pour les unités cqi des tampons (.fx-stamp-*). */
  container-type: inline-size;
}
.shadow-photo-wrap {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  overflow: visible;
  border: var(--border-thick);
  background: var(--paper-2);
  container-type: inline-size;
}
.shadow-photo {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}

.deputy-card {
  background: var(--white);
  border: var(--border-thick);
  box-shadow: var(--sh-lg);
  padding: var(--space-4);
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  height: 100%;
  overflow: hidden;
  transition: transform 0.55s cubic-bezier(0.45, 0.05, 0.55, 0.95);
  will-change: transform;
  /* Container query context pour les unités cqi des tampons (.fx-stamp-*).
     Permet aussi aux tampons d'occuper toute la zone carte (incluant le
     padding autour de .photo-wrap), spécialement utile sur mobile. */
  container-type: inline-size;
}
.deputy-card.swiping-out {
  /* Trajectoire de chute : X linéaire dans le temps, Y quadratique (gravité).
     Linear timing — la courbe vient des positions des keyframes elles-mêmes. */
  animation: swipeOutCurve 0.55s linear forwards;
}
@keyframes swipeOutCurve {
  /* X(p) = p × X_final  (linéaire — vitesse horizontale constante)
     Y(p) = p² × Y_final (quadratique — accélération vers le bas)
     rot(p) = p × rot_final  ·  scale(p) = 1 + p × (scale_final − 1) */
  0% {
    transform: translate(0, 0) rotate(0) scale(1);
  }
  25% {
    transform:
      translate(calc(var(--swipe-x, -120vw) * 0.25), calc(var(--swipe-y, 80vh) * 0.0625))
      rotate(calc(var(--swipe-rot, -25deg) * 0.25))
      scale(calc(1 + (var(--swipe-scale, 0.75) - 1) * 0.25));
  }
  50% {
    transform:
      translate(calc(var(--swipe-x, -120vw) * 0.50), calc(var(--swipe-y, 80vh) * 0.25))
      rotate(calc(var(--swipe-rot, -25deg) * 0.50))
      scale(calc(1 + (var(--swipe-scale, 0.75) - 1) * 0.50));
  }
  75% {
    transform:
      translate(calc(var(--swipe-x, -120vw) * 0.75), calc(var(--swipe-y, 80vh) * 0.5625))
      rotate(calc(var(--swipe-rot, -25deg) * 0.75))
      scale(calc(1 + (var(--swipe-scale, 0.75) - 1) * 0.75));
  }
  100% {
    transform:
      translate(var(--swipe-x, -120vw), var(--swipe-y, 80vh))
      rotate(var(--swipe-rot, -25deg))
      scale(var(--swipe-scale, 0.75));
  }
}

/* ── Shiny card — apparaît ~1/15 fois, double les points ──────────────── */
/* Glow doré pulsant autour de la carte (box-shadow, ne couvre aucun bouton).
   `--card-sh-base` reprend l'ombre néobrut de la carte (sh-lg desktop, sh-md
   mobile via override) → shiny/holo gardent la MÊME ombre portée que la
   carte non-rare, juste avec un glow par-dessus. Sans cette variable, le
   keyframe imposait sh-lg en mobile et la shiny dépassait l'hémicycle.
   Délai -0.9s aligné sur les autres animations shiny → le glow est déjà au
   peak (50%) au moment où la carte apparaît, plus de « stagger » de 900ms
   où le glow monte depuis zéro. */
.deputy-card { --card-sh-base: var(--sh-lg); }
.deputy-card.shiny {
  animation: shinyGlow 1.8s ease-in-out -0.9s infinite;
}
/* Quand une carte shiny part en swipe-out, on combine les deux animations
   (sinon shiny gagne par cascade et le swipe-out n'a pas lieu). */
.deputy-card.shiny.swiping-out {
  animation:
    shinyGlow 1.8s ease-in-out -0.9s infinite,
    swipeOutCurve 0.55s linear forwards;
}
@keyframes shinyGlow {
  0%, 100% { box-shadow: var(--card-sh-base, var(--sh-lg)), 0 0 0 rgba(245, 197, 24, 0); }
  50%      { box-shadow: var(--card-sh-base, var(--sh-lg)), 0 0 28px rgba(245, 197, 24, 0.75); }
}

/* Couche dédiée aux effets shiny — clip ses propres pseudos sans toucher le post-it.
   `contain: layout paint` isole les recalculs au sous-arbre → l'apparition
   d'une nouvelle carte shiny/holo n'invalide pas le layout du parent et
   réduit le « stagger » visible sur le shimmer à la 1ère frame.
   `transform: translateZ(0)` force la promotion GPU dès la base (pas
   d'attente du compositor au moment du display:block toggle). */
.shiny-fx {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 2;
  display: none;
  contain: layout paint;
  transform: translateZ(0);
}
.deputy-card.shiny .shiny-fx,
.deputy-card.holo  .shiny-fx,
.deputy-card-shadow.shiny .shiny-fx,
.deputy-card-shadow.holo  .shiny-fx {
  display: block;
}
/* Bordure dorée pulsante (carte courante + shadow card pour pre-style).
   Délai -0.85s pour rester aligné sur .photo-wrap (-0.9s) avec un micro
   décalage (≈50 ms) — donne de la profondeur sans flou de phase visible
   sur le bord intérieur de la double bordure. */
.deputy-card.shiny .shiny-fx::before,
.deputy-card-shadow.shiny .shiny-fx::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 4px solid #f5c518;
  pointer-events: none;
  animation: shinyBorderPulse 1.8s ease-in-out -0.85s infinite;
}
@keyframes shinyBorderPulse {
  0%, 100% { box-shadow: inset 0 0 8px rgba(255, 215, 0, 0.4); }
  50%      { box-shadow: inset 0 0 22px rgba(255, 230, 102, 0.8); }
}
/* Bordure HOLO iridescente : cycle de couleurs sur 6 paliers (rose →
   cyan → jaune → vert → orange → magenta). Plus rapide et plus saturé
   que la version shiny pour bien marquer la rareté ×5. Délai -0.55s
   (≈50 ms après .photo-wrap -0.6s) pour le même micro décalage. */
.deputy-card.holo  .shiny-fx::before,
.deputy-card-shadow.holo  .shiny-fx::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 4px solid #ff00ff;
  pointer-events: none;
  animation: holoBorderHue 3s linear -0.55s infinite;
}
@keyframes holoBorderHue {
  0%   { border-color: #ff00ff; box-shadow: inset 0 0 14px rgba(255, 0, 255, 0.55); }
  20%  { border-color: #00ffff; box-shadow: inset 0 0 14px rgba(0, 255, 255, 0.55); }
  40%  { border-color: #ffff00; box-shadow: inset 0 0 14px rgba(255, 255, 0, 0.55); }
  60%  { border-color: #00ff66; box-shadow: inset 0 0 14px rgba(0, 255, 100, 0.55); }
  80%  { border-color: #ff6633; box-shadow: inset 0 0 14px rgba(255, 100, 50, 0.55); }
  100% { border-color: #ff00ff; box-shadow: inset 0 0 14px rgba(255, 0, 255, 0.55); }
}
/* Bordure photo dorée pour les rôles rectangulaires (depute, etc.) en mode
   shiny/holo. Les rôles avec clip-path mettent leur .photo en border:none,
   donc ces règles n'ont aucun effet sur eux (l'animation SVG du polygon
   prend le relais pour suivre la forme). Pas de box-shadow inset ici (sinon
   on tinte la photo elle-même). */
@keyframes shinyPhotoBorder {
  0%, 100% { border-color: #f5c518; }
  50%      { border-color: #fff09a; }
}
@keyframes holoPhotoBorder {
  0%   { border-color: #ff00ff; }
  20%  { border-color: #00ffff; }
  40%  { border-color: #ffff00; }
  60%  { border-color: #00ff66; }
  80%  { border-color: #ff6633; }
  100% { border-color: #ff00ff; }
}
/* Animations en pause par défaut (perf grille + sync avec .shiny-fx::before
   qui est aussi paused). Reprises au hover/focus/shiny-active : les deux
   strokes redémarrent à 0% en même temps → cycles iridescents synchronisés.
   Délais identiques à .shiny-fx::before pour que la frame figée soit cohérente
   entre les deux strokes (cadre + photo même couleur). */
.dcard.shiny .photo,
.deputy-card.shiny .photo-wrap,
.deputy-card-shadow.shiny .shadow-photo-wrap {
  animation: shinyPhotoBorder 1.8s ease-in-out -0.9s infinite;
  animation-play-state: paused;
}
.dcard.holo .photo,
.deputy-card.holo .photo-wrap,
.deputy-card-shadow.holo .shadow-photo-wrap {
  animation: holoPhotoBorder 3s linear -0.6s infinite;
  animation-play-state: paused;
}
.dcard.shiny:hover .photo,
.dcard.shiny:focus-within .photo,
.dcard.shiny.shiny-active .photo,
.dcard.holo:hover .photo,
.dcard.holo:focus-within .photo,
.dcard.holo.shiny-active .photo,
.deputy-card.shiny .photo-wrap,
.deputy-card.holo  .photo-wrap,
.deputy-card-shadow.shiny .shadow-photo-wrap,
.deputy-card-shadow.holo  .shadow-photo-wrap {
  animation-play-state: running;
}
/* Shimmer diagonal — élément 200% de large, translation de -50% à 0%
   (= shift d'une demi-largeur = une période). Le gradient contient DEUX
   bands identiques, espacées d'exactement une période. Quand la première
   sort à droite, la deuxième est centrée → continuité visuelle.
   Plus : un léger fade-in/out aux extrémités du cycle pour adoucir le
   point de loop (la moindre désynchro est masquée par l'opacité qui dip). */
.deputy-card.shiny .shiny-fx::after,
.deputy-card-shadow.shiny .shiny-fx::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 200%;
  height: 100%;
  background: linear-gradient(115deg,
    transparent 17%,
    rgba(255, 232, 120, 0.5) 25%,
    transparent 33%,
    transparent 67%,
    rgba(255, 232, 120, 0.5) 75%,
    transparent 83%);
  transform: translate3d(-50%, 0, 0);
  /* Délai -0.7s (≈25% du cycle) aligné sur la version Collection (.dcard).
     Sans ça, le shimmer démarrait à opacity 0 → 500ms invisibles à l'apparition
     de la carte = effet de « stagger » du gradient. Avec -0.7s on rentre déjà
     dans la zone opaque visible. */
  animation: shinyShimmer 2.8s linear -0.7s infinite;
  will-change: transform, opacity;
}
/* Shimmer HOLO : deux bands multicolores aux mêmes positions (25% et 75%
   du gradient), avec hue-rotate continue par-dessus pour l'effet oil-slick.
   Opacité réduite (0.30 vs 0.45 avant) — l'effet était trop chargé. */
.deputy-card.holo  .shiny-fx::after,
.deputy-card-shadow.holo  .shiny-fx::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 200%;
  height: 100%;
  background: linear-gradient(115deg,
    transparent 13%,
    rgba(255, 100, 200, 0.30) 19%,
    rgba(100, 200, 255, 0.30) 23%,
    rgba(255, 220, 100, 0.30) 27%,
    rgba(180, 100, 255, 0.30) 31%,
    transparent 37%,
    transparent 63%,
    rgba(255, 100, 200, 0.30) 69%,
    rgba(100, 200, 255, 0.30) 73%,
    rgba(255, 220, 100, 0.30) 77%,
    rgba(180, 100, 255, 0.30) 81%,
    transparent 87%);
  transform: translate3d(-50%, 0, 0);
  /* Mêmes délais qu'en shiny : -0.7s sur shinyShimmer (translate visible
     d'emblée) et -1s sur holoShimmerHue (cyan/orange dès l'apparition). */
  animation: shinyShimmer 2.8s linear -0.7s infinite, holoShimmerHue 4s linear -1s infinite;
  will-change: transform, opacity;
}
/* Shimmer keyframes : translation linéaire + fade-in/out COMPLET aux 2 bouts.
   Opacity passe à 0 aux extrémités → la band est totalement invisible au
   moment du loop. Le jump du transform (de translate(0) à translate(-50%))
   se fait pendant que l'opacité est nulle → 100% imperceptible.
   Fade plus large (18% de chaque côté = ~500ms) pour une transition douce. */
@keyframes shinyShimmer {
  0%   { transform: translate3d(-50%, 0, 0); opacity: 0; }
  18%  { opacity: 1; }
  82%  { opacity: 1; }
  100% { transform: translate3d(0%, 0, 0);   opacity: 0; }
}
@keyframes holoShimmerHue {
  0%   { filter: hue-rotate(0deg); }
  100% { filter: hue-rotate(360deg); }
}

/* Étoile shiny sur la carte Collection (SVG net, contour propre) */
.dcard .shiny-star {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 4;
  width: 22px;
  height: 22px;
  display: inline-block;
  line-height: 0;
  pointer-events: none;
  filter: drop-shadow(0 1px 0 var(--ink)) drop-shadow(1px 0 0 var(--ink));
}
.dcard .shiny-star svg { display: block; }

/* Variante "shiny" : fond doré, label complet visible jusqu'au shrink */
.collection-fly.shiny {
  background: #f5c518;
  color: var(--ink);
  border-color: var(--ink);
}
.collection-fly.shiny .cf-mark {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  margin-right: 4px;
}
/* Variante holographique : gradient iridescent en background, animé */
.collection-fly.holo {
  background: linear-gradient(115deg, #ff00ff 0%, #00ffff 25%, #ffff00 50%, #00ff66 75%, #ff00ff 100%);
  background-size: 200% 100%;
  color: var(--ink);
  border-color: var(--ink);
  animation: holoFlyShift 1.4s linear infinite;
}
.collection-fly.holo .cf-mark {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  margin-right: 4px;
}
@keyframes holoFlyShift {
  0%   { background-position: 0% 0; }
  100% { background-position: 200% 0; }
}
/* Phase 2 — bumper rétréci :
   - `cf-label-full` + `cf-mark` passent en `display: none` (hors flow) →
     l'offsetWidth mesuré reflète juste « +1 » + padding (sinon le label
     long, même en opacity:0, contribuait à la layout width et `shrunkW`
     restait ≈ `fullW` → box ne rétrécissait pas).
   - `cf-label-short` devient `display: inline-block`, position static
     (en flow) → centré par le `justify-content: center` du flex parent.
   - L'explicit width posée en JS (fly.style.width = fullW → shrunkW) +
     `transition: width 280ms` (cf. .collection-fly) → la box rétrécit
     smooth depuis la pleine largeur jusqu'à la taille « +1 ». */
.collection-fly .cf-label-short { display: none; }
.collection-fly.shrunk .cf-label-full,
.collection-fly.shrunk .cf-mark { display: none; }
.collection-fly.shrunk .cf-label-short { display: inline-block; }
.collection-fly.shrunk {
  padding: 4px 11px 6px;
  font-size: 20px;
}

/* Bumper « +1 » simple (carte normale) — pop juste à GAUCHE du bouton
   Collection (positionné en JS via left/top px, transform centré
   translate(-50%,-50%)). Évite la troncature haut-du-viewport sur desktop. */
.collection-bump {
  position: fixed;
  transform: translate(-50%, -50%) scale(0);
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 1;
  padding: 4px 11px 6px;
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  color: var(--green);
  pointer-events: none;
  z-index: 600;
  white-space: nowrap;
  animation: collectionBumpSimple 1.2s ease-out both;
  will-change: transform, opacity;
}
@keyframes collectionBumpSimple {
  0%   { transform: translate(-50%, -50%) scale(0)    rotate(-8deg); opacity: 0; }
  22%  { transform: translate(-50%, -50%) scale(1.2)  rotate(4deg);  opacity: 1; }
  40%  { transform: translate(-50%, -50%) scale(1)    rotate(-2deg); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(0.75) rotate(-2deg); opacity: 0; }
}

.photo-wrap {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  overflow: visible;
  border: var(--border-thick);
  background: var(--paper-2);
  container-type: inline-size;
}
.deputy-photo {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
  user-select: none;
}
/* Legacy : .scan-lines neutralisé (effets photo via pseudos ci-dessous). */
.scan-lines { display: none; }

/* ── Effets photo combo (reset from scratch) ───────────────────────────────
   Empilage de 4 effets sur les deux wrappers photo (jeu + carte suivante
   en shadow) :
   - box-shadow inset blanc fort : inner glow clair (halo lumineux interne)
   - ::before = stippling fin (turbulence haute fréquence) + scan lines
                 fines (linear-gradient 1 sur 4 px) en multiply
   - ::after  = overlay couleur chaude (tint doré, multiply)
   Aucun filter sur l'image elle-même : la couleur d'origine est préservée,
   les effets se posent par dessus. */
.photo-wrap, .shadow-photo-wrap {
  box-shadow: inset 0 0 60px 12px rgba(255,255,255,0.58);
}
.photo-wrap::before, .shadow-photo-wrap::before {
  content: '';
  position: absolute; inset: 0;
  /* Stippling fin (turbulence haute fréquence, comme G14) + scan lines fines
     (repeating linear, comme G15). Empilés dans un même pseudo via background
     multi-layer. */
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence baseFrequency='1.8' numOctaves='1' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 -0.8'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>"),
    repeating-linear-gradient(0deg, rgba(0,0,0,0) 0 3px, rgba(0,0,0,0.10) 3px 4px);
  background-size: 120px 120px, 100% 4px;
  mix-blend-mode: multiply;
  opacity: 0.50;
  pointer-events: none;
  z-index: 1;
}
/* En mode shiny / holo : on retire à la fois les scan lines ET le stippling
   pour ne pas casser l'effet d'iridescence — seul l'overlay tint warm
   (cf. ::after) et l'inner glow restent. */
.deputy-card.shiny .photo-wrap::before,
.deputy-card.holo  .photo-wrap::before,
.deputy-card-shadow.shiny .shadow-photo-wrap::before,
.deputy-card-shadow.holo  .shadow-photo-wrap::before {
  background: none;
}
.photo-wrap::after, .shadow-photo-wrap::after {
  content: '';
  position: absolute; inset: 0;
  /* Overlay tinted warm (comme proposition I) — teinte chaude légère qui
     unifie les photos sans assombrir trop. */
  background: rgba(245, 195, 110, 0.24);
  mix-blend-mode: multiply;
  pointer-events: none;
  z-index: 1;
}
.corner {
  position: absolute;
  width: 16px; height: 16px;
  border: 3px solid var(--ink);
  pointer-events: none;
}
.corner.tl { top: 8px; left: 8px; border-right: 0; border-bottom: 0; }

/* Stamp ✓/✗ on card — neo-brutalist block */
.stamp {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) rotate(-8deg) scale(0.3);
  width: clamp(140px, 28vw, 240px);
  height: clamp(140px, 28vw, 240px);
  padding: 22px;
  border: 6px solid var(--ink);
  border-radius: 0;
  opacity: 0;
  pointer-events: none;
  z-index: 10;
  box-shadow: 10px 10px 0 0 var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
}
.stamp svg { width: 100%; height: 100%; display: block; }
.stamp[data-tone="correct"] { background: var(--green); color: var(--ink); }
.stamp[data-tone="wrong"]   { background: var(--m-gauche); color: var(--ink); }
.stamp.show {
  animation: stampSlam 360ms cubic-bezier(.18,.89,.32,1.28) forwards;
}
@keyframes stampSlam {
  0%   { opacity: 0; transform: translate(-50%, -50%) rotate(-8deg) scale(2.2); }
  55%  { opacity: 1; transform: translate(-50%, -50%) rotate(-8deg) scale(0.94); }
  78%  { transform: translate(-50%, -50%) rotate(-8deg) scale(1.04); }
  100% { opacity: 1; transform: translate(-50%, -50%) rotate(-8deg) scale(1); }
}
.corner.tr { top: 8px; right: 8px; border-left: 0; border-bottom: 0; }
.corner.bl { bottom: 8px; left: 8px; border-right: 0; border-top: 0; }
.corner.br { bottom: 8px; right: 8px; border-left: 0; border-top: 0; }

/* ── Post-it Indice ──────────────────────────────────────────────────────── */
/* Sibling de .deputy-card dans .card-stack → déborde librement du cadre.
   Layout vertical 4 lignes (icône en pavé noir · "Demander" · "un indice"
   · prix). Animation : sway constant + respiration (durée FIXE pour ne
   pas restart sur chaque update --hint-amp, c'est ça qui causait le
   stagger). Seule l'amplitude est animée par JS. */
/* Le wrapper EST le post-it (bg, border, padding, rotation, animations).
   Les enfants (message + bouton) sont des zones de contenu transparentes
   À L'INTÉRIEUR de la même boîte → quand le bouton se rétracte, il rentre
   "dans" le message sans dédoublement visuel. */
.hint-postit-wrap {
  position: absolute;
  top: -10px;
  right: 4px;
  z-index: 25;
  background: var(--yellow);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  padding: 6px 8px;
  /* Hauteur verrouillée à la hauteur naturelle du contenu bouton, peu importe
     que le bouton soit visible ou rétracté. Empêche tout grossissement de
     hauteur du post-it. Border-box → ces 110px incluent padding + border. */
  min-height: 110px;
  max-height: 110px;
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  line-height: 1.1;
  rotate: 4deg;
  scale: 1;
  animation: hintSway 3.6s ease-in-out infinite,
             hintBreathe 1.6s ease-in-out infinite alternate;
  transition: opacity 200ms ease, transform 280ms cubic-bezier(.34, 1.56, .64, 1);
  pointer-events: none;
}
@keyframes hintSway {
  0%, 100% { rotate: 3deg; }
  50%      { rotate: 5deg; }
}
@keyframes hintBreathe {
  from { scale: 1; }
  to   { scale: calc(1 + var(--hint-amp, 0.02)); }
}

/* Bouton (carrier du clic + contenu icône/libellé/prix). Pas de bg/border :
   c'est le wrap qui fait le post-it. Peut se rétracter sans casser la boîte.
   align-self: center → garde sa hauteur naturelle même si le wrap est en
   align-items: stretch (pour que SEUL le message s'étire à la hauteur du
   bouton pour le séparateur — pas l'inverse). */
.hint-postit {
  pointer-events: auto;
  align-self: center;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  line-height: inherit;
  cursor: pointer;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  max-width: 240px;
  opacity: 1;
  overflow: hidden;
  transition: max-width 320ms cubic-bezier(.4, 0, .2, 1),
              opacity 200ms ease,
              margin-left 320ms cubic-bezier(.4, 0, .2, 1);
}
.hint-postit:hover, .hint-postit:focus-visible {
  filter: brightness(0.96);
}
/* Hint-out : le bouton se rétracte horizontalement (max-width 0) et fade.
   Visuellement il "rentre" dans la zone message (à sa gauche). Le wrap
   reste un post-it cohérent, juste plus court. */
.hint-postit.hint-out {
  max-width: 0;
  opacity: 0;
  pointer-events: none;
  margin-left: 0;
}

/* Zone message — sibling du bouton, à sa gauche. Pas de bg/border (le
   wrap fait le décor). Apparait en sliding (max-width 0 → 210px). */
.hint-postit-message {
  pointer-events: auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 16px;
  text-transform: none;
  letter-spacing: 0.01em;
  line-height: 1.15;
  color: var(--ink);
  max-width: 0;
  /* Le texte peut wrapper sur plusieurs lignes (white-space normal). La
     hauteur du wrap étant verrouillée par min/max-height, un message multi-
     ligne s'affichera dans la zone allouée, centré verticalement. */
  overflow: hidden;
  opacity: 0;
  transition: max-width 360ms cubic-bezier(.34, 1.56, .64, 1),
              opacity 200ms ease 120ms;
}
.hint-postit-wrap.has-message .hint-postit-message {
  max-width: 200px;
  opacity: 1;
}

/* Séparateur vertical : élément dédié, align-self: stretch pour matcher la
   hauteur naturelle du bouton (qui définit la hauteur du wrap). N'affecte
   PAS la hauteur du wrap (élément vide, natural height = 0 → ne pèse pas
   dans le max-children calcul de flex). */
.hint-postit-sep {
  width: 0;
  align-self: stretch;
  background: var(--ink);
  margin: 0;
  opacity: 0;
  transition: width 360ms cubic-bezier(.34, 1.56, .64, 1),
              margin 360ms cubic-bezier(.34, 1.56, .64, 1),
              opacity 200ms ease 120ms;
}
.hint-postit-wrap.has-message .hint-postit-sep {
  width: 2px;
  margin: 0 8px;
  opacity: 1;
}
/* Si le bouton est rétracté : séparateur disparait (plus rien à séparer). */
.hint-postit-wrap.has-message:has(.hint-postit.hint-out) .hint-postit-sep {
  width: 0;
  margin: 0;
  opacity: 0;
}
/* Si le wrap n'a plus de contenu (bouton retiré ET pas de message), on cache
   tout le post-it pour ne pas laisser un cadre vide. */
.hint-postit-wrap:not(.has-message):has(.hint-postit.hint-out) {
  opacity: 0;
  transform: scale(0);
  pointer-events: none;
}
@media (max-width: 860px) {
  .hint-postit-message { font-size: 13.5px; }
  .hint-postit-wrap.has-message .hint-postit-message {
    max-width: 140px;
    margin-right: 6px;
  }
}
/* Icône ? dans un pavé noir (matche le pavé prix). */
.hint-postit > .ico {
  background: var(--ink);
  color: var(--yellow);
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.hint-postit .hint-line {
  white-space: nowrap;
}
.hint-postit .cost {
  font-family: var(--font-mono);
  font-size: 17px;
  font-weight: 700;
  background: var(--ink);
  color: var(--yellow);
  padding: 4px 8px;
  margin-left: 0;
  letter-spacing: 0;
  align-self: stretch;   /* prend la largeur dispo du flex column */
  text-align: center;
}

/* (Le menu déroulant des 3 indices a été remplacé par un clic unique
   sur le post-it qui élimine un macro/groupe faux dans l'hémicycle.
   Les anciennes règles .hint-menu et .hint-option ont été supprimées.) */

/* ── Right col / Panel ───────────────────────────────────────────────────── */
.right-col { display: flex; flex-direction: column; gap: var(--space-4); height: 100%; min-height: 0; }

.game-panel {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: var(--space-4);
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  position: relative;
}
.panel-title {
  font-family: var(--font-display);
  font-size: clamp(13px, 1.4vw, 18px); text-transform: uppercase;
  display: flex; align-items: center; gap: 10px;
  flex-shrink: 0;
  white-space: nowrap;
  overflow: hidden;
}
.num-tag {
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--ink-2); color: var(--paper);
  padding: 2px 8px;
  flex-shrink: 0;
}

/* ── Hémicycle ───────────────────────────────────────────────────────────── */
.hemicycle-wrap {
  flex: none;
  aspect-ratio: 2 / 1;
  position: relative;
  overflow: visible;
}
.hemicycle-wrap svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
  transition: opacity var(--dur-base);
}
.pop-sector {
  transition: transform var(--dur-fast) var(--ease-out);
  transform-box: view-box;
  transform-origin: 50% 90%;
  will-change: transform;
}
/* Hover : seulement sur périphériques avec un vrai hover (souris/trackpad).
   Sur tactile (iOS, Android), :hover reste collé après le tap → quand un
   sub-group apparaît sous le doigt à l'expansion d'un macro, il prend
   tout de suite l'état hover et se présente comme pré-sélectionné. */
@media (hover: hover) {
  .pop-sector:hover  { transform: scale(1.08); }
  .hemicycle-wrap svg.easy .macro:hover { transform: scale(1.08); }
  .hemicycle-wrap svg.animating .pop-sector:hover { transform: none; }
}
.hemicycle-wrap svg.easy .macro {
  transition: transform var(--dur-fast) var(--ease-out);
  transform-box: view-box;
  transform-origin: 50% 90%;
  cursor: pointer;
  will-change: transform;
}
.hemicycle-wrap svg.easy .macro:active { transform: scale(0.94); transition-duration: 70ms; }
.hemicycle-wrap svg.animating .pop-sector { transition: none; }
.pop-sector.armed  { transform: scale(1.12); }
.pop-sector:active { transform: scale(0.94); transition-duration: 70ms; }
.pop-sector.armed-pulse { animation: armedPulse 700ms infinite alternate; }
@keyframes armedPulse {
  from { transform: scale(1.08); }
  to   { transform: scale(1.18); }
}

.sector-reveal-correct,
.sector-reveal-wrong {
  transform-box: view-box;
  transform-origin: 50% 90%;
}
.sector-reveal-correct { animation: sectorCorrect 0.45s var(--ease-pop) forwards; }
.sector-reveal-wrong   { animation: sectorWrong 0.38s ease-out forwards; }
@keyframes sectorCorrect {
  0% { transform: scale(1); }
  50% { transform: scale(1.13); }
  100% { transform: scale(1.04); }
}
@keyframes sectorWrong {
  0%, 100% { transform: scale(1); }
  25% { transform: scale(0.95) rotate(-2deg); }
  60% { transform: scale(0.98) rotate(1deg); }
}

/* ── Élimination (indices) — flash puis grisage ─────────────────── */
.elim-flash {
  transform-box: view-box;
  transform-origin: 50% 90%;
  animation: elimFlash 700ms ease-out forwards;
}
@keyframes elimFlash {
  0%   { filter: brightness(1)   drop-shadow(0 0 0 transparent); transform: scale(1); }
  20%  { filter: brightness(2.2) drop-shadow(0 0 14px var(--red)); transform: scale(1.12); }
  40%  { filter: brightness(0.6); transform: scale(0.95); }
  60%  { filter: brightness(2.2) drop-shadow(0 0 14px var(--red)); transform: scale(1.08); }
  80%  { filter: brightness(0.6); transform: scale(0.96); }
  100% { filter: brightness(1); transform: scale(1); }
}
.eliminated {
  pointer-events: none;
}
.eliminated path {
  filter: grayscale(1);
  transition: opacity 200ms ease-out, fill 200ms ease-out;
}

/* Indication "Touche une famille…" : retirée pour libérer la place sous
   l'hémicycle. L'élément reste dans le DOM (accédé par app.js) mais caché. */
.hover-hint { display: none !important; }

/* ── Reveal screen plein cadre (remplace hémicycle pendant la révélation) ── */
.reveal-screen {
  position: relative;
  width: 100%;
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: var(--space-4);
  padding-bottom: 28px;
  gap: var(--space-3);
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms var(--ease-out);
  display: none;
}
/* Desktop : wrappers transparents, items positionnés par grid-area pour
   préserver l'ordre vertical original (verdict, name, party, sub). */
.reveal-col-left,
.reveal-col-right { display: contents; }
.reveal-screen.visible .reveal-verdict       { grid-area: verdict; }
.reveal-screen.visible .reveal-name          { grid-area: name; }
.reveal-screen.visible .reveal-party         { grid-area: party; }
.reveal-screen.visible .reveal-party-sub     { grid-area: sub; }
.reveal-screen.visible .reveal-groupe-sigle  { grid-area: sigle; }
.reveal-screen.visible {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-areas:
    "verdict"
    "name"
    "party"
    "sub"
    "sigle";
  opacity: 1;
  pointer-events: auto;
}
.game-panel:has(.reveal-screen.visible) .hemicycle-wrap,
.game-panel:has(.reveal-screen.visible) .hover-hint {
  display: none;
}
.reveal-screen.visible {
  opacity: 1;
  pointer-events: auto;
}
.reveal-verdict {
  font-family: var(--font-display);
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  text-transform: uppercase;
  padding: 6px 16px;
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  align-self: flex-start;
  justify-self: start;          /* grid : sinon s'étend jusqu'au bord du cadre */
  width: fit-content;
  transform: rotate(-2deg);
  animation: revealPop 360ms var(--ease-pop) both;
}
.reveal-verdict[data-tone="correct"] { background: var(--green);  color: var(--ink); }
.reveal-verdict[data-tone="wrong"]   { background: var(--red);    color: var(--paper); }
.reveal-verdict[data-tone="almost"]  { background: var(--orange); color: var(--ink); }
@keyframes revealPop {
  0% { opacity: 0; transform: rotate(-2deg) scale(0.4); }
  60% { opacity: 1; transform: rotate(-2deg) scale(1.15); }
  100% { transform: rotate(-2deg) scale(1); }
}
.reveal-name {
  font-family: var(--font-display);
  font-size: clamp(24px, 4vw, 44px);
  line-height: 1.05;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  animation: revealSlide 400ms var(--ease-out) both 100ms;
  word-break: break-word;
}
/* .reveal-party-wrap a été retiré du HTML — animation déplacée sur les items */
.reveal-party,
.reveal-party-sub { animation: revealSlide 400ms var(--ease-out) both 200ms; }
.reveal-party {
  align-self: flex-start;
  justify-self: start;  /* sinon le grid stretch et le pill prend toute la largeur */
  display: inline-block;
  width: fit-content;
  font-family: var(--font-display);
  font-size: clamp(16px, 2.4vw, 26px);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  padding: 8px 14px 10px;
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  transform: rotate(-1deg);
}
.reveal-party-sub {
  font-family: var(--font-mono);
  font-size: 15px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 700;
  margin-top: 6px;
  line-height: 1.1;
  opacity: 0.95;
  color: var(--ink);
}
.reveal-party-sub::before {
  content: "Parti ";
  opacity: 0.5;
  margin-right: 4px;
}
/* Sigle du groupe parlementaire (plus petit, sous le nom du parti). */
.reveal-groupe-sigle {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 700;
  margin-top: 1px;
  line-height: 1.1;
  opacity: 0.6;
  color: var(--ink);
  animation: revealSlide 400ms var(--ease-out) both 200ms;
}
.reveal-groupe-sigle::before {
  content: "Groupe ";
  opacity: 0.7;
  margin-right: 4px;
}
@keyframes revealSlide {
  from { opacity: 0; transform: translateX(-30px); }
  to   { opacity: 1; transform: translateX(0); }
}

.reveal-meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: 4px;
  animation: revealSlide 400ms var(--ease-out) both 350ms;
}
.reveal-meta-chip {
  background: var(--paper-2);
  border: var(--border-thin);
  padding: 8px 10px;
  min-width: 0;
}
.reveal-meta-chip .label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  opacity: 0.6;
}
.reveal-meta-chip .value {
  font-family: var(--font-display);
  font-size: 14px;
  margin-top: 2px;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  line-height: 1.1;
  word-break: break-word;
}

/* Auto-advance progress bar */
.reveal-progress {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: 6px;
  background: var(--ink);
  overflow: hidden;
}
.reveal-progress-fill {
  height: 100%;
  background: var(--green);
  width: 100%;
  transform-origin: left;
  animation: progress var(--auto-dur, 3200ms) linear forwards;
}
/* Couleur de la barre de progression assortie au verdict.
   `data-verdict` est posé sur .reveal-screen lui-même → toujours résolvable
   peu importe la structure interne (col-wrappers en display:contents/flex). */
.reveal-screen[data-verdict="correct"] .reveal-progress-fill { background: var(--green); }
.reveal-screen[data-verdict="almost"]  .reveal-progress-fill { background: var(--orange); }
.reveal-screen[data-verdict="wrong"]   .reveal-progress-fill { background: var(--red); }
@keyframes progress {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0); }
}

.reveal-next { display: none !important; }
  z-index: 2;
  font-family: var(--font-display);
  background: var(--ink);
  color: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  padding: 6px 12px;
  cursor: pointer;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.reveal-next:hover { transform: translate(-2px, -2px); box-shadow: 5px 5px 0 0 var(--ink); }

/* ── Controls panel (stats compact 3 cards + modes) ───────────────────────── */
.controls-panel {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: var(--space-4);
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  justify-content: center;
}
.section-title {
  font-family: var(--font-display);
  font-size: clamp(13px, 1.4vw, 18px);
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.section-title.section-mode { margin-top: var(--space-3); }
.section-tag {
  background: var(--ink-2);
  color: var(--paper);
  padding: 4px 6px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 0;
}
.section-tag .ico { width: 16px; height: 16px; }

.stats-compact { display: flex; gap: var(--space-3); }
.stat-card {
  background: var(--paper-2);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: 10px 12px;
  flex: 1;
  min-width: 0;
  position: relative;
  overflow: visible;
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.stat-card[data-tone="points"]   { background: #4b3cd1; color: var(--paper); }
.stat-card[data-tone="streak"]   { background: var(--orange); }
.stat-card[data-tone="acc"]      { background: var(--green); }
.stat-card[data-tone="lives"]    { background: var(--red); color: var(--paper); }

.stat-head {
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; font-weight: 700;
  opacity: 0.85;
}
.stat-head .ico {
  width: 22px; height: 22px;
  background: var(--ink-2); color: var(--paper);
  border-radius: 50%;
}
.stat-card[data-tone="points"] .stat-head .ico { background: var(--paper); color: #4b3cd1; }
.stat-card[data-tone="lives"]  .stat-head .ico { background: var(--paper); color: var(--red); }
.stat-num {
  font-family: var(--font-display);
  font-size: clamp(22px, 2.6vw, 36px); line-height: 1;
  letter-spacing: -0.02em;
}
.stat-sub {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-weight: 700;
  opacity: 0.95;
}
.stat-sub-acc {
  display: flex;
  align-items: center;
  gap: 10px;
}
.stat-sub-acc .acc-good,
.stat-sub-acc .acc-bad {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 900;
}
.stat-sub-acc .acc-sep {
  opacity: 0.5;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 900;
}
.stat-sub-acc .ico {
  width: 16px;
  height: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0.9;
}
.stat-sub-acc .ico svg {
  width: 16px;
  height: 16px;
}
.stat-sub:not(.stat-sub-acc) span {
  font-family: var(--font-display);
  font-size: 16px;
  letter-spacing: -0.01em;
  font-weight: 900;
  text-transform: none;
  vertical-align: -1px;
}

.modes {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  flex-shrink: 0;
}
.mode-btn {
  font-family: var(--font-display);
  font-size: clamp(10px, 1.1vw, 13px); letter-spacing: 0.02em; text-transform: uppercase;
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  padding: 8px 14px;
  cursor: pointer; color: var(--ink);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap;
  flex: 1;
  justify-content: center;
  min-width: 80px;
}
.mode-btn:hover, .mode-btn:focus-visible { transform: translate(-1px,-1px); box-shadow: 4px 4px 0 0 var(--ink); }
.mode-btn.active {
  box-shadow: var(--sh-md); transform: translate(-2px,-2px);
}
.mode-btn.active[data-mode="normal"]      { background: var(--blue);     color: var(--paper); }
.mode-btn.active[data-mode="easy"]        { background: var(--green);    color: var(--ink); }
.mode-btn.active[data-mode="speed"]       { background: var(--yellow);   color: var(--ink); }
.mode-btn.active[data-mode="survie"]      { background: var(--m-gauche); color: var(--paper); }
.mode-btn.active[data-mode="daily"]       { background: var(--violet);   color: var(--paper); }
.mode-btn.active[data-mode="specialiste"] { background: var(--pink);     color: var(--ink); }
.mode-btn .ico { width: 16px; height: 16px; }

/* Sélecteur d'option de mode (Spécialiste : famille / Survie : vies /
   Speed : durée). Container + pills partagés. */
.specialiste-family-picker,
.specialiste-role-picker,
.mode-option-picker {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 8px;
}
/* Le picker de rôle suit immédiatement le picker de bloc en mode Spécialiste —
   on resserre fortement l'interligne pour qu'ils forment un bloc visuel. */
.specialiste-role-picker { margin-top: 2px; }

/* Spécialiste actif → controls-panel prend sa hauteur intrinsèque (bloc + rôle
   pickers doublent la hauteur normale) et game-panel se contracte pour
   absorber le manque. On masque le titre « Quel est son groupe… » et on
   coupe l'aspect-ratio fixe de l'hémicycle (comportement mobile) pour que le
   SVG suive la hauteur disponible.
   PENDANT le reveal : on masque les sélecteurs bloc/rôle, le controls-panel
   reprend sa taille naturelle (score + modes seulement) et le game-panel
   revient au layout desktop normal → le reveal screen s'affiche tel quel,
   plus de troncature. */
.right-col:has(#specialiste-family-picker:not(.hidden)):not(:has(.reveal-screen.visible)) .controls-panel {
  flex: 0 0 auto;
}
.right-col:has(#specialiste-family-picker:not(.hidden)):not(:has(.reveal-screen.visible)) .game-panel {
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
}
.right-col:has(#specialiste-family-picker:not(.hidden)):not(:has(.reveal-screen.visible)) .game-panel .panel-title {
  display: none;
}
.right-col:has(#specialiste-family-picker:not(.hidden)):not(:has(.reveal-screen.visible)) .hemicycle-wrap {
  flex: 1 1 0;
  min-height: 0;
  aspect-ratio: unset;
  width: 100%;
}
/* Cache les pickers tant que le reveal screen est visible — libère l'espace
   du controls-panel pour qu'il ne pousse plus le game-panel à se rétrécir. */
.right-col:has(.reveal-screen.visible) #specialiste-family-picker,
.right-col:has(.reveal-screen.visible) #specialiste-role-picker {
  display: none;
}
.specialiste-family-picker .picker-label,
.specialiste-role-picker .picker-label,
.mode-option-picker .picker-label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
  margin-right: 2px;
}
.family-pill,
.role-pill,
.pick-pill {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  background: var(--paper);
  border: var(--border-thin);
  padding: 5px 10px;
  cursor: pointer;
  color: var(--ink);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.family-pill:hover, .family-pill:focus-visible,
.role-pill:hover,   .role-pill:focus-visible,
.pick-pill:hover,   .pick-pill:focus-visible {
  transform: translate(-1px, -1px);
  box-shadow: 2px 2px 0 0 var(--ink);
}
/* « Tous » : neutre noir (pas de couleur de bloc associée). */
.family-pill.active[data-family="all"]    { background: var(--ink);     color: var(--paper); border-color: var(--ink); }
.family-pill.active[data-family="gauche"] { background: var(--m-gauche); color: var(--paper); border-color: var(--ink); }
.family-pill.active[data-family="droite"] { background: var(--m-droite); color: var(--paper); border-color: var(--ink); }
.family-pill.active[data-family="facho"]  { background: var(--m-facho);  color: var(--paper); border-color: var(--ink); }
/* Rôle actif : violet sobre, mêmes codes (paper/ink) que les autres pickers. */
.role-pill.active { background: #4b3cd1; color: var(--paper); border-color: var(--ink); }
/* Survie : pill active = rouge (heart-tone). Speed : pill active = jaune. */
#survie-lives-picker  .pick-pill.active { background: var(--red);    color: var(--paper); border-color: var(--ink); }
#speed-duration-picker .pick-pill.active { background: var(--yellow); color: var(--ink);   border-color: var(--ink); }

.mode-desc {
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--ink);
  opacity: 0.9;
  margin: 10px 2px 0;
  line-height: 1.4;
}

/* ── Mobile-only ─────────────────────────────────────────────────────────── */
.stats-trigger            { display: none; }
.mobile-footer-nav        { display: none; }
.stats-backdrop           { display: none; }
.stats-close-btn          { display: none; }
.btn-collection-mobile-only { display: none; }

/* ── Combo system : intro center-screen + post-it pin (Balatro-like) ──────
   Palette procédurale heatmap : jaune → orange → rouge → rose néon → bleu
   flamme → cyan/blanc. Variables locales définies par tier puis consommées
   par .combo-intro et .combo-pin pour rester cohérents. */
.combo-intro, .combo-pin {
  --tier-bg: var(--yellow);
  --tier-fg: var(--ink);
  --tier-glow: rgba(255,210,63,0.55);
  --tier-stroke: var(--ink);
  --tier-accent: var(--orange);
}
[data-tier="1.5"] { --tier-bg: #ffd23f; --tier-fg: #0a0a0a; --tier-glow: rgba(255,210,63,0.55);  --tier-accent: #ffae00; }
[data-tier="2"]   { --tier-bg: #ff6b1a; --tier-fg: #fdf6e3; --tier-glow: rgba(255,107,26,0.65);  --tier-accent: #ffd23f; --tier-stroke: #0a0a0a; }
[data-tier="3"]   { --tier-bg: #ff3b3b; --tier-fg: #fdf6e3; --tier-glow: rgba(255,59,59,0.7);    --tier-accent: #ffd23f; --tier-stroke: #0a0a0a; }
[data-tier="5"]   { --tier-bg: #ff2a6d; --tier-fg: #fdf6e3; --tier-glow: rgba(255,42,109,0.75);  --tier-accent: #ffd23f; --tier-stroke: #0a0a0a; }
[data-tier="7"]   { --tier-bg: #0080ff; --tier-fg: #fdf6e3; --tier-glow: rgba(0,128,255,0.7);   --tier-accent: #ffffff; --tier-stroke: #0a0a0a; }
[data-tier="10"]  { --tier-bg: #00e5ff; --tier-fg: #0a0a0a; --tier-glow: rgba(0,229,255,0.9);   --tier-accent: #ff2a6d; --tier-stroke: #0a0a0a; }

/* ── Intro bumper : pop-in centre-écran, morphing vers la position du pin ─
   --morph-tx / --morph-ty : translation cible (mesurée en JS depuis le pin).
   Sans valeurs JS, l'animation morphe vers le coin haut-droit par défaut. */
.combo-intro {
  --morph-tx: 35vw;
  --morph-ty: -32vh;
  position: fixed;
  top: 38%;
  left: 50%;
  z-index: 600;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.4) rotate(-4deg);
  transition: none;
}
.combo-intro.show { animation: comboIntroMorph 1900ms cubic-bezier(.17,.89,.32,1.25) forwards; }
.combo-intro-card {
  position: relative;
  background: var(--tier-bg);
  color: var(--tier-fg);
  border: var(--border-thick);
  box-shadow: var(--sh-lg), 0 0 60px 8px var(--tier-glow);
  padding: 18px clamp(26px, 5vw, 44px) 22px;
  text-align: center;
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  min-width: clamp(220px, 38vw, 380px);
  overflow: visible;
}
.combo-intro-mult {
  font-size: clamp(56px, 11vw, 110px);
  line-height: 0.92;
  display: flex; align-items: baseline; justify-content: center; gap: 0.05em;
}
.combo-intro-x { font-size: 0.62em; opacity: 0.85; }
.combo-intro-title {
  font-size: clamp(22px, 4vw, 36px);
  margin-top: 4px;
  letter-spacing: 0.12em;
}
.combo-intro-sub {
  margin-top: 8px;
  font-family: var(--font-body);
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0.01em;
  font-size: clamp(13px, 1.5vw, 16px);
  opacity: 1;
}
/* L'intro pop au centre, reste lisible ~700 ms, puis se déplace en
   shrinkant vers la position du pin (translate par variables CSS). À la
   fin (opacity 0 + scale petit), elle "atterrit" sur le pin qui prend
   le relais visuellement. */
@keyframes comboIntroMorph {
  /* Durée totale 1900 ms : pop ≈ 170 ms · settle ≈ 130 ms · HOLD ≈ 1200 ms
     · morph 280 ms · fade 120 ms. Hold étendu (était 728 ms) pour laisser
     le temps de lire le palier de combo (×3, ×5…) avant le morph vers le pin. */
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.3)  rotate(-10deg); }
  9%   { opacity: 1; transform: translate(-50%, -50%) scale(1.15) rotate(-3deg); }
  16%  { opacity: 1; transform: translate(-50%, -50%) scale(1)    rotate(-3deg); }
  79%  { opacity: 1; transform: translate(-50%, -50%) scale(1)    rotate(-3deg); }
  94%  { opacity: 0.85; transform: translate(calc(-50% + var(--morph-tx) * 0.85), calc(-50% + var(--morph-ty) * 0.85)) scale(0.28) rotate(2deg); }
  100% { opacity: 0; transform: translate(calc(-50% + var(--morph-tx)), calc(-50% + var(--morph-ty))) scale(0.18) rotate(6deg); }
}

/* ── Pin post-it : compact, accolé au score (Balatro-like) ────────────────
   État stable = display: inline-flex via .show, transform rotate(6deg)
   scale(1). Les anims (.show-pop / .bump / .leave) jouent sans 'forwards'
   pour revenir au state stable défini par .show — c'était la raison du
   bug "pin invisible au-delà de ×1.5". */
.combo-pin {
  position: absolute;
  top: -14px;
  right: -16px;
  z-index: 4;
  display: none;
  align-items: center;
  gap: 4px;
  padding: 6px 12px 7px;
  background: var(--tier-bg);
  color: var(--tier-fg);
  border: var(--border-thick);
  box-shadow: var(--sh-sm), 0 0 18px 2px var(--tier-glow);
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1;
  letter-spacing: 0.02em;
  transform: rotate(6deg);
  transform-origin: 50% 50%;
  pointer-events: none;
  white-space: nowrap;
  opacity: 1;
}
.combo-pin.show     { display: inline-flex; }
.combo-pin.show-pop { animation: comboPinPop  360ms cubic-bezier(.17,.89,.32,1.4); }
.combo-pin.bump     { animation: comboPinBump 420ms cubic-bezier(.17,.89,.32,1.4); }
.combo-pin.leave {
  display: inline-flex;
  animation: comboPinLeave 420ms cubic-bezier(.55,.05,.7,.2) forwards;
}
/* Idle wobble : 2 keyframes + animation-direction:alternate → un seul
   aller-retour sinusoïdal continu, sans pause aux 4 paliers du
   précédent design. Keyframes en valeurs littérales (pas de
   calc(var(...))) pour permettre l'accélération GPU. will-change
   promeut le pin sur sa propre couche compositor. */
.combo-pin.show:not(.show-pop):not(.bump):not(.leave) {
  will-change: transform;
}
.combo-pin[data-tier="1.5"].show:not(.show-pop):not(.bump):not(.leave) {
  animation: comboPinIdle15 1.30s ease-in-out infinite alternate;
}
.combo-pin[data-tier="2"].show:not(.show-pop):not(.bump):not(.leave) {
  animation: comboPinIdle2 1.10s ease-in-out infinite alternate;
}
.combo-pin[data-tier="3"].show:not(.show-pop):not(.bump):not(.leave) {
  animation: comboPinIdle3 0.90s ease-in-out infinite alternate;
}
.combo-pin[data-tier="5"].show:not(.show-pop):not(.bump):not(.leave) {
  animation: comboPinIdle5 0.70s ease-in-out infinite alternate;
}
.combo-pin[data-tier="7"].show:not(.show-pop):not(.bump):not(.leave) {
  animation: comboPinIdle7 0.50s ease-in-out infinite alternate;
}
.combo-pin[data-tier="10"].show:not(.show-pop):not(.bump):not(.leave) {
  animation: comboPinIdle10 0.35s ease-in-out infinite alternate;
}
@keyframes comboPinIdle15 {
  from { transform: rotate(5.2deg) scale(0.985); }
  to   { transform: rotate(6.8deg) scale(1.015); }
}
@keyframes comboPinIdle2 {
  from { transform: rotate(4.7deg) scale(0.975); }
  to   { transform: rotate(7.3deg) scale(1.025); }
}
@keyframes comboPinIdle3 {
  from { transform: rotate(4deg) scale(0.96); }
  to   { transform: rotate(8deg) scale(1.04); }
}
@keyframes comboPinIdle5 {
  from { transform: rotate(3.2deg) scale(0.945); }
  to   { transform: rotate(8.8deg) scale(1.055); }
}
@keyframes comboPinIdle7 {
  from { transform: rotate(2.2deg) scale(0.925); }
  to   { transform: rotate(9.8deg) scale(1.075); }
}
@keyframes comboPinIdle10 {
  from { transform: rotate(1deg) scale(0.9); }
  to   { transform: rotate(11deg) scale(1.1); }
}
.combo-pin-num {
  /* Pas de stroke ni text-shadow : on garde le chiffre net et lisible. */
}
@keyframes comboPinPop {
  0%   { transform: rotate(-15deg) scale(0);    opacity: 0; }
  60%  { transform: rotate(10deg)  scale(1.25); opacity: 1; }
  100% { transform: rotate(6deg)   scale(1);    opacity: 1; }
}
@keyframes comboPinBump {
  0%   { transform: rotate(6deg)  scale(1); }
  35%  { transform: rotate(-4deg) scale(1.35); }
  70%  { transform: rotate(10deg) scale(0.95); }
  100% { transform: rotate(6deg)  scale(1); }
}
@keyframes comboPinLeave {
  0%   { transform: rotate(6deg)   scale(1)   translate(0,0);       opacity: 1; }
  30%  { transform: rotate(-18deg) scale(1.1) translate(8px,-6px);  opacity: 1; }
  100% { transform: rotate(40deg)  scale(0.6) translate(60px, 80px); opacity: 0; }
}

/* Mobile : pin à GAUCHE du chiffre. Wrap `.trigger-num-wrap` sert de
   contexte de positionnement. Padding-left appliqué quand le pin est
   `.show` → le chiffre est repoussé à droite pour libérer la place,
   et "point" reste lisible à sa position naturelle. */
.trigger-num-wrap {
  position: relative;
  display: inline-block;
  transition: padding-left 0.20s ease;
}
.trigger-num-wrap:has(.combo-pin.show) {
  padding-left: 42px;
}
/* Tier ×1.5 = 4 caractères (×1.5) au lieu de 2 (×2/×3/etc.) → pin plus large.
   Compense le padding-left pour éviter le chevauchement sur le chiffre des points. */
.trigger-num-wrap:has(.combo-pin[data-tier="1.5"].show) {
  padding-left: 56px;
}
.stats-trigger .combo-pin {
  top: -8px;
  left: -6px;
  right: auto;
  font-size: 16px;
  padding: 4px 8px 5px;
}

/* ── Flammes (≥ ×5) — gooey filter sur le post-it lui-même ─────────────
   Les `.cflame-p` sont enfants directs du post-it / card. Le filtre
   SVG (feMerge : outline + goo + SourceGraphic) trace UNE seule
   bordure continue autour de la silhouette gooey (cadre + flammes).
   La bordure CSS est mise transparente pour ne pas dupliquer le tracé.
   Trade-off accepté : les coins du cadre sont légèrement arrondis
   (effet gooey), mais le stroke reste cohérent avec celui de la flamme.
   drop-shadow enchaîné après pour le hard shadow + glow. */
.combo-pin[data-tier="5"],
.combo-pin[data-tier="7"],
.combo-pin[data-tier="10"] {
  filter: url(#cflame-fire-pin)
          drop-shadow(0 0 3px var(--tier-glow));
  border-color: transparent;
  box-shadow: none;
}
.combo-intro[data-tier="5"]  .combo-intro-card,
.combo-intro[data-tier="7"]  .combo-intro-card,
.combo-intro[data-tier="10"] .combo-intro-card {
  filter: url(#cflame-fire-intro)
          drop-shadow(0 0 10px var(--tier-glow));
  border-color: transparent;
  box-shadow: none;
}

/* Pastilles en gouttes verticales (border-radius asymétrique pour
   amorcer la forme de langue de flamme). Cachées par défaut, visibles
   uniquement à partir du tier ×5. `bottom: calc(100% - 8px)` → les
   particules démarrent 8 px à l'intérieur du post-it pour que la
   flamme émerge depuis l'intérieur du cadre, sans gap visible. */
.cflame-p {
  position: absolute;
  bottom: calc(100% - 8px);
  width: 11px;
  height: 15px;
  margin-left: -5.5px;
  background: var(--tier-bg);
  border-radius: 50% 50% 45% 45% / 65% 65% 35% 35%;
  pointer-events: none;
  animation: cflameRise var(--dur, 0.55s) var(--delay, 0s) linear infinite;
  will-change: transform;
  display: none;
}
.combo-pin[data-tier="5"]   .cflame-p,
.combo-pin[data-tier="7"]   .cflame-p,
.combo-pin[data-tier="10"]  .cflame-p,
.combo-intro[data-tier="5"]  .cflame-p,
.combo-intro[data-tier="7"]  .cflame-p,
.combo-intro[data-tier="10"] .cflame-p {
  display: block;
}
.combo-intro-card .cflame-p {
  width: 22px;
  height: 30px;
  margin-left: -11px;
  bottom: calc(100% - 16px);
}

@keyframes cflameRise {
  0%   { transform: translate(0, 0) scale(1.15, 0.85); opacity: 1; }
  45%  { transform: translate(calc(var(--tx, 0px) * 0.35), calc(var(--ty, -30px) * 0.45)) scale(0.95, 1.2); opacity: 1; }
  100% { transform: translate(var(--tx, 0px), var(--ty, -30px)) scale(0.4, 1.5); opacity: 0; }
}

/* ── Bumper « Combo perdu » ─────────────────────────────────────────────── */
.combo-lost {
  position: fixed;
  top: 38%;
  left: 50%;
  z-index: 590;
  pointer-events: none;
  display: none;
  align-items: center;
  gap: 10px;
  padding: 10px 22px 12px;
  background: var(--ink);
  color: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  font-family: var(--font-display);
  font-size: clamp(20px, 3.5vw, 30px);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  transform: translate(-50%, -50%) rotate(-2deg);
  opacity: 0;
}
.combo-lost.show {
  display: inline-flex;
  animation: comboLostBump 1100ms cubic-bezier(.17,.89,.32,1.25) forwards;
}
.combo-lost-x {
  color: var(--red);
  font-size: 1.2em;
  -webkit-text-stroke: 1px var(--paper);
}
@keyframes comboLostBump {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.5) rotate(-8deg); }
  15%  { opacity: 1; transform: translate(-50%, -50%) scale(1.12) rotate(-2deg); }
  25%  { transform: translate(-50%, -50%) scale(1) rotate(-2deg); }
  75%  { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(-2deg); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(0.9) rotate(2deg); }
}

/* ── Achievement toast ───────────────────────────────────────────────────── */
.ach-toast-zone {
  position: fixed;
  bottom: 20px;
  right: 20px;
  /* z-index 700 > settings-backdrop (600) pour que les toasts (sync, succès,
     etc.) restent visibles AU-DESSUS du menu Paramètres. Sinon le toast
     "score synchronisé" était caché derrière le menu sur mobile. */
  z-index: 700;
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-2);
  pointer-events: none;
}
/* Le reveal a priorité : on cache les toasts pendant qu'il est visible
   (sinon, en cas de cascade de succès, ils chevauchent le reveal).
   On masque la zone ET on met les anims en pause sur les toasts pré-existants,
   pour que le swipe-in soit bien visible au moment où le reveal disparaît. */
body:has(.reveal-screen.visible) .ach-toast-zone {
  visibility: hidden;
}
body:has(.reveal-screen.visible) .ach-toast {
  animation-play-state: paused !important;
}
.ach-toast {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: var(--space-3);
  display: flex;
  gap: var(--space-3);
  align-items: center;
  min-width: 280px;
  max-width: 360px;
  cursor: pointer;
  pointer-events: auto;   /* override parent .ach-toast-zone pointer-events:none */
  /* Desktop : swipe IN depuis le BAS (la zone est en bottom-right).
     Mobile : override dans la media query plus bas (swipe depuis le haut).
     Visible ~4.5s — assez long pour lire le nom + desc, sans rester
     plombé à l'écran. Stagger 320 ms entre toasts en cascade. */
  animation: toastInUp 560ms cubic-bezier(.34, 1.56, .64, 1) backwards,
             toastOutDown 420ms ease 4.5s forwards;
}
/* Sur mobile, les toasts apparaissent en HAUT (sous le titre) avec swipe-in
   depuis le haut. La media query DOIT être placée APRÈS la règle de base
   ci-dessus, sinon la cascade fait gagner la règle desktop (même spécificité). */
@media (max-width: 860px) {
  .ach-toast-zone {
    /* Collés en haut d'écran (env(safe-area-inset-top) pour iOS notch).
       On accepte de masquer le titre du jeu — un succès, c'est plus important. */
    top: calc(env(safe-area-inset-top, 0px) + 8px);
    bottom: auto;
    right: 12px;
    left: 12px;
    align-items: stretch;
    flex-direction: column;
  }
  .ach-toast {
    min-width: 0;
    max-width: 100%;
    animation: toastInDown 560ms cubic-bezier(.34, 1.56, .64, 1) backwards,
               toastOutUp   420ms ease 4.5s forwards;
  }
}
/* Click → dismiss immédiat (swipe-out rapide vers la droite). */
.ach-toast.dismiss {
  animation: toastDismiss 240ms cubic-bezier(.55, 0, .8, .2) forwards !important;
}
.ach-toast .ico-big {
  width: 44px; height: 44px;
  background: var(--ink); color: var(--paper);
  display: grid; place-items: center;
  flex-shrink: 0;
  border: var(--border-thick);
}
.ach-toast[data-tier="silver"] .ico-big   { background: #c0c0c0; color: var(--ink); }
.ach-toast[data-tier="gold"] .ico-big     { background: var(--yellow); color: var(--ink); }
.ach-toast[data-tier="platinum"] .ico-big { background: #e5e4e2; color: var(--ink); }
.ach-toast .ach-label {
  font-family: var(--font-mono);
  font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase;
  opacity: 0.6;
}
.ach-toast .ach-name {
  font-family: var(--font-display);
  font-size: 15px; text-transform: uppercase;
}
.ach-toast .ach-desc {
  font-family: var(--font-body);
  font-size: 12px;
  margin-top: 2px;
}
/* Desktop : arrive depuis le BAS (la zone est en bottom-right). */
@keyframes toastInUp {
  from { transform: translateY(140px) rotate(2deg);  opacity: 0; }
  60%  { opacity: 1; }
  to   { transform: translateY(0)     rotate(0);     opacity: 1; }
}
@keyframes toastOutDown {
  to { transform: translateY(140px) rotate(-2deg); opacity: 0; }
}
/* Mobile : arrive depuis le HAUT (la zone est en top). */
@keyframes toastInDown {
  from { transform: translateY(-140px) rotate(-2deg); opacity: 0; }
  60%  { opacity: 1; }
  to   { transform: translateY(0)      rotate(0);     opacity: 1; }
}
@keyframes toastOutUp {
  to { transform: translateY(-140px) rotate(2deg); opacity: 0; }
}
/* Click → dismiss latéral (rapide, pour différencier de l'auto-out). */
@keyframes toastDismiss {
  to { transform: translateX(460px) rotate(6deg); opacity: 0; }
}

/* ── Score bump ──────────────────────────────────────────────────────────── */
.score-bump {
  position: absolute;
  top: -10px;
  left: 50%;
  font-family: var(--font-display);
  font-size: 28px;
  line-height: 1;
  padding: 2px 11px 6px;
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-sm);
  pointer-events: none;
  z-index: 50;
  white-space: nowrap;
  animation: scoreBump 1.15s ease-out both;
  will-change: transform, opacity;
}
@keyframes scoreBump {
  0%   { transform: translateX(-50%) translateY(0)     rotate(var(--bump-rot, -6deg)) scale(0);    opacity: 0; }
  20%  { transform: translateX(-50%) translateY(0)     rotate(var(--bump-rot, -6deg)) scale(1.2);  opacity: 1; }
  40%  { transform: translateX(-50%) translateY(0)     rotate(var(--bump-rot, -6deg)) scale(1);    opacity: 1; }
  70%  { transform: translateX(-50%) translateY(-20px) rotate(var(--bump-rot, -6deg)) scale(1);    opacity: 1; }
  100% { transform: translateX(-50%) translateY(-58px) rotate(var(--bump-rot, -6deg)) scale(0.8);  opacity: 0; }
}

/* ── Speed timer (post-it jaune, sablier, millisecondes) ──────────────── */
/* Positionné dans .hemicycle-wrap, donc ne chevauche jamais le titre du panneau */
/* Bloc et contenu tournent ensemble : l'icône et les chiffres suivent
   l'inclinaison du post-it jaune, conservant un alignement cohérent. */
.speed-timer {
  position: absolute;
  top: 4px;
  right: 4px;
  padding: 7px 12px;
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--ink);
  line-height: 1;
  letter-spacing: -0.02em;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  z-index: 30;
  white-space: nowrap;
  transform: rotate(-4deg);
  transform-origin: center;
}
.speed-timer::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--yellow);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  z-index: -1;
  transition: background-color 200ms;
}
.speed-timer .ico,
.speed-timer .speed-num,
.speed-timer .speed-unit {
  position: relative; /* au-dessus du ::before */
}
.speed-timer .ico {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.speed-timer .ico > svg {
  width: 20px !important;
  height: 20px !important;
  display: block;
}
.speed-timer .speed-num {
  font-variant-numeric: tabular-nums;
  min-width: 58px;
  text-align: right;
  flex: 0 0 auto;
}
.speed-timer .speed-unit {
  font-size: 0.55em;
  opacity: 0.6;
  margin-left: -2px;
  flex: 0 0 auto;
}
.speed-timer.warning { color: var(--paper); }
.speed-timer.warning::before {
  background: var(--red);
  animation: timerPulse 380ms infinite alternate;
}
@keyframes timerPulse {
  from { transform: scale(1); }
  to   { transform: scale(1.08); }
}

/* ── Confirm modal (changement de mode) ────────────────────────────── */
.confirm-backdrop {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(10,10,10,0.6);
  z-index: 250;
  padding: 20px;
}
.confirm-backdrop.show { display: flex; }
.confirm-card {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-lg);
  padding: var(--space-5) var(--space-5) var(--space-4);
  max-width: 440px;
  width: 100%;
  text-align: center;
  animation: confirmIn 0.32s var(--ease-pop) both;
}
@keyframes confirmIn {
  from { transform: scale(0.7) rotate(-2deg); opacity: 0; }
  to   { transform: scale(1) rotate(0); opacity: 1; }
}
.confirm-card h2 {
  font-family: var(--font-display);
  font-size: clamp(24px, 4vw, 32px);
  text-transform: uppercase;
  letter-spacing: -0.02em;
  margin-bottom: var(--space-3);
}
.confirm-card p {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.45;
  margin-bottom: var(--space-4);
  opacity: 0.85;
}
.confirm-buttons {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
}
.confirm-buttons button {
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 12px 22px;
  border: var(--border-thick);
  cursor: pointer;
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--sh-sm);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.confirm-buttons button:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--sh-md);
}
.confirm-buttons .btn-primary {
  background: var(--ink);
  color: var(--paper);
}

/* ── Score bump anchors sur Série et Précision ──────────────────────── */
.stat-card { position: relative; }

/* ── Daily / Lives post-it ───────────────────────────────────────────
   Même structure et style (compteur tilté sur la photo). Daily = jaune
   à gauche, Vies (survie) = rouge à droite (symétrique). */
.daily-postit,
.lives-postit {
  position: absolute;
  top: 28px;
  background: var(--yellow);
  color: var(--ink);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: 9px 13px 10px;
  z-index: 5;
  font-family: var(--font-display);
  text-align: center;
  min-width: 86px;
  pointer-events: none;
  transition: transform 280ms var(--ease-pop);
}
.daily-postit {
  left: -24px;
  transform: rotate(-7deg);
}
.lives-postit {
  left: -24px;
  transform: rotate(-7deg);
  background: var(--red);
  color: var(--paper);
}
.daily-postit.bump { transform: rotate(-7deg) scale(1.18); }
.lives-postit.bump { transform: rotate(-7deg) scale(1.18); }
.lives-postit-label,
.lives-postit-num,
.lives-postit-sub { display: block; }
.daily-postit-label,
.lives-postit-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.7;
  margin-bottom: 4px;
}
.daily-postit-num,
.lives-postit-num {
  font-size: 26px;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.daily-postit-num .daily-postit-sep,
.lives-postit-num .lives-postit-sep {
  opacity: 0.5;
  margin: 0 1px;
}
.daily-postit-sub,
.lives-postit-sub {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-top: 4px;
  opacity: 0.7;
}
@media (max-width: 760px) {
  .daily-postit, .lives-postit {
    top: 10px;
    padding: 7px 10px 8px;
    min-width: 72px;
  }
  .daily-postit { left: 10px; transform: rotate(-5deg); }
  .lives-postit { left: 10px; transform: rotate(-5deg); }
  .daily-postit.bump { transform: rotate(-5deg) scale(1.15); }
  .lives-postit.bump { transform: rotate(-5deg) scale(1.15); }
  .daily-postit-num, .lives-postit-num { font-size: 20px; }
}

/* ── Collection fly-in (carte shiny ou holographique : pop-in + shrink + fly) ──
   Phase 1 : pop-in BIG sur la carte avec label « +1 SHINY » / « +1 HOLO ».
   Phase 2 : shrink via .shrunk + envol vers le bouton Collection.
   La transition d'échelle entre les 2 phases est portée par l'animation JS
   (Web Animations API) — ici on règle juste l'apparence statique.
   `width` est posée explicitement en JS (mesurée à la création) et transite
   en CSS quand `.shrunk` est ajoutée → la box rétrécit smooth (avant : snap
   instantané dû au display:none des labels). */
.collection-fly {
  position: fixed;
  z-index: 600;
  pointer-events: none;
  background: var(--green);
  color: var(--ink);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: 10px 16px;
  font-family: var(--font-display);
  font-size: 22px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transform: translate(-50%, -50%) scale(0);
  white-space: nowrap;
  overflow: hidden;
  box-sizing: border-box;
  transition: width 280ms cubic-bezier(.55, 0, .35, 1),
              padding 280ms cubic-bezier(.55, 0, .35, 1),
              font-size 280ms cubic-bezier(.55, 0, .35, 1);
}
.collection-fly .ico { width: 18px; height: 18px; }

/* ── Loading ─────────────────────────────────────────────────────────────── */
#loading {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 80px 20px; gap: 18px;
}
.spinner {
  width: 44px; height: 44px;
  border: 4px solid var(--paper-2);
  border-top-color: var(--ink);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
#loading p {
  font-family: var(--font-mono);
  font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase;
}

#error { display: flex; flex-direction: column; align-items: center; padding: 60px 20px; }
.error-box {
  background: var(--paper-2);
  border: var(--border-thick); box-shadow: var(--sh-lg);
  padding: 36px 44px; text-align: center;
}
.error-icon { font-size: 2.5rem; margin-bottom: 12px; }
#error-msg { font-family: var(--font-body); font-size: 1rem; margin-bottom: 20px; }
.btn-retry {
  font-family: var(--font-display);
  font-size: 15px; text-transform: uppercase;
  background: var(--ink-2); color: var(--paper);
  border: var(--border-thick); box-shadow: var(--sh-sm);
  padding: 12px 28px; cursor: pointer;
}

/* ── Game over modal (mode Survie) ───────────────────────────────────────── */
.gameover-backdrop {
  position: fixed; inset: 0;
  background: rgba(10,10,10,0.7);
  z-index: 700;
  display: none;
}
.gameover-backdrop.show { display: grid; place-items: center; }
.gameover-card {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-lg);
  padding: var(--space-6);
  max-width: 480px;
  width: calc(100% - 32px);
  text-align: center;
  animation: revealPop 400ms var(--ease-pop) both;
}
.gameover-card h2 {
  font-family: var(--font-display);
  font-size: 36px;
  text-transform: uppercase;
  margin-bottom: var(--space-3);
  color: var(--red);
  -webkit-text-stroke: 1px var(--ink);
}
.gameover-stats { display: flex; gap: var(--space-3); justify-content: center; margin: var(--space-4) 0; }
.gameover-stat { background: var(--paper-2); border: var(--border-thick); padding: var(--space-3); min-width: 100px; }
.gameover-stat .label { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.7; }
.gameover-stat .value { font-family: var(--font-display); font-size: 28px; }
.gameover-replay {
  font-family: var(--font-display);
  font-size: 15px;
  background: var(--ink); color: var(--paper);
  border: var(--border-thick); box-shadow: var(--sh-sm);
  padding: 12px 28px; cursor: pointer;
  text-transform: uppercase;
}

.hidden { display: none !important; }

/* ── Responsive ──────────────────────────────────────────────────────────── */
@media (max-width: 860px) {
  /* Padding latéral symétrique (16px chaque côté) — l'asymétrie 20px/16px
     précédente faisait déborder de 4px sur iPhone 16. */
  .app {
    padding: 12px 16px 16px 16px;
    overflow-y: visible;
    overflow-x: hidden;
    overflow-x: clip;
    max-width: 100%;
    width: 100%;
  }
  /* Pas d'overflow:hidden sur ces containers — sinon les box-shadow des
     enfants au bord droit/bas sont rognées. MAIS overflow-x: clip sur .main
     pour bloquer le débord horizontal causé par le swipe-out de .deputy-card
     (transform translate(±160vw)) qui sinon étend la zone de scroll sur
     iOS Safari. `clip` ne crée pas de scroll container, donc les shadows
     verticales restent libres. */
  .main { overflow: visible; overflow-x: clip; }
  /* gap 12px en mobile pour matcher .main gap (espace carte→hémicycle).
     Tous les espaces verticaux sont ainsi alignés sur 12px. */
  .right-col { overflow: visible; gap: 12px; }
  .site-title { font-size: clamp(18px, 7.5vw, 44px); }
  /* Sur mobile, le bandeau coloré du titre s'étend jusqu'au bord droit
     (au lieu de prendre uniquement la largeur du texte). margin-right
     négatif pour qu'il dépasse 4px du padding .app (= 12px du viewport),
     visuellement plus collé au bord droit que les autres éléments. */
  .site-title .accent {
    flex: 1 1 auto;
    margin-right: -4px;
  }
  .header .btn-collection, .header .btn-nav { display: none; }
  .btn-collection-mobile-only { display: flex; width: 100%; justify-content: center; }

  /* Bouton indice mobile : à DROITE de la photo, en superposition légère
     sur le coin haut-droit. Anciennement right: -4px (déborderait), mais
     depuis que .main n'a plus de padding-right asymétrique, le bouton se
     ferait clipper par overflow-x: clip. right: 4px le garde dans le visible. */
  .hint-postit-wrap {
    top: -8px;
    right: 4px;
    left: auto;
    /* Hauteur mobile plus compacte (font/icon/padding plus petits). */
    min-height: 86px;
    max-height: 86px;
  }
  .hint-postit {
    font-size: 10px;
    gap: 2px;
    /* Min-width pour éviter que le bouton se rétrécisse à un état intermédiaire
       (transition max-width interrompue ou flex-shrink du parent). */
    min-width: 84px;
    flex-shrink: 0;
  }
  .hint-postit.hint-out {
    /* Sauf en hint-out, où on veut que ça rétrécisse à 0. */
    min-width: 0;
  }
  /* Cost ("-1 PTS") + lignes texte plus petits sur mobile pour soulager
     en hauteur (le bouton se retrouvait trop étroit en haut/bas). */
  .hint-postit .cost {
    font-size: 13px;
    margin-top: 2px;
  }
  .hint-postit > .ico {
    width: 20px;
    height: 20px;
  }

  /* Footer navigation mobile : maintenant en is-fixed sur toutes les
     pages (cf HTML). Pas de margin/padding spécifique : les styles
     .is-fixed ci-dessous gèrent tout. */
  .mobile-footer-nav {
    display: flex;
    gap: clamp(3px, 1vw, 6px);
    align-items: center;
    /* Pas de flex-wrap : tout reste sur une ligne. Les boutons texte se
       partagent l'espace via flex:1 1 auto (grow proportionnel au contenu),
       le texte rétrécit via clamp() si nécessaire. */
  }
  .mobile-nav-btn {
    /* Sizing par contenu (flex-basis: auto), shrink si besoin pour rester
       sur une ligne, grow proportionnellement au contenu pour combler la
       largeur disponible — chaque bouton s'étire en fonction de la longueur
       de son label (« Classements » > « Succès » > « Jeu »). */
    flex: 1 1 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: clamp(2px, 0.8vw, 7px);
    font-family: var(--font-display);
    /* Le texte rétrécit en viewport étroit (de 12px à 8px sur iPhone mini).
       Plage 8-12px pour permettre la compression jusqu'à ~360px sans
       débordement. */
    font-size: clamp(8px, 2.4vw, 12px);
    letter-spacing: 0.02em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--ink);
    background: var(--paper);
    border: var(--border-thick);
    box-shadow: var(--sh-sm);
    padding: 10px clamp(3px, 1.2vw, 14px);
    cursor: pointer;
    white-space: nowrap;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Très petits écrans (≤430px = iPhone 16 Pro et plus petit) : on garde
     icônes + texte (plus lisible) mais on compresse le bouton « Succès »
     en icône-seule pour libérer la largeur. */
  @media (max-width: 430px) {
    .mobile-footer-nav {
      width: 100%;
      max-width: 100%;
      overflow-x: clip;
      gap: 4px;
      align-items: stretch;
    }
    .mobile-nav-btn {
      /* flex 1 1 auto : chaque bouton fait sa taille de contenu + se
         partage l'espace restant équitablement. 'JEU' (court) reste petit,
         'CLASSEMENTS' (long) prend plus de place — aspect naturel. */
      flex: 1 1 auto;
      min-width: 0;
      padding: 10px 6px;
      font-size: clamp(10px, 2.7vw, 13px);
      gap: 4px;
      overflow: hidden;
      text-overflow: ellipsis;
      align-self: stretch;
    }
    .mobile-nav-btn .ico { width: 17px; height: 17px; }
  }
  .mobile-nav-btn:active {
    transform: translate(2px, 2px);
    box-shadow: 1px 1px 0 0 var(--ink);
  }
  .mobile-nav-btn .ico { flex-shrink: 0; }
  /* Bouton "icône seule" : ne prend pas de place horizontale superflue,
     laisse les boutons texte profiter du flex:1 restant. */
  .mobile-nav-btn-icon-only {
    flex: 0 0 auto;
    width: 44px;
    padding: 10px 0;
    justify-content: center;
  }
  /* Sur ≤430px, le bouton 'Succès' (href achievements.html) est compressé
     en icône-seule pour libérer la largeur et éviter le débord. Le texte
     'Succès' est masqué via font-size: 0 (le seul texte direct dans le
     <a>), l'icône garde sa taille via reset. */
  @media (max-width: 430px) {
    .mobile-nav-btn-icon-only { width: 36px; padding: 10px 0; }
    .mobile-nav-btn[href*="achievements.html"] {
      flex: 0 0 36px;
      width: 36px;
      padding: 10px 0;
      font-size: 0;
      gap: 0;
    }
    .mobile-nav-btn[href*="achievements.html"] .ico {
      width: 16px;
      height: 16px;
      font-size: initial;
    }
  }

  /* Variante : footer collé au bas de l'écran (pages Collection et Succès) */
  .mobile-footer-nav.is-fixed {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 50;
    background: var(--paper);
    border-top: var(--border-thick);
    padding: 10px 10px calc(14px + env(safe-area-inset-bottom, 0px)) 10px;
    margin: 0;
    max-width: 100%;
    overflow-x: clip;
    box-sizing: border-box;
  }
  body:has(.mobile-footer-nav.is-fixed) .app {
    /* Padding-bottom = hauteur de la nav + air. 84px = 78 + 6px d'air
       supplémentaire entre le bandeau Points et la nav fixe. */
    padding-bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  }
  /* padding-right léger (6px) pour laisser respirer les box-shadow des
     cadres internes (game-panel, hemicycle-wrap, controls-panel) qui sont
     tirées en bas-droit.
     Row 1 (cadre photo) réduite de 12px au total pour libérer 6px à
     l'hémicycle + 6px à l'espace bandeau→nav. */
  .main { grid-template-columns: 1fr; grid-template-rows: clamp(158px, calc(100dvh - 412px), calc(46vh - 12px)) 1fr; gap: 12px; padding-right: 6px; }
  /* Reveal screen sur mobile : pas de cadre interne (le .game-panel parent
     a déjà son border + box-shadow), pas de fond, contenu collé en haut
     du cadre (align-content: start + padding-top minimal). */
  .reveal-screen {
    border: none;
    box-shadow: none;
    background: transparent;
    padding: 0 var(--space-3) var(--space-3) var(--space-3);
  }
  .reveal-screen.visible {
    align-content: start;
  }
  .shadow-photo-wrap, .photo-wrap { flex: 1; min-height: 0; width: auto; aspect-ratio: 3/4; align-self: center; max-width: 100%; }
  /* Carte photo : shadow alignée sur celle du game-panel (--sh-md) pour cohérence
     visuelle et économiser 4px en bas/à droite. La var --card-sh-base est aussi
     redéfinie : shinyGlow l'utilise dans ses keyframes → la carte shiny mobile
     reprend la MÊME ombre réduite que la carte normale (sans ça, la shiny
     dépassait le cadre hémicycle). */
  .deputy-card,
  .deputy-card-shadow { box-shadow: var(--sh-md); }
  .deputy-card { --card-sh-base: var(--sh-md); }
  /* Game-panel : padding asymétrique pour pousser le contenu (hémicycle) un
     peu plus bas dans le cadre + côtés très resserrés pour donner ~12px de
     plus à la largeur du SVG (= ~6px de plus en hauteur via le ratio 2:1). */
  .game-panel { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 16px 4px 4px 4px; }
  /* Titre du panneau masqué en mobile : "Quel est son groupe parlementaire ?"
     superflu une fois le jeu compris ; libère l'espace pour la photo. */
  .panel-title { display: none; }
  .hemicycle-wrap { flex: 1; min-height: 0; aspect-ratio: unset; width: 100%; }
  /* Sur mobile, le reveal prend la place de l'hémicycle. Layout grille :
       ┌───────────┬─────────────────┐
       │ BRAVO !   │  Prénom         │
       │           │  Nom            │
       │ PARTI     │  Groupe parl…   │
       ├───────────┴─────────────────┤
       │ ▓▓ progress ▓▓▓▓▓▓▓▓▓▓▓ │
       └─────────────────────────────┘
     • Col 1 : verdict (row 1) + pill du parti (row 2)
     • Col 2 : prénom + nom (sur 2 lignes via \n + white-space:pre-line)
                puis groupe parlementaire en dessous
     • Le wrapper .reveal-party-wrap est en `display: contents` pour que
       ses enfants se placent directement dans la grille. */
  .reveal-screen.visible {
    flex: 1 1 0;
    min-height: 0;
    /* Padding-top : assez d'air pour respirer mais pas centré. */
    padding: 10px 14px 14px;
    /* Sur mobile : 2 colonnes (col-left | col-right), 1 row alignée en
       haut (pas centrée — on remonte le contenu près du haut du cadre). */
    grid-template-columns: auto 1fr;
    grid-template-rows: 1fr;
    grid-template-areas: "left right";
    column-gap: 22px;
    align-items: start;
  }
  /* Mobile : les wrappers reprennent leur rôle de container flex. */
  .reveal-col-left,
  .reveal-col-right {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .reveal-col-left  { grid-area: left; }
  .reveal-col-right { grid-area: right; }
  /* Désactive les grid-area que le desktop applique aux items individuels :
     en mobile, les items ne sont plus enfants directs du grid. */
  .reveal-screen.visible .reveal-verdict,
  .reveal-screen.visible .reveal-name,
  .reveal-screen.visible .reveal-party,
  .reveal-screen.visible .reveal-party-sub,
  .reveal-screen.visible .reveal-groupe-sigle { grid-area: auto; }
  .reveal-verdict   {
    font-size: clamp(20px, 6vw, 28px);
    padding: 4px 12px;
  }
  .reveal-name      {
    /* Le textContent contient un \n entre prénom et nom — affichage sur
       deux lignes uniquement en mobile. */
    white-space: pre-line;
    font-size: clamp(17px, 5.5vw, 26px);
    line-height: 1.1;
  }
  .reveal-party     {
    font-size: clamp(13px, 3.6vw, 18px);
    padding: 5px 10px 7px;
  }
  .reveal-party-sub {
    font-size: 10px;
    margin-top: 0;
    letter-spacing: 0.06em;
  }
  /* .reveal-progress n'est plus dans le grid : il est en position:absolute
     pour faire partie de la bordure inférieure (cf. règle plus haut). */
  /* Panneau stats : bottom-sheet */
  .controls-panel {
    position: fixed; bottom: calc(-100% - 30px); left: 0; right: 0;
    z-index: 200; justify-content: flex-start;
    border-top: var(--border-thick); border-left: var(--border-thick); border-right: var(--border-thick);
    box-shadow: -6px -6px 0 0 var(--ink);
    max-height: 82dvh; overflow-y: auto;
    transition: bottom 320ms var(--ease-pop);
  }
  .controls-panel.stats-open { bottom: 0; }
  .stats-close-btn {
    display: flex; align-self: flex-end; margin-bottom: var(--space-2);
    font-family: var(--font-display); font-size: 16px;
    background: var(--paper-2); border: var(--border-thick); box-shadow: var(--sh-sm);
    padding: 1px 10px; cursor: pointer; color: var(--ink);
  }
  .stats-backdrop {
    display: block; position: fixed; inset: 0;
    background: rgba(10,10,10,0.5); z-index: 199;
    visibility: hidden; opacity: 0; transition: opacity 0.2s;
  }
  .stats-backdrop.visible { visibility: visible; opacity: 1; }
  .stats-trigger {
    display: flex; align-items: center; gap: 10px;
    background: #4b3cd1; color: var(--paper);
    border: var(--border-thick); box-shadow: var(--sh-md);
    padding: 10px 14px; cursor: pointer; flex-shrink: 0; width: 100%;
    position: relative;
  }
  .stats-trigger:active { transform: translate(2px,2px); box-shadow: 1px 1px 0 0 var(--ink); }
  /* Bloc points : nombre proéminent (×2 par rapport à avant) suivi de "points" en label */
  .trigger-pts { display: flex; align-items: baseline; gap: 8px; position: relative; }
  .trigger-num   { font-family: var(--font-display); font-size: 34px; line-height: 1; }
  .trigger-label { font-family: var(--font-display); font-size: 18px; line-height: 1; text-transform: uppercase; letter-spacing: 0.02em; }
  /* Hint à droite : "Stats et modes de jeu" + chevron up */
  .trigger-hint {
    margin-left: auto;
    display: inline-flex; align-items: center; gap: 6px;
    font-family: var(--font-mono); font-size: 11px; font-weight: 700;
    letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.95;
    text-align: right;
  }
  .trigger-hint .ico { color: var(--paper); }

  /* Stat-cards (visibles dans le bottom-sheet) : compactées en mobile pour
     ne pas saturer le sheet ouvert et laisser respirer le mode-de-jeu. */
  .stats-compact { gap: var(--space-2); }
  .stat-card     { padding: 7px 9px; gap: 2px; }
  .stat-head     { font-size: 9px; letter-spacing: 0.12em; }
  .stat-head .ico { width: 18px; height: 18px; }
  .stat-head .ico svg { width: 14px !important; height: 14px !important; }
  .stat-num      { font-size: 22px !important; }
  .stat-sub      { font-size: 10px; letter-spacing: 0.02em; }
  .stat-sub-acc .acc-good,
  .stat-sub-acc .acc-bad,
  .stat-sub-acc .acc-sep { font-size: 13px; }
  .stat-sub-acc .ico,
  .stat-sub-acc .ico svg { width: 13px !important; height: 13px !important; }
  .stat-sub:not(.stat-sub-acc) span { font-size: 13px; }

  /* Mode buttons mobile : grille 3×2 héritée du desktop, juste un gap réduit. */
  .modes         { gap: var(--space-1); }
  .mode-btn      { padding: 6px 8px; font-size: 10px !important; gap: 5px; min-width: 0; flex: none; }
  .mode-btn .ico { width: 13px; height: 13px; }
  .mode-btn .ico svg { width: 13px !important; height: 13px !important; }
  .mode-desc     { font-size: 12.5px; line-height: 1.35; }
  /* Sélecteur de famille : pills plus compactes en mobile */
  .specialiste-family-picker,
  .specialiste-role-picker { gap: 4px; }
  .family-pill,
  .role-pill { font-size: 10px; padding: 4px 8px; }
}

@media (max-width: 480px) {
  /* Padding gauche/droite généreux pour les box-shadow néobrut sans débord. */
  .app { padding: 10px 18px 14px 14px; }
  .reveal-meta { grid-template-columns: 1fr; }
  /* Titre réduit pour ne plus déborder (en 7.5vw il atteignait ≈30 px sur
     iPhone et la chaîne "DEVINE LE PARTI" + emoji + drop-shadow forçait .header
     plus large que .app content area). */
  .site-title { font-size: clamp(15px, 6vw, 24px); }
  /* .panel-title masqué via la règle 860px — pas d'override 480px nécessaire. */
  /* Stats-trigger : padding/gap un poil resserrés pour iPhone, mais on
     préserve la taille du num/label (priorité visuelle). */
  .stats-trigger { gap: 8px; padding: 9px 12px; }
  .trigger-num   { font-size: 30px; }
  .trigger-label { font-size: 16px; }
  .trigger-hint  { font-size: 10px; letter-spacing: 0.04em; gap: 4px; }
  .trigger-hint  .ico-svg { width: 16px !important; height: 16px !important; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* ───────────────────────────────────────────────────────────────────────
   COLLECTION v3 : data-role appliqué sur la PHOTO (pas la carte entière).
   Designs thématiques par fonction. Toutes les déco scopées au masque de
   la photo → pas de débordement hors carte, pas de flicker pendant le
   swipe (cf. app.js applyRoleStyle).

   Sélecteurs partagés jeu/collection :
     .dcard .photo[data-role="..."]              (collection : div .photo)
     .deputy-card .photo-wrap[data-role="..."]   (jeu : conteneur img)
   ─────────────────────────────────────────────────────────────────────── */

/* Le compteur d'origine en bas-droite (correct/encounters) est remplacé
   par le rôle. Le label loc reste à gauche. */
.dcard .meta-loc { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dcard .meta-role {
  font-family: var(--font-display);
  font-size: 9px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  background: var(--paper);
  border: 1.5px solid var(--ink);
  padding: 2px 6px 2.5px;
  line-height: 1;
  white-space: nowrap;
  color: var(--ink);
  opacity: 0.95;
  flex-shrink: 0;
  max-width: 60%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dcard.locked .meta-role { opacity: 0.3; }

/* ─── Visuels par rôle ───────────────────────────────────────────────
   Wipé : on repart d'une feuille blanche pour les contours/masques de photo.
   Les premières tentatives (scotch, tricolore, timbre, RF, ondulé) sont
   archivées dans git, mais aucune n'était assez aboutie. Le data-role est
   conservé en JS pour qu'on puisse y revenir sereinement plus tard.
   Aujourd'hui : juste le label texte en bas-droite (.meta-role), aucun
   traitement visuel sur la photo. */

/* ─── Shiny version collection (= traitement jeu, mais en pause) ─────
   On reproduit la couche .shiny-fx du jeu : bordure dorée pulsante +
   shimmer diagonal. Pausés par défaut pour ne pas saturer la grille.
   Reprise au :hover (souris) ou via .shiny-active (tap mobile). */
.dcard .shiny-fx {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 3;
  display: none;
}
.dcard.shiny .shiny-fx,
.dcard.holo  .shiny-fx { display: block; }
.dcard.shiny .shiny-fx::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 3px solid #f5c518;
  pointer-events: none;
  /* Délai négatif = la frame figée tombe à 50 % du cycle (peak du pulse,
     teinte plus claire #fff09a). */
  animation: shinyBorderPulse 1.8s ease-in-out -0.9s infinite;
  animation-play-state: paused;
}
.dcard.shiny .shiny-fx::after {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 200%; height: 100%;
  background: linear-gradient(115deg,
    transparent 17%,
    rgba(255, 232, 120, 0.5) 25%,
    transparent 33%,
    transparent 67%,
    rgba(255, 232, 120, 0.5) 75%,
    transparent 83%);
  transform: translate3d(-50%, 0, 0);
  /* -0.7s ≈ 25 % du cycle : opacité 1, translation -38 %, bande dorée
     visible vers le tiers droit de la photo (vs opacity 0 en frame 0). */
  animation: shinyShimmer 2.8s linear -0.7s infinite;
  animation-play-state: paused;
  will-change: transform;
}
/* Bordure HOLO iridescente collection — mêmes keyframes que le jeu */
.dcard.holo .shiny-fx::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 3px solid #ff00ff;
  pointer-events: none;
  /* -0.6s = 20 % du cycle : cyan #00ffff (plus marquant que magenta de base). */
  animation: holoBorderHue 3s linear -0.6s infinite;
  animation-play-state: paused;
}
/* Shimmer HOLO collection — gradient multicolore + hue-rotate.
   Opacité 0.30 (réduite vs 0.45) pour éviter la surcharge. */
.dcard.holo .shiny-fx::after {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 200%; height: 100%;
  background: linear-gradient(115deg,
    transparent 13%,
    rgba(255, 100, 200, 0.30) 19%,
    rgba(100, 200, 255, 0.30) 23%,
    rgba(255, 220, 100, 0.30) 27%,
    rgba(180, 100, 255, 0.30) 31%,
    transparent 37%,
    transparent 63%,
    rgba(255, 100, 200, 0.30) 69%,
    rgba(100, 200, 255, 0.30) 73%,
    rgba(255, 220, 100, 0.30) 77%,
    rgba(180, 100, 255, 0.30) 81%,
    transparent 87%);
  transform: translate3d(-50%, 0, 0);
  /* Même phase que shiny (.shimmer à -0.7s) + hue-rotate décalé pour avoir
     une teinte non-magenta de base sur la frame figée. */
  animation: shinyShimmer 2.8s linear -0.7s infinite, holoShimmerHue 4s linear -1s infinite;
  animation-play-state: paused;
  will-change: transform, opacity;
}
/* Reprise : hover (desktop), focus clavier, ou .shiny-active (tap tactile) */
.dcard.shiny:hover .shiny-fx::before,
.dcard.shiny:hover .shiny-fx::after,
.dcard.shiny:focus-within .shiny-fx::before,
.dcard.shiny:focus-within .shiny-fx::after,
.dcard.shiny.shiny-active .shiny-fx::before,
.dcard.shiny.shiny-active .shiny-fx::after,
.dcard.holo:hover .shiny-fx::before,
.dcard.holo:hover .shiny-fx::after,
.dcard.holo:focus-within .shiny-fx::before,
.dcard.holo:focus-within .shiny-fx::after,
.dcard.holo.shiny-active .shiny-fx::before,
.dcard.holo.shiny-active .shiny-fx::after {
  animation-play-state: running;
}
/* Pas d'étoile statique : l'utilisateur veut le MÊME traitement que le jeu
   (cf. brief). La bordure dorée reste visible figée même animation en pause,
   ce qui distingue déjà la carte shiny dans la grille. */

/* ─── Bouton "Charger plus" (lazy load Collection) ─────────────────── */
.load-more-wrap {
  margin: var(--space-4) 0 var(--space-3);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}
.load-more-wrap.hidden { display: none; }
.load-more-info {
  font-family: var(--font-mono);
  font-size: 11px;
  opacity: 0.7;
  letter-spacing: 0.04em;
}
.load-more-btn {
  background: var(--paper);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: 12px 28px;
  font-family: var(--font-display);
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  color: var(--ink);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.load-more-btn:hover,
.load-more-btn:focus-visible {
  transform: translate(-3px, -3px);
  box-shadow: 7px 7px 0 0 var(--ink);
  outline: none;
}
.load-more-btn:active {
  transform: translate(0, 0);
  box-shadow: var(--sh-sm);
}

/* Suppression de l'ancienne étoile shiny (remplacée par .shiny-fx) */
.dcard .shiny-star { display: none !important; }

/* ── Tampons sérigraphie (sceau RF rond + tampon rect institutionnel) ──
   Visibles uniquement sur la carte de jeu (.deputy-card + shadow) ; pas
   dans la collection. Positions (tl/tr/bl/br) et rotation (--rot) sont
   randomisées à chaque draw par applyStamps() en JS. Taille relative au
   container photo via cqi (container query inline-size). */
.fx-stamp {
  position: absolute;
  pointer-events: none;
  z-index: 5;
  /* Couleur et opacité randomisées par tampon via applyStamps (range de
     rouges/bordeaux + opacité variable) → chaque tampon a sa propre teinte
     d'encre, comme dans la réalité. */
  color: var(--stamp-color, #b53a2a);
  opacity: var(--stamp-opacity, 0.78);
  /* Filter de déformation (SVG turbulence + displacement map) appliqué aux
     tracés du tampon — cercles, texte, border deviennent légèrement
     irréguliers, comme une vraie encre tamponnée à la main. La rotation
     est conservée via combinaison de filter + transform. */
  filter: url(#stamp-warp) drop-shadow(0 0 0.4px rgba(181,58,42,0.35));
  transform: rotate(var(--rot, -10deg));
  transform-origin: center center;
}
/* Position de base par coin + offsets random additionnels via custom
   properties (--offset-x / --offset-y), pour que chaque tampon ne tombe pas
   exactement au même endroit à chaque élu. Plus large en vertical qu'en
   horizontal — l'œil pardonne mieux la dérive verticale. */
.fx-stamp[data-pos="tl"] {
  top: calc(6% + var(--offset-y, 0%));
  left: calc(5% + var(--offset-x, 0%));
  right: auto; bottom: auto;
}
.fx-stamp[data-pos="tr"] {
  top: calc(6% + var(--offset-y, 0%));
  right: calc(5% + var(--offset-x, 0%));
  left: auto; bottom: auto;
}
.fx-stamp[data-pos="bl"] {
  bottom: calc(7% + var(--offset-y, 0%));
  left: calc(5% + var(--offset-x, 0%));
  top: auto; right: auto;
}
.fx-stamp[data-pos="br"] {
  bottom: calc(7% + var(--offset-y, 0%));
  right: calc(5% + var(--offset-x, 0%));
  top: auto; left: auto;
}

/* Tampon rond — sceau RF (texte sur arc). Taille augmentée (36 → 44 cqi)
   + offsets resserrés (5-6 % → 1-2 %) pour pousser le sceau dans les bords
   du card. Sur desktop comme sur mobile, le sceau dépasse visuellement de
   la photo et peut se faire couper par le cadre (overflow hidden) du card. */
.fx-stamp.fx-stamp-rf {
  width: 44cqi;
  aspect-ratio: 1;
  height: auto;
  min-width: 96px;
  max-width: 156px;
}
.fx-stamp.fx-stamp-rf svg { width: 100%; height: 100%; display: block; }
/* Offsets spécifiques au sceau RF : positionnement plus extérieur que les
   tampons de base, pour qu'il puisse mordre sur le bord du card.
   Custom properties --offset-x / --offset-y conservées. */
.fx-stamp.fx-stamp-rf[data-pos="tl"] {
  top: calc(1% + var(--offset-y, 0%));
  left: calc(1% + var(--offset-x, 0%));
  right: auto; bottom: auto;
}
.fx-stamp.fx-stamp-rf[data-pos="tr"] {
  top: calc(1% + var(--offset-y, 0%));
  right: calc(1% + var(--offset-x, 0%));
  left: auto; bottom: auto;
}
.fx-stamp.fx-stamp-rf[data-pos="bl"] {
  bottom: calc(2% + var(--offset-y, 0%));
  left: calc(1% + var(--offset-x, 0%));
  top: auto; right: auto;
}
.fx-stamp.fx-stamp-rf[data-pos="br"] {
  bottom: calc(2% + var(--offset-y, 0%));
  right: calc(1% + var(--offset-x, 0%));
  top: auto; left: auto;
}

/* Tampon rectangulaire — institution + DOSSIER N° + numéro (3 lignes).
   Traits épaissis (border 2.5 → 4 px) pour cohérence avec le sceau. */
.fx-stamp.fx-stamp-rect {
  font-family: var(--font-display);
  letter-spacing: 0.10em;
  border: 4px solid currentColor;
  padding: 1.6cqi 3cqi 1.4cqi;
  line-height: 1.1;
  text-align: center;
  box-shadow: inset 0 0 0 2px rgba(181,58,42,0.25);
  max-width: 62%;
  white-space: nowrap;
}
.fx-stamp.fx-stamp-rect .l1 {
  display: block;
  font-size: 3.0cqi;
  letter-spacing: 0.16em;
}
.fx-stamp.fx-stamp-rect .l2 {
  display: block;
  font-size: 3.0cqi;
  letter-spacing: 0.14em;
  margin-top: 2px;
  opacity: 0.85;
}
.fx-stamp.fx-stamp-rect .l3 {
  display: block;
  font-size: 5.2cqi;     /* numéro mis en valeur */
  letter-spacing: 0.04em;
  margin-top: 1px;
}
/* Réduction des tampons sur mobile : RF un peu plus que le rect pour rester
   équilibrés sur les petits écrans. */
@media (max-width: 860px) {
  .fx-stamp.fx-stamp-rf {
    width: 34cqi;        /* desktop 44cqi → mobile 34cqi */
    min-width: 76px;
    max-width: 116px;
  }
  .fx-stamp.fx-stamp-rect {
    border-width: 3px;
    padding: 1.4cqi 2.6cqi 1.2cqi;
    box-shadow: inset 0 0 0 1.5px rgba(181,58,42,0.25);
  }
  .fx-stamp.fx-stamp-rect .l1 { font-size: 2.6cqi; }
  .fx-stamp.fx-stamp-rect .l2 { font-size: 2.6cqi; }
  .fx-stamp.fx-stamp-rect .l3 { font-size: 4.4cqi; }
}
/* Plancher de lisibilité pour les très petits écrans. */
@media (max-width: 480px) {
  .fx-stamp.fx-stamp-rect .l1 { font-size: 8.5px; }
  .fx-stamp.fx-stamp-rect .l2 { font-size: 8.5px; }
  .fx-stamp.fx-stamp-rect .l3 { font-size: 12.5px; }
}

/* Sécurité : pas de tampons dans la Collection (cf. .dcard) — au cas où le
   HTML viendrait à dupliquer la structure photo-wrap. */
.dcard .fx-stamp { display: none; }

/* ── Glossaire partagé ────────────────────────────────────────────────────
   Termes en gras dans les descriptions (succès, modes de jeu…) avec
   tooltip flottant au hover/tap. CSS partagé entre achievements.html et
   index.html ; comportement dans glossary.js. */
.gloss-term {
  font-weight: 700;
  border-bottom: 1.5px dotted currentColor;
  cursor: help;
  padding-bottom: 1px;
}
.gloss-term:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* Tooltip flottant — un seul élément réutilisé dans tout le document. */
.gloss-tooltip {
  position: fixed;
  z-index: 1000;
  max-width: min(340px, calc(100% - 24px));
  background: var(--paper);
  color: var(--ink);
  border: var(--border-thick);
  box-shadow: var(--sh-md);
  padding: 12px 14px;
  opacity: 0;
  pointer-events: none;
  transform: translateY(4px);
  transition: opacity 140ms var(--ease-out), transform 140ms var(--ease-out);
  left: 0; top: 0;
}
.gloss-tooltip.visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.gloss-tip-label {
  font-family: var(--font-display);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height: 1;
  margin-bottom: 7px;
  opacity: 0.7;
}
.gloss-tip-def {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.5;
}
