/* ==========================================================================
   Lockace — Composants : boutons, cartes, badges, CTA, formulaires, consentement
   ========================================================================== */

/* Boutons (cf. plan §12.5)
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: var(--text-base);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast),
    color var(--transition-fast), transform var(--transition-fast);
}

.btn:active {
  transform: translateY(1px);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

.btn-primary {
  background: var(--color-primary-on-text);
  color: #fff;
}

.btn-primary:hover {
  background: var(--color-primary-on-text-strong);
  color: #fff;
}

.btn-secondary {
  background: transparent;
  border-color: var(--color-secondary);
  color: var(--color-secondary-soft);
}

.btn-secondary:hover {
  background: rgb(71 134 236 / 0.16);
  color: var(--color-text);
}

.btn-tertiary {
  background: transparent;
  border-color: var(--color-tertiary);
  color: var(--color-tertiary-soft);
}

.btn-tertiary:hover {
  background: rgb(188 124 23 / 0.16);
  color: var(--color-text);
}

/* État de chargement */
.btn.is-loading {
  pointer-events: none;
  opacity: 0.7;
}

.btn.is-loading::after {
  content: "";
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: btn-spin 0.7s linear infinite;
}

@keyframes btn-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Badges
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.15rem 0.65rem;
  border-radius: var(--radius-pill);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.badge-new {
  background: var(--color-primary-on-text);
  color: #fff;
}

/* Fond opaque, comme .badge-new : ces badges sont posés sur les visuels des
   cartes, un fond translucide laissait le contraste dépendre de l'image. */
.badge-fast {
  background: var(--color-secondary-on-text);
  color: #fff;
}

.badge-soon {
  background: var(--color-surface-alt);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

.badge-expert {
  background: var(--color-tertiary-on-text);
  color: #fff;
}

/* Cartes de jeu (cf. plan §9.1)
   -------------------------------------------------------------------------- */
.game-card {
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.game-card:hover {
  border-color: var(--color-primary);
  transform: translateY(-3px);
}

/* Cadre d'illustration au format fixe : les visuels du catalogue ont des tailles
   et des ratios variés (carré, 16/10, portrait), on les recadre pour que toutes
   les cartes s'alignent. */
.game-card-media {
  position: relative;
  aspect-ratio: 16 / 10;
  /* La carte est un conteneur flex : sans `min-height: 0`, la taille minimale
     automatique du média serait celle de l'image et écraserait l'aspect-ratio. */
  min-height: 0;
  overflow: hidden;
  background: var(--color-surface-alt);
}

/* Image en position absolue : elle remplit le cadre sans jamais peser sur la
   hauteur de celui-ci, quelles que soient ses dimensions intrinsèques. */
.game-card-media img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Point d'intérêt par défaut : légèrement au-dessus du centre, ce qui préserve
     les sujets (visages, titres) sur les visuels portrait fortement recadrés.
     Surchargeable par jeu via `imageFocus` dans games.json. */
  object-position: var(--game-card-focus, 50% 40%);
}

.game-card-media .badge {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
}

/* Cœur des favoris (cf. favorites.js)
   -------------------------------------------------------------------------- */

/* Posé face au badge, dans l'angle opposé. Le titre de la carte est un lien qui
   couvre toute la surface (`::after { inset: 0 }`) : sans `z-index`, le cœur
   serait sous ce lien et le clic ouvrirait le jeu au lieu de basculer l'état. */
.favorite-btn {
  position: absolute;
  z-index: 2;
  top: var(--space-3);
  right: var(--space-3);
  display: grid;
  place-items: center;
  width: var(--tap-target);
  height: var(--tap-target);
  padding: 0;
  background: rgb(0 0 0 / 0.55);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  cursor: pointer;
  font-size: 1.15rem;
  line-height: 1;
  /* Le cœur est un fantôme discret tant qu'il n'est pas choisi, puis s'affirme :
     l'état se lit à la couleur *et* à la taille, jamais à la couleur seule. */
  transition: color var(--transition-fast), border-color var(--transition-fast),
    transform var(--transition-fast);
}

.favorite-btn:hover {
  border-color: var(--color-primary);
  color: var(--color-primary-strong);
  transform: scale(1.08);
}

.favorite-btn[aria-pressed="true"] {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

/* Pas d'animation à la bascule : les cœurs se remplissent aussi à l'arrivée des
   données (cf. `hydrate()`), et une grille qui palpite au chargement ne dirait
   rien du geste du visiteur. La couleur suffit à confirmer. */
@media (prefers-reduced-motion: reduce) {
  .favorite-btn:hover {
    transform: none;
  }
}

.game-card-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--space-3);
  padding: var(--space-5);
}

.game-card h2,
.game-card h3 {
  font-size: 1.25rem;
}

.game-card h2 a,
.game-card h3 a {
  color: var(--color-text);
  text-decoration: none;
}

.game-card h2 a::after,
.game-card h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.game-card {
  position: relative;
}

.game-card h2 a:hover,
.game-card h3 a:hover {
  color: var(--color-primary);
}

.game-card p {
  color: var(--color-text-muted);
  flex: 1;
}

.game-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.game-card-meta span {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* Thème et tags d'une carte : descriptifs, jamais cliquables. */
.game-card-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.chip {
  padding: calc(var(--space-1) / 1.5) var(--space-2);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  font-size: 0.75rem;
  line-height: 1.5;
}

/* Le thème prime visuellement sur les tags, qui restent en retrait. */
.chip-theme {
  border-color: var(--color-secondary);
  color: var(--color-secondary-soft);
  font-weight: 600;
}

.game-card-cta {
  margin-top: var(--space-2);
  align-self: flex-start;
  /* Le lien de la carte couvre déjà toute la surface : le bouton est décoratif.
     `pointer-events: none` laisse le clic atteindre ce lien — sans quoi le
     bouton, placé au-dessus par son z-index, absorberait le clic sans rien faire. */
  position: relative;
  z-index: 1;
  pointer-events: none;
}

.game-card.is-soon {
  opacity: 0.75;
}

.game-card.is-soon:hover {
  border-color: var(--color-border);
  transform: none;
}

/* Recherche du catalogue
   -------------------------------------------------------------------------- */
.games-search {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.games-search-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  /* Occupe la largeur disponible, mais se replie sous 100 % sur mobile. */
  flex: 1 1 18rem;
}

.games-search-label {
  color: var(--color-text-muted);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.games-search input[type="search"] {
  width: 100%;
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-text);
  font: inherit;
  transition: border-color var(--transition-fast);
}

.games-search input[type="search"]::placeholder {
  color: var(--color-text-muted);
}

.games-search input[type="search"]:focus-visible {
  border-color: var(--color-secondary);
}

/* Actions à droite de la recherche : favoris et réinitialisation. Sur mobile
   elles passent sous le champ, qui garde la priorité de largeur. */
.games-search-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
}

.games-search-reset {
  flex: 0 0 auto;
}

/* Compteur de résultats : discret, mais annoncé par les lecteurs d'écran. */
.results-count {
  margin-bottom: var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* Filtres du catalogue
   --------------------------------------------------------------------------
   Les critères d'affinage tiennent dans un `<details>` toujours replié au
   chargement : dépliés, leurs dix-sept pastilles repoussaient la première carte
   sous la ligne de flottaison. Le `<details>` natif nous donne le clavier et
   `aria-expanded` sans une ligne de script. */
.filters-panel {
  margin-bottom: var(--space-6);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

.filters-summary {
  display: flex;
  align-items: center;
  /* Trois critères actifs débordent d'une ligne sur mobile : ils passent
     dessous plutôt que de comprimer le titre. */
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-4);
  color: var(--color-text);
  cursor: pointer;
  font-weight: 600;
  /* Le marqueur natif diffère d'un navigateur à l'autre : on pose le nôtre. */
  list-style: none;
}

.filters-summary::-webkit-details-marker {
  display: none;
}

.filters-summary:hover {
  color: var(--color-secondary);
}

.filters-summary-chevron {
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  /* Pointe à droite replié, vers le bas déplié. */
  transform: rotate(-45deg);
  transition: transform var(--transition-fast);
}

.filters-panel[open] .filters-summary-chevron {
  transform: rotate(45deg);
}

/* Replié, le panneau filtrerait en silence : ces pastilles nomment les critères
   qui pèsent encore sur la grille. */
.filters-summary-active {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.filters-summary-chip {
  padding: 0.125rem var(--space-2);
  background: var(--color-secondary);
  border-radius: var(--radius-pill);
  color: #0b1526;
  font-size: var(--text-sm);
  font-weight: 700;
  /* Un rappel d'état, pas une commande : le clic reste celui du `summary`. */
  white-space: nowrap;
}

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-6);
  padding: var(--space-2) var(--space-4) var(--space-4);
  border-top: 1px solid var(--color-border);
}

.filter-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.filter-group-label {
  color: var(--color-text-muted);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.filter-group-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.filter-btn {
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  cursor: pointer;
  font-weight: 500;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.filter-btn:hover {
  border-color: var(--color-secondary);
  color: var(--color-text);
}

.filter-btn[aria-pressed="true"] {
  background: var(--color-secondary);
  border-color: var(--color-secondary);
  color: #0b1526;
  font-weight: 700;
}

/* « Mes favoris » : un interrupteur posé près de la recherche, hors du panneau
   d'affinage. Il emprunte la couleur des cœurs plutôt que le bleu des filtres,
   pour qu'on lise d'un coup d'œil qu'il ne relève pas du même mécanisme. */
.filter-btn-favorite {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.filter-btn-favorite:hover {
  border-color: var(--color-primary);
}

.filter-btn-favorite[aria-pressed="true"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-primary-contrast);
}

/* État vide */
.empty-state {
  padding: var(--space-7);
  text-align: center;
  color: var(--color-text-muted);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-lg);
}

/* CTA Markind (cf. plan §11.1)
   -------------------------------------------------------------------------- */
.markind-cta {
  margin-top: var(--space-8);
  padding-block: var(--space-7);
  background:
    radial-gradient(60rem 20rem at 20% 0%, rgb(221 119 125 / 0.12), transparent),
    radial-gradient(50rem 18rem at 90% 100%, rgb(71 134 236 / 0.12), transparent),
    var(--color-surface);
  border-block: 1px solid var(--color-border);
  text-align: center;
}

.markind-cta h2 {
  margin-bottom: var(--space-3);
}

.markind-cta p {
  color: var(--color-text-muted);
  max-width: 46rem;
  margin-inline: auto;
  margin-bottom: var(--space-5);
}

.cta-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}

/* Bloc newsletter
   -------------------------------------------------------------------------- */
.newsletter-block {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
}

.newsletter-block h2 {
  font-size: var(--text-h3);
  margin-bottom: var(--space-2);
}

.newsletter-block p {
  color: var(--color-text-muted);
}

/* Formulaires
   -------------------------------------------------------------------------- */
.form-field {
  margin-bottom: var(--space-5);
}

.form-field label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.form-hint {
  display: block;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-top: var(--space-1);
}

input[type="text"],
input[type="email"],
select,
textarea {
  width: 100%;
  min-height: var(--tap-target);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font: inherit;
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--color-secondary);
  outline-offset: 1px;
  border-color: var(--color-secondary);
}

.form-error {
  color: var(--color-error);
  font-size: var(--text-sm);
  margin-top: var(--space-1);
}

.checkbox-field {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.checkbox-field input {
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.2rem;
  accent-color: var(--color-primary);
}

/* Breadcrumb
   -------------------------------------------------------------------------- */
.breadcrumb {
  padding-block: var(--space-4);
  font-size: var(--text-sm);
}

.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.breadcrumb li + li::before {
  content: "›";
  margin-right: var(--space-2);
  color: var(--color-text-muted);
}

.breadcrumb a {
  color: var(--color-text-muted);
}

.breadcrumb [aria-current="page"] {
  color: var(--color-text);
}

/* Notification (retour de partage, etc.)
   -------------------------------------------------------------------------- */
.toast {
  position: fixed;
  bottom: var(--space-5);
  left: 50%;
  transform: translateX(-50%);
  z-index: 90;
  padding: var(--space-3) var(--space-5);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-success);
  border-radius: var(--radius-pill);
  color: var(--color-text);
  box-shadow: var(--shadow-card);
}

/* Bannière de consentement (cf. plan §20)
   -------------------------------------------------------------------------- */
.consent-banner {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 80;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  box-shadow: 0 -10px 30px rgb(0 0 0 / 0.6);
  padding: var(--space-5);
}

.consent-inner {
  width: min(100% - 2.5rem, var(--container-max));
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

.consent-inner p {
  flex: 1 1 24rem;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  margin: 0;
}

.consent-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* Encadrés d'information
   -------------------------------------------------------------------------- */
.notice {
  padding: var(--space-4) var(--space-5);
  background: var(--color-surface-alt);
  border-left: 3px solid var(--color-tertiary);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* Preuve sociale WiserNotify (accueil, avant la grille de jeux)
   -------------------------------------------------------------------------- */
.social-proof {
  display: flex;
  justify-content: center;
  margin-bottom: var(--space-5);
}

.social-proof .htmlsnpt {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  text-align: center;
}

/* Lockace en chiffres (accueil)
   -------------------------------------------------------------------------- */
.stats-section {
  /* Enchaîne le hero : moins d'air en haut qu'une section standard. */
  padding-block: var(--space-7) var(--space-8);
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
  gap: var(--space-4);
  margin: 0;
}

.stat {
  /* La valeur est écrite après le libellé (ordre `dt`/`dd` imposé par HTML) :
     l'inversion visuelle remet le chiffre au-dessus. */
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-2);
  padding: var(--space-5);
  background:
    radial-gradient(24rem 12rem at 50% 0%, rgb(221 119 125 / 0.1), transparent),
    var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  text-align: center;
}

.stat-value {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
}

.stat-icon {
  font-size: var(--text-xl);
  line-height: 1;
}

.stat-number {
  font-size: clamp(2rem, 5vw, 2.75rem);
  font-weight: 700;
  line-height: 1;
  color: var(--color-primary-strong);
  font-variant-numeric: tabular-nums;
}

.stat-label {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  text-wrap: balance;
}
