/* ==========================================================================
   Objectif Fauteuil — Component Classes (Stage 1 foundation)
   ==========================================================================
   Built ONLY from tokens.css custom properties. No raw hex, no raw
   rgba() literals, no magic px outside the token scale defined there.

   Naming: block--modifier (double dash). Legacy classes already living in
   style.css (.btn-primary, .btn-secondary, .btn-outline, .btn-danger) are
   NOT redefined here on purpose — these new classes exist alongside them
   without colliding, ready for a later migration to adopt.
   ========================================================================== */

/* --------------------------------------------------------------------
   Attribut hidden
   -------------------------------------------------------------------- */
/* La regle UA [hidden] { display: none } perd contre toute classe auteur qui
   declare un display (.subm-preview { display: flex } gardait l'apercu d'une
   proposition affiche en permanence : le bouton « Voir » ne basculait rien).
   Garde globale : el.hidden = true masque toujours, quelle que soit la classe. */
[hidden] { display: none !important; }

/* --------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------- */
/* Toute la metrique du bouton est declaree dans style.css (cf. commentaire plus
   bas). style.css etant charge APRES components.css, chaque propriete declaree
   des deux cotes voyait la valeur d'ici mourir en silence : font-weight valait
   --weight-medium ici et --weight-body la-bas, et c'est --weight-body qui
   gagnait. On ne garde donc ici que ce que style.css ne declare pas. */
.btn {
  gap: var(--space-2);
  font-family: var(--font-ui);
}

.btn:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}

.btn:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

/* Variantes et tailles : supprimees le 2026-08-19. Le systeme canonique
   est .btn + .btn-primary / -secondary / -outline / -danger dans style.css
   (64 appels dans le HTML/JS contre 0 pour .btn--*). Le concept de taille
   survit sous .btn--lg, defini a cote de .btn dans style.css pour que
   toute la metrique du bouton se lise au meme endroit. */

/* --------------------------------------------------------------------
   Layout utility — horizontal stack (replaces repeated
   style="display:flex; align-items:center; gap:1rem" inline blocks)
   -------------------------------------------------------------------- */
.hstack {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.hstack--tight { gap: var(--space-3); }

/* Vertical stack (replaces repeated
   style="display:flex; flex-direction:column; gap:..." inline blocks) */
.vstack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.vstack--tight { gap: var(--space-2); }
.vstack--md { gap: var(--space-3); }

/* Flex column with no gap of its own (callers add spacing explicitly) */
.flex-col { display: flex; flex-direction: column; }

.flex-1 { flex: 1; }
.mt-4 { margin-top: var(--space-4); }
.mt-5 { margin-top: var(--space-5); }
.mb-3 { margin-bottom: var(--space-3); }

/* Modal scroll-height variants (replace inline max-height/overflow-y) */
/* Repli svh apres vh : sur un moteur sans svh la seconde ligne est invalide et
   ignoree, la premiere tient. Meme cascade que #info-modal (style.css). */
.modal--scroll-85 { max-height: 85vh; max-height: 85svh; overflow-y: auto; }
.modal--scroll-88 { max-height: 88vh; max-height: 88svh; overflow-y: auto; }
.modal--scroll-90 { max-height: 90vh; max-height: 90svh; overflow-y: auto; }
/* Empilement des modales superposees (sous-modale par-dessus sa modale parente).
   Specificite doublee volontairement : .settings-modal (style.css) declare
   z-index:1000 et, style.css etant charge APRES components.css, une simple classe
   utilitaire perdrait la cascade a specificite egale — la sous-modale s'ouvrait
   alors derriere le catalogue. */
.modal--z1001.modal--z1001 { z-index: var(--z-modal-2); }
.modal--z1002.modal--z1002 { z-index: var(--z-modal-3); }

/* --------------------------------------------------------------------
   Card
   -------------------------------------------------------------------- */
.card {
  background: var(--surface-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  backdrop-filter: blur(var(--blur-md));
  -webkit-backdrop-filter: blur(var(--blur-md));
}

/* --------------------------------------------------------------------
   Field (text input / select / textarea)
   -------------------------------------------------------------------- */
.field {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-ui);
  font-size: var(--text-md);
  font-weight: var(--weight-body);
  color: var(--text-main);
  background: var(--surface-2);
  /* Contraste de bordure WCAG 1.4.11 : limite du champ visible au repos. */
  border: 1px solid var(--border-contrast);
  border-radius: var(--radius-sm);
  transition: border-color var(--dur-base) var(--ease-standard),
              box-shadow var(--dur-base) var(--ease-standard);
}

/* Idem `.admin-field` (style.css) : la liste native d'un <select> hérite du
   blanc et devient invisible sur le fond clair de l'OS. */
select.field { color-scheme: dark; }
select.field option {
  /* Opaque : les tokens --surface-* sont translucides et ne couvriraient pas le
     fond clair d'un moteur qui ignorerait color-scheme. */
  background-color: var(--surface-solid-1);
  color: var(--text-main);
}

.field::placeholder {
  color: var(--text-muted);
}

.field:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px var(--gold-glow);
}

/* iOS zoome automatiquement sur le focus d'un input < 16px, y compris
   dans les modales position:fixed (.modal__backdrop). On remonte à
   --text-base (16px) sous 768px ; taille desktop inchangée au-dessus. */
@media (max-width: 767px) {
  .field {
    font-size: var(--text-base);
  }
}

/* --------------------------------------------------------------------
   Modal shell
   -------------------------------------------------------------------- */
.modal__backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg-deep) 70%, transparent);
  backdrop-filter: blur(var(--blur-sm));
  -webkit-backdrop-filter: blur(var(--blur-sm));
  opacity: 0;
  visibility: hidden;
  /* visibility bascule d'un coup : interpolée, elle vaut encore « hidden » au
     moment où .is-open est posée, et focus() dans la modale ne fait rien. */
  transition: opacity var(--dur-base) var(--ease-standard),
              visibility 0s linear var(--dur-base);
}

.modal__backdrop.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-base) var(--ease-standard), visibility 0s;
}

.modal {
  width: min(90vw, 480px);
  max-height: 85vh;
  overflow-y: auto;
  background: var(--bg-card);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  box-shadow: var(--glass-shadow);
  padding: var(--space-6);
  transform: translateY(10px);
  transition: transform var(--dur-base) var(--ease-decelerate);
}

.modal__backdrop.is-open .modal {
  transform: translateY(0);
}

/* --------------------------------------------------------------------
   Reduced motion — neutralise transitions/animations app-wide
   Transitions à 0s, jamais une durée infime : voir la règle jumelle de
   style.css (focus() perdu sur un `visibility 0s` devenu transition).
   -------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: 0s !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------
   États de message (game.setFeedback) — remplace les couleurs posées
   en style inline depuis le JS.
   -------------------------------------------------------------------- */
.fb-ok  { color: var(--correct-color); }
.fb-err { color: var(--wrong-color); }

/* Image d'une question (aperçu admin + jeu). La classe existait dans le JS mais
   n'avait aucune règle : le style vivait en `style.cssText` inline. */
.question-image {
  max-width: 100%;
  border-radius: var(--radius-md);
  margin: var(--space-4) 0;
}

/* --------------------------------------------------------------------
   Modale de connexion / inscription (auth.js)
   Ces règles remplacent 12 attributs style="" construits en JS, dont une
   constante FIELD_STYLE qui redéfinissait ses propres rgba().
   -------------------------------------------------------------------- */
.auth-title { margin: 0 0 var(--space-6); }

.auth-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-6);
}

.auth-field {
  /* 12px/16px : les pas de l'échelle les plus proches du 12px/14px d'origine.
     --surface-3 (0.08) est le barreau le plus proche du rgba(…,0.07) supprimé.
     Bordure passée à --border-contrast (WCAG 1.4.11) : limite du champ
     visible au repos. */
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  border: 1px solid var(--border-contrast);
  color: var(--text-main);
  font-family: inherit;
  font-size: var(--text-base);
  width: 100%;
  box-sizing: border-box;
}

.auth-pwd-row { position: relative; }
.auth-field--pwd { padding-right: 44px; }

.auth-pwd-toggle {
  position: absolute;
  right: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--text-lg);
}

.auth-link-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: var(--text-sm);
  cursor: pointer;
  padding: 0;
  text-align: left;
  text-decoration: underline;
}

.auth-submit { width: 100%; }

.auth-feedback {
  font-size: var(--text-sm);
  min-height: 1.1em;
  margin: 0;
}

/* --------------------------------------------------------------------
   Résultats de recherche (search.js) — remplace 7 attributs style="".
   -------------------------------------------------------------------- */
.search-res-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--space-2);
}

.search-res-id {
  color: var(--gold);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
}

.search-res-src {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.search-res-q {
  font-size: var(--text-md);
  line-height: 1.4;
}

.search-res-actions {
  margin-top: var(--space-3);
  text-align: right;
}

.search-res-more {
  text-align: center;
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-top: var(--space-3);
}

.search-edit-btn {
  background: none;
  border: 1px solid var(--gold);
  color: var(--gold);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  padding: var(--space-1) var(--space-3);
  cursor: pointer;
}

/* ============================================
   📊 AUDIENCE — tableau de bord admin
   Spec : docs/superpowers/specs/2026-08-31-tracker-audience-design.md
   Charpente partagée avec « Partie du jour » (adp-* dans style.css) :
   en-tête, période, onglets, corps défilant, pied. Ici : le contenu des
   onglets. Aucune librairie de graphiques : seules width/height des
   remplissages sont inline, parce que calculées à l'exécution.
   ============================================ */

/* --- Tuiles --- */
.aud-tiles {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}
.aud-tile {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
    padding: var(--space-3);
    border: 1px solid var(--surface-2);
    border-radius: var(--radius-md);
    background: var(--surface-1);
    text-align: center;
}
.aud-tile-label {
    font-size: var(--text-2xs);
    font-weight: var(--weight-bold);
    letter-spacing: 0.8px;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--text-main) 42%, transparent);
}
.aud-tile-value {
    font-size: var(--text-lg);
    color: var(--gold);
}
.aud-tile-hint {
    overflow: hidden;
    font-size: var(--text-2xs);
    color: color-mix(in srgb, var(--text-main) 42%, transparent);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Cartes (sparkline, entonnoir, manches, défi du jour) --- */
.aud-card {
    min-width: 0;
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4) var(--space-4);
    border: 1px solid var(--surface-2);
    border-radius: var(--radius-md);
    background: var(--surface-1);
}
.aud-card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.aud-card-head > span {
    color: var(--gold);
    font-size: var(--text-2xs);
    font-weight: var(--weight-impact);
    letter-spacing: 1.3px;
    text-transform: uppercase;
}
.aud-card-head > small {
    color: color-mix(in srgb, var(--text-main) 42%, transparent);
    font-size: var(--text-2xs);
    white-space: nowrap;
}
.aud-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-4);
}
.aud-cols .aud-card { margin-bottom: var(--space-4); }

/* --- Sparkline --- */
.aud-spark {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 72px;
}
.aud-spark-col {
    display: flex;
    flex: 1;
    align-items: flex-end;
    height: 100%;
    min-width: 2px;
}
.aud-spark-fill {
    width: 100%;
    min-height: 1px;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    background: color-mix(in srgb, var(--gold) 70%, transparent);
}
.aud-spark-axis {
    display: flex;
    justify-content: space-between;
    margin-top: var(--space-1);
    font-size: var(--text-2xs);
    color: color-mix(in srgb, var(--text-main) 38%, transparent);
}

/* --- Barres --- */
.aud-bar-row {
    display: grid;
    grid-template-columns: 6rem minmax(0, 1fr) 3rem;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}
.aud-bar-row:last-child { margin-bottom: 0; }
.aud-bar-label {
    overflow: hidden;
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--text-main) 62%, transparent);
    text-overflow: ellipsis;
    white-space: nowrap;
}
.aud-bar-track {
    height: var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    overflow: hidden;
}
.aud-bar-fill {
    display: block;
    height: 100%;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--gold) 70%, transparent);
}
.aud-bar-value {
    font-size: var(--text-xs);
    font-weight: var(--weight-bold);
    text-align: right;
    color: var(--text-main);
}

/* --- Distributions (Acquisition, Engagement, Technique) ---
   Même barre que ci-dessus, mais la colonne de droite porte la valeur ET sa part
   du total : d'où la piste plus large et la valeur sur deux lignes. */
/* Colonne de droite en `max-content` : un compteur à quatre chiffres dans une
   carte de demi-largeur (.aud-cols) déborderait sur la piste avec une largeur fixe. */
.aud-dist .aud-bar-row {
    grid-template-columns: minmax(5rem, 8rem) minmax(0, 1fr) max-content;
    margin-bottom: var(--space-3);
}
.aud-dist .aud-bar-value {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.2;
    white-space: nowrap;
}
.aud-dist .aud-bar-value small {
    font-size: var(--text-2xs);
    font-weight: var(--weight-body);
    color: color-mix(in srgb, var(--text-main) 42%, transparent);
}
.aud-empty {
    margin: 0;
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--text-main) 42%, transparent);
}
/* Note de bas de carte : ce que le chiffre ne dit pas (méthode, limite). */
.aud-note {
    margin: var(--space-3) 0 0;
    font-size: var(--text-2xs);
    line-height: 1.5;
    color: color-mix(in srgb, var(--text-main) 38%, transparent);
}
.aud-note code {
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    font-size: var(--text-2xs);
}
/* Axe à graduations régulières (heures) — l'axe de la sparkline, lui, n'affiche
   que ses deux extrémités et reste en `space-between`. */
.aud-spark-axis--even { justify-content: space-around; }

/* --- Web Vitals : moyenne + barre empilée bon / moyen / mauvais --- */
.aud-vital {
    display: grid;
    grid-template-columns: 6rem 4.5rem minmax(0, 1fr);
    align-items: center;
    gap: var(--space-2) var(--space-3);
    margin-bottom: var(--space-4);
}
.aud-vital:last-of-type { margin-bottom: 0; }
.aud-vital-name {
    font-size: var(--text-xs);
    font-weight: var(--weight-bold);
    color: color-mix(in srgb, var(--text-main) 72%, transparent);
}
.aud-vital-name small {
    display: block;
    font-size: var(--text-2xs);
    font-weight: var(--weight-body);
    color: color-mix(in srgb, var(--text-main) 38%, transparent);
}
.aud-vital-avg {
    font-size: var(--text-md);
    color: var(--gold);
    text-align: right;
}
.aud-vital-track {
    display: flex;
    overflow: hidden;
    height: var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--surface-2);
}
.aud-vital-seg { display: block; height: 100%; }
.aud-vital-seg--good { background: color-mix(in srgb, var(--correct-color) 70%, transparent); }
.aud-vital-seg--ni   { background: color-mix(in srgb, var(--warn-soft) 70%, transparent); }
.aud-vital-seg--poor { background: color-mix(in srgb, var(--wrong-color) 70%, transparent); }
.aud-vital-legend {
    grid-column: 3;
    font-size: var(--text-2xs);
    color: color-mix(in srgb, var(--text-main) 42%, transparent);
}

/* --- Carte « Défi du jour » : résumé + renvoi vers les Suspicions --- */
.aud-daily {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}
.aud-daily p { margin: 0; color: color-mix(in srgb, var(--text-main) 72%, transparent); font-size: var(--text-sm); }
.aud-daily p .adp-int-badge { margin-left: var(--space-2); }
.aud-daily .btn { min-height: var(--control-h-sm); padding: var(--space-2) var(--space-3); font-size: var(--text-xs); white-space: nowrap; }

/* --- Joueurs : barre d'outils, en-tête de colonnes, lignes --- */
.aud-toolbar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: end;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}
.aud-filter {
    width: 100%;
    min-width: 0;
    height: 34px;
    padding: 0 var(--space-3);
    color: var(--text-main);
    background: var(--surface-solid-4);
    /* Contraste de bordure WCAG 1.4.11 : limite du champ visible au repos. */
    border: 1px solid var(--border-contrast);
    border-radius: var(--radius-sm);
    font: inherit;
    font-size: var(--text-xs);
}
.aud-filter::placeholder { color: color-mix(in srgb, var(--text-main) 38%, transparent); }
.aud-filter:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
.aud-sort-wrap { display: flex; flex-direction: column; gap: var(--space-1); }
.aud-sort-wrap > span { color: color-mix(in srgb, var(--text-main) 34%, transparent); font-size: var(--text-2xs); font-weight: var(--weight-bold); letter-spacing: 0.7px; text-transform: uppercase; }
.aud-stale { min-height: 34px; padding: var(--space-2) var(--space-3); font-size: var(--text-xs); }
.aud-stale[aria-pressed="true"] { color: var(--gold); border-color: var(--gold); }
.aud-count {
    display: block;
    margin-bottom: var(--space-2);
    color: color-mix(in srgb, var(--text-main) 42%, transparent);
    font-size: var(--text-xs);
}
.aud-thead,
.aud-player {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 64px 92px 72px 56px 20px;
    align-items: center;
    gap: var(--space-3);
}
.aud-thead {
    padding: 0 var(--space-3) var(--space-2);
    color: color-mix(in srgb, var(--text-main) 34%, transparent);
    font-size: var(--text-2xs);
    font-weight: var(--weight-bold);
    letter-spacing: 0.7px;
    text-transform: uppercase;
}
.aud-thead > span:not(:first-child) { text-align: right; }
.aud-roster { display: grid; gap: var(--space-1); }
.aud-row {
    border: 1px solid var(--surface-2);
    border-radius: var(--radius-sm);
    background: var(--surface-1);
    transition: background var(--dur-fast) ease, border-color var(--dur-fast) ease;
}
.aud-row:hover, .aud-row:focus-within { background: var(--surface-2); border-color: var(--border); }
.aud-row--open { border-color: color-mix(in srgb, var(--gold-tint) 45%, transparent); }
.aud-player {
    /* Ligne cliquable : un vrai <button> (clavier, lecteur d'écran), remis à
       plat pour garder l'apparence d'une ligne de tableau. */
    width: 100%;
    min-height: 42px;
    padding: var(--space-2) var(--space-3);
    color: var(--text-main);
    background: none;
    border: 0;
    font: inherit;
    font-size: var(--text-sm);
    text-align: left;
    cursor: pointer;
}
.aud-player:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; border-radius: var(--radius-sm); }
.aud-player-name {
    overflow: hidden;
    font-weight: var(--weight-medium);
    text-overflow: ellipsis;
    white-space: nowrap;
}
.aud-player-stat,
.aud-player-seen {
    font-size: var(--text-xs);
    color: color-mix(in srgb, var(--text-main) 62%, transparent);
    text-align: right;
    white-space: nowrap;
}
.aud-player-stat small { color: color-mix(in srgb, var(--text-main) 38%, transparent); }
.aud-row--stale .aud-player-seen { color: var(--gold); }
.aud-chevron { color: color-mix(in srgb, var(--text-main) 38%, transparent); font-size: var(--text-xs); text-align: right; transition: transform var(--dur-fast) ease; }
.aud-row--open .aud-chevron { transform: rotate(180deg); }
.aud-detail {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-4);
    padding: var(--space-3) var(--space-3) var(--space-4);
    border-top: 1px solid var(--surface-2);
}
.aud-detail-title {
    margin: 0 0 var(--space-2);
    color: var(--gold);
    font-size: var(--text-2xs);
    font-weight: var(--weight-impact);
    letter-spacing: 1.3px;
    text-transform: uppercase;
}
.aud-detail-line {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    font-size: var(--text-xs);
    color: var(--text-main);
}
.aud-detail-line > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aud-detail-line > span:last-child { white-space: nowrap; color: color-mix(in srgb, var(--text-main) 55%, transparent); }
.aud-detail-sep { font-size: var(--text-xs); color: color-mix(in srgb, var(--text-main) 38%, transparent); text-align: center; }

@media (max-width: 767px) {
    .aud-tiles { grid-template-columns: repeat(2, 1fr); }
    .aud-tiles .aud-tile:last-child { grid-column: 1 / -1; }
    .aud-cols  { grid-template-columns: 1fr; }
    /* Libellés et moyennes reprennent leur largeur : sur 360 px, une piste de
       barre trop courte ne compare plus rien. */
    .aud-dist .aud-bar-row { grid-template-columns: minmax(4rem, 6rem) minmax(0, 1fr) max-content; }
    .aud-vital { grid-template-columns: 4.5rem 3.5rem minmax(0, 1fr); }
    .aud-vital-avg { font-size: var(--text-sm); }
    .aud-daily { align-items: stretch; flex-direction: column; }
    .aud-toolbar { grid-template-columns: 1fr 1fr; }
    .aud-toolbar .aud-filter { grid-column: 1 / -1; }
    .aud-thead { display: none; }
    .aud-player { grid-template-columns: minmax(0, 1fr) auto 20px; row-gap: var(--space-1); }
    .aud-player-name { grid-column: 1 / 2; }
    .aud-player-stat:nth-of-type(2), .aud-player-stat:nth-of-type(3) { grid-column: 1 / 2; text-align: left; }
    .aud-detail { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------
   Défilement — apparence de la barre et confinement
   --------------------------------------------------------------------
   Une seule apparence de scrollbar pour toute l'app : la barre native
   (blanc/gris système) tranchait sur les surfaces sombres des modales.
   Deux implémentations, jamais les deux à la fois : dès que
   `scrollbar-color` est déclaré, Chrome bascule sur la barre standard et
   IGNORE tout le bloc ::-webkit-* (barre large, flèches haut/bas). D'où le
   `@supports not selector(::-webkit-scrollbar)` : les propriétés standard
   ne s'appliquent qu'à Firefox, ::-webkit-* tient Chrome/Safari. Elles sont
   HÉRITÉES, donc :root suffit — y compris pour les conteneurs créés plus
   tard en innerHTML.
   -------------------------------------------------------------------- */
@supports not selector(::-webkit-scrollbar) {
  :root {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--gold-tint) 30%, transparent) transparent;
  }
}

/* Souris seulement. Sur un mobile la barre est en surimpression et disparaît
   toute seule ; styler ::-webkit-scrollbar l'y transforme en barre classique
   qui prend 10 px de large en permanence dans chaque modale. */
@media (hover: hover) and (pointer: fine) {
  *::-webkit-scrollbar { width: 10px; height: 10px; }
  *::-webkit-scrollbar-track { background: transparent; }
  *::-webkit-scrollbar-corner { background: transparent; }
  *::-webkit-scrollbar-thumb {
    /* Bordure transparente + background-clip : le pouce paraît fin (4 px) tout
       en gardant une cible de saisie souris de 10 px. */
    background-color: color-mix(in srgb, var(--gold-tint) 30%, transparent);
    background-clip: padding-box;
    border: 3px solid transparent;
    border-radius: var(--radius-pill);
  }
  *::-webkit-scrollbar-thumb:hover {
    background-color: color-mix(in srgb, var(--gold-tint) 55%, transparent);
    background-clip: padding-box;
  }
}

/* Le document réserve sa gouttière en permanence : sans ça, le verrou
   ci-dessous fait disparaître la barre de la page et tout le contenu saute
   latéralement de 10 px à l'ouverture d'une modale. */
html { scrollbar-gutter: stable; }

/* Verrou de défilement : tant qu'une modale est ouverte, la molette ne doit
   plus déplacer la page derrière (le fond glissait sous la modale, d'où
   l'impression que le scroll « part ailleurs »). Posé par
   `game._lockPageScroll` (ui.js), qui fournit aussi --scroll-lock-y :
   `position: fixed` seul ramènerait la page en haut. */
body.is-scroll-locked {
  position: fixed;
  top: var(--scroll-lock-y, 0);
  left: 0;
  right: 0;
  width: 100%;
}

/* Fin de course d'une zone scrollable : ne rien propager au parent. Sans
   `contain`, arriver en bas d'une liste de modale enchaînait sur le scroll
   du document (et sur le pull-to-refresh mobile). */
.settings-modal,
.modal,
.modal--scroll-85,
.modal--scroll-88,
.modal--scroll-90,
.adp-scroll-region,
.admin-cat-list,
.bilan-container,
.daily-lb-modal-list,
.profile-games,
#profile-body,
.search-results-list,
#cat-list,
#info-modal { overscroll-behavior: contain; }

/* --------------------------------------------------------------------
   Toast — notification passagère, empilée en bas à droite.
   Seul emploi actuel : un badge débloqué (ui.js, pushBadgeToast).
   -------------------------------------------------------------------- */
.toast-stack {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-2);
  /* La pile couvre le coin de l'écran en permanence : sans cela elle
     intercepterait les clics sur ce qu'elle recouvre quand elle est vide. */
  pointer-events: none;
}

/* Purement informative : aucune action, donc aucune cible de clic. La pile flotte
   a --z-toast, au-dessus des modales ; interactive, trois cartes recouvraient le
   bouton « Enregistrer » de « Mon profil » et le clic fermait une carte au lieu
   d enregistrer. Un div cliquable n etait de toute facon pas atteignable au
   clavier : elle s efface seule au bout de TOAST_MS. */
.toast {
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: min(21rem, calc(100vw - var(--space-6)));
  padding: var(--space-3);
  background: var(--surface-solid-4);
  border: 1px solid var(--gold-glow);
  border-radius: var(--radius-md);
  box-shadow: var(--glass-shadow);
  text-align: left;
  animation: toast-in var(--dur-base) var(--ease-spring) both;
}

.toast--leaving {
  animation: toast-out var(--dur-base) var(--ease-standard) both;
}

.toast-medal {
  flex: none;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  color: var(--gold);
  border: 1px solid var(--gold-glow);
  background: color-mix(in srgb, var(--gold) 12%, var(--surface-2));
}

.toast-medal .badge-icon {
  width: 26px;
  height: 26px;
}

.toast-body {
  flex: 1;
  min-width: 0;
}

.toast-eyebrow {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--text-2xs);
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.toast-title {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  color: var(--gold);
}

.toast-desc {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.4;
  color: var(--text-muted);
}

/* Rareté sur la carte d’un badge fraîchement débloqué : le moment où elle vaut
   le plus cher, et elle ne coûte aucune place permanente. Réservée aux badges
   rares (ui.js) — « 88 % l’ont » sur la carte qui félicite, c’est le compliment
   repris aussitôt. */
.toast-rarity {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--text-2xs);
  font-weight: var(--weight-bold);
  color: var(--gold);
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(var(--space-4)) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

@keyframes toast-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(var(--space-2)); }
}

@media (max-width: 600px) {
  .toast-stack {
    left: var(--space-3);
    right: var(--space-3);
    bottom: var(--space-3);
  }

  .toast {
    width: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast,
  .toast--leaving {
    animation-duration: 0.01ms;
  }
}
