/* ============================================================================
   Le Tribunal des Flags — vue plein écran, badges de profil, accroche de chat.
   Cf. Documentations/Gamification/tribunal_des_flags.md

   Charte reprise du reste de l'application :
     - fond « aurora » (dégradé qui coule + orbes flous), même principe visuel que
       modules/authBackgroundAurora.css et modules/loadingScreenBackground.css, avec des
       keyframes préfixées `flag-` pour ne dépendre d'aucune de ces deux feuilles ;
     - dégradé signature `90deg, var(--sy-brand-500) → var(--sy-accent-600)` (identique à .sy-btn--primary) ;
     - boutons en pilule (border-radius 9999px) et rebond `cubic-bezier(0.34, 1.45, 0.55, 1)`,
       l'easing de .meeting-card-entrance et de l'entrée du bouton scanner ;
     - Raleway 700 pour le texte décoratif (la situation jugée, le badge de fin), Inter pour
       le reste — comme .font-raleway.

   L'overlay monte à z-index 13600 : au-dessus de TOUT le reste de l'app (le plus haut
   existant est la feuille d'actions Swipe à 13000), puisque la consigne produit est de
   masquer totalement la navigation pendant une partie.

   Toutes les animations sont neutralisées sous `prefers-reduced-motion` (bloc final).
   ============================================================================ */

.flag-game {
    position: fixed;
    inset: 0;
    z-index: 13600;
    display: flex;
    flex-direction: column;
    /* Repli si la feuille arrive après le premier rendu (même précaution que #auth-container). */
    background-color: var(--sy-brand-800);
    color: #fff;
    padding: max(0.75rem, env(safe-area-inset-top, 0px)) 1rem max(1rem, env(safe-area-inset-bottom, 0px));
    overscroll-behavior: contain;
    -webkit-user-select: none;
    user-select: none;
    /* Tiroir : le jeu monte depuis le bas de l'écran et redescend en sortant. */
    animation: flag-overlay-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
    will-change: transform;
}

@keyframes flag-overlay-in {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
}

/* Sortie : posée par `closeFlagGame()`, qui retire l'élément une fois l'animation finie.
   `pointer-events: none` pendant la descente — plus rien ne doit être cliquable. */
.flag-game--closing {
    animation: flag-overlay-out 0.32s cubic-bezier(0.4, 0, 1, 1) both;
    pointer-events: none;
}

@keyframes flag-overlay-out {
    from { transform: translateY(0); }
    to   { transform: translateY(100%); }
}

/* Le corps ne défile plus derrière l'overlay (rebond iOS pendant une partie). */
body.flag-game-open {
    overflow: hidden;
}

/* ------------------------------------------------------------ fond « aurora »

   Deux orbes seulement (l'écran de connexion en a trois) : le jeu reste affiché plusieurs
   minutes d'affilée, là où l'écran de connexion ne dure que quelques secondes — deux orbes
   floutés animés suffisent à l'effet pour un tiers de travail de composition en moins. */

.flag-game__bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
}

.flag-game__bg-gradient {
    position: absolute;
    inset: 0;
    background: linear-gradient(
        160deg,
        var(--sy-accent-900) 0%,
        var(--sy-accent-700) 26%,
        var(--sy-brand-700) 52%,
        var(--sy-brand-700) 74%,
        var(--sy-accent-900) 100%
    );
    background-size: 300% 300%;
    animation: flag-bg-gradient-flow 14s ease-in-out infinite;
}

.flag-game__bg-orb {
    position: absolute;
    border-radius: 50%;
    filter: blur(60px);
    opacity: 0.5;
    will-change: transform;
}

.flag-game__bg-orb--brand {
    width: min(80vmax, 560px);
    height: min(80vmax, 560px);
    top: -26%;
    right: -22%;
    background: radial-gradient(circle, rgb(var(--sy-brand-300-rgb) / 0.9) 0%, rgb(var(--sy-brand-300-rgb) / 0) 70%);
    animation: flag-bg-orb-brand 11s ease-in-out infinite alternate;
}

.flag-game__bg-orb--blue {
    width: min(70vmax, 480px);
    height: min(70vmax, 480px);
    bottom: -24%;
    left: -20%;
    background: radial-gradient(circle, rgb(var(--sy-accent-300-rgb) / 0.85) 0%, rgb(var(--sy-accent-300-rgb) / 0) 70%);
    animation: flag-bg-orb-blue 13s ease-in-out infinite alternate-reverse;
}

@keyframes flag-bg-gradient-flow {
    0%   { background-position: 0% 40%; }
    50%  { background-position: 100% 60%; }
    100% { background-position: 0% 40%; }
}

@keyframes flag-bg-orb-brand {
    0%   { transform: translate(0, 0) scale(1); }
    100% { transform: translate(-12vw, 10vh) scale(1.18); }
}

@keyframes flag-bg-orb-blue {
    0%   { transform: translate(0, 0) scale(0.92); }
    100% { transform: translate(13vw, -9vh) scale(1.14); }
}

/* Tout le contenu passe au-dessus du fond ET de la photo (elle est en z-index 0). */
.flag-game__bar,
.flag-game__stage,
.flag-game__actions {
    position: relative;
    z-index: 1;
}

/* L'en-tête domine TOUT, y compris l'écran d'accueil (`inset: 0`, z-index 2) qui le recouvrait
   et avalait les clics sur la croix : on doit pouvoir ressortir depuis les règles. */
.flag-game__bar {
    z-index: 3;
}

/* --------------------------------------------------------------- barre haute */

/* Le titre du jeu, centré, et la sortie à droite. Aucune jauge, aucun compteur de catalogue :
   le nombre de situations restantes n'a pas à peser sur une partie — l'indicateur de
   progression vit dans le tiroir Paramètres, là où l'on décide de jouer. */
.flag-game__bar {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 2.25rem;
    flex-shrink: 0;
}

.flag-game__brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    white-space: nowrap;
    /* Le générique agrandit ce bloc depuis le centre de l'écran : sans origine explicite,
       l'échelle et la translation se combinent différemment selon la largeur du titre. */
    transform-origin: center center;
    will-change: transform;
}

.flag-game__brand-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 9999px;
    background: rgb(var(--sy-white-rgb) / 0.16);
    border: 1px solid rgb(var(--sy-white-rgb) / 0.28);
    font-size: 1rem;
    flex-shrink: 0;
}

.flag-game__brand-name {
    font-family: 'Raleway', 'Inter', sans-serif;
    font-size: 0.9375rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    text-shadow: 0 1px 6px rgb(var(--sy-brand-950-rgb) / 0.4);
}

.flag-game__close {
    position: absolute;
    right: 0;
    top: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 9999px;
    background: rgb(var(--sy-white-rgb) / 0.14);
    border: 1px solid rgb(var(--sy-white-rgb) / 0.22);
    color: #fff;
    font-size: 1.25rem;
    flex-shrink: 0;
    transform: translateY(-50%);
    transition: opacity 0.35s ease, background 0.15s ease;
}

.flag-game__close:active {
    background: rgb(var(--sy-white-rgb) / 0.26);
}

/* ------------------------------------------------------------------ générique

   Le logo et le nom apparaissent en grand au centre de l'écran, marquent un temps, puis se
   réduisent pour aller se loger dans l'en-tête. L'élément animé EST celui de l'en-tête, à sa
   place définitive : c'est ce qui rend l'atterrissage exact, sans repositionnement à la fin.

   `--flag-brand-scale` est mesuré en JS (applyIntroBrandScale) pour que le titre tienne en
   une ligne quelle que soit la largeur de l'écran. */

/* Deux temps DISTINCTS, parce que l'écran d'accueil attend un geste et non un délai :
   `--intro` fait apparaître le titre au centre et l'y laisse ; `--intro-leaving`, posée au clic
   sur « Commencer », le fait remonter dans l'en-tête. Une seule animation enchaînée aurait
   renvoyé le titre en haut au bout de N secondes, que l'utilisateur ait lu ou non. */

/* `50vh - 3rem` : le brand est haut de 2,25 rem sous un padding de 0,75 rem, son centre est
   donc à ~3 rem du haut. La descente l'amène au centre optique de l'écran. */
.flag-game--intro .flag-game__brand {
    animation: flag-brand-in 0.9s cubic-bezier(0.34, 1.45, 0.55, 1) both;
}

@keyframes flag-brand-in {
    0%   { opacity: 0; transform: translateY(var(--flag-intro-shift, calc(50vh - 3rem))) scale(calc(var(--flag-brand-scale, 2) * 0.35)); }
    60%  { opacity: 1; transform: translateY(var(--flag-intro-shift, calc(50vh - 3rem))) scale(calc(var(--flag-brand-scale, 2) * 1.08)); }
    100% { opacity: 1; transform: translateY(var(--flag-intro-shift, calc(50vh - 3rem))) scale(var(--flag-brand-scale, 2)); }
}

/* Départ = état final de `flag-brand-in`, sinon le titre sauterait avant de remonter. */
.flag-game--intro-leaving .flag-game__brand {
    animation: flag-brand-land 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes flag-brand-land {
    from { opacity: 1; transform: translateY(var(--flag-intro-shift, calc(50vh - 3rem))) scale(var(--flag-brand-scale, 2)); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* ------------------------------------------------------------- écran d'accueil

   `--flag-intro-shift` (translation du titre) et `--flag-intro-top` (haut des règles) sont
   calculés en JS par `layoutIntroScreen()` : c'est l'ENSEMBLE titre + règles + bouton qui doit
   être centré verticalement, et sa hauteur dépend du texte, de la police et de l'échelle du
   titre. Les valeurs de repli placent simplement le titre au milieu, comme avant l'écran
   d'accueil, si le calcul n'a pas pu tourner. */

.flag-game__intro {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding: var(--flag-intro-top, calc(50vh + 2.5rem)) 1.5rem 1.5rem;
    overflow-y: auto;
    text-align: center;
    animation: flag-intro-panel-in 0.5s ease-out both;
    /* Après l'apparition du titre : il finit sa course avant que les règles ne se posent. */
    animation-delay: 0.75s;
}

@keyframes flag-intro-panel-in {
    from { opacity: 0; transform: translateY(1rem); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Au clic sur « Commencer », les règles s'effacent pendant que le titre remonte. */
.flag-game--intro-leaving .flag-game__intro {
    animation: none;
    opacity: 0;
    transform: translateY(0.5rem);
    pointer-events: none;
    transition: opacity 0.35s ease, transform 0.35s ease;
}

.flag-game__rules {
    list-style: none;
    margin: 0 0 1.75rem;
    padding: 0;
    max-width: 22rem;
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
}

.flag-game__rules li {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    text-align: left;
    font-size: 0.875rem;
    line-height: 1.35;
    color: rgba(255, 255, 255, 0.9);
    text-shadow: 0 1px 6px rgb(var(--sy-brand-950-rgb) / 0.4);
}

/* Aucune pastille : le chiffre et les emoji sont posés nus. `min-width` sert uniquement à
   aligner les trois lignes de texte entre elles. */
/* Les trois lignes de légende forment un bloc : resserrées entre elles, elles se lisent comme
   un ensemble plutôt que comme trois règles indépendantes, et l'écran gagne la hauteur qu'il
   faut pour rester centré sur un petit mobile (l'intro est passée de 3 à 5 lignes). */
.flag-game__rule--legend {
    font-size: 0.8125rem;
}

.flag-game__rule--legend + .flag-game__rule--legend {
    margin-top: -0.4375rem;
}

.flag-game__rule--legend strong {
    font-weight: 700;
    color: #fff;
}

/* Icône Phosphor à la place d'un emoji : elle hérite de `currentColor`, donc du blanc du
   texte. L'emoji 👤 qu'elle remplace était un glyphe monochrome sombre, illisible sur le fond
   azur — un défaut qu'aucune règle de couleur ne pouvait corriger, la teinte étant dans la
   police d'emoji elle-même. */
.flag-game__rule-icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    font-size: 1.25rem;
    line-height: 1;
}

.flag-game__rule-num,
.flag-game__rule-emoji {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    font-size: 0.9375rem;
}

.flag-game__rule-num {
    font-family: 'Raleway', 'Inter', sans-serif;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
}

/* Bouton BLANC : c'est le seul geste attendu de tout l'écran, et le dégradé azur/bleu de
   `.sy-btn--primary` se dissoudrait dans le fond aurora. */
.flag-game__start {
    min-width: 12rem;
    padding: 0.9375rem 2rem;
    border-radius: 9999px;
    border: none;
    background: var(--sy-white);
    color: var(--sy-brand-900);
    font-family: 'Raleway', 'Inter', sans-serif;
    font-size: 1rem;
    font-weight: 700;
    box-shadow: 0 10px 30px rgb(var(--sy-brand-950-rgb) / 0.45);
    transition: transform 0.15s ease, box-shadow 0.2s ease;
}

.flag-game__start:active {
    transform: scale(0.96);
    box-shadow: 0 6px 18px rgb(var(--sy-brand-950-rgb) / 0.45);
}

/* Pendant le générique, rien d'autre à l'écran. La scène et les boutons entrent quand la
   classe tombe — c'est le changement de sélecteur qui démarre leurs animations. */
.flag-game--intro .flag-game__stage,
.flag-game--intro .flag-game__photo,
.flag-game--intro .flag-game__actions {
    opacity: 0;
    pointer-events: none;
}

/* La croix apparaît avec les règles : on doit pouvoir ressortir sans jouer. */
.flag-game--intro .flag-game__close {
    opacity: 0;
    animation: flag-intro-panel-in 0.4s ease-out both;
    animation-delay: 0.9s;
}

/* Hors écran d'accueil, le panneau n'a plus rien à faire là. */
.flag-game:not(.flag-game--intro) .flag-game__intro {
    display: none;
}

/* La première photo apparaît PENDANT la remontée du titre, sur la même durée (0,7 s) : le
   décor se met en place dans le même mouvement, au lieu de surgir une fois le titre arrivé.
   Cette règle doit rester APRÈS celle de `--intro` : les deux sélecteurs pèsent deux classes,
   c'est donc l'ordre du fichier qui départage.

   Pas d'animation @keyframes ici : posée avec `both`, elle figerait son état final et
   écraserait aussi bien l'opacité de repos (0,7) que celle de la révélation (1) — une
   animation l'emporte toujours sur les déclarations et les transitions. */
.flag-game--intro-leaving .flag-game__photo {
    opacity: 0.7;
    transition: opacity 0.7s ease-out;
}

/* -------------------------------------------------------------------- scène */

/* La situation est centrée sur TOUT L'ÉCRAN, pas dans l'espace laissé libre par les boutons.
   D'où le retrait du flux : en `flex: 1`, la scène n'occupait que le haut et la phrase se
   retrouvait bien au-dessus du milieu (mesuré 233 px pour un milieu à 401).

   `pointer-events: none` parce que la scène couvre désormais toute la surface, boutons de vote
   compris : seuls ses contenus réellement interactifs la réactivent. */
.flag-game__stage {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4rem 1rem;
    pointer-events: none;
    /* Le rebond d'entrée déborde légèrement : pas de clipping, pas de barre de défilement. */
    overflow: visible;
}

.flag-game__card,
.flag-reveal {
    pointer-events: auto;
}

/* La scène ne tenant plus de place dans la colonne, c'est cette marge qui pousse la bande de
   vote en bas de l'écran. */
.flag-game__actions {
    margin-top: auto;
}

/* Vivier vide : aucune photo à afficher, le fond aurora reste seul. */
.flag-game--nophoto .flag-game__photo {
    opacity: 0;
}

.flag-game--nophoto .flag-game__stage {
    align-items: center;
}

/* Fiche profil ouverte depuis le jeu.

   `#profile-drawer-overlay` vit à z-index 10020, l'overlay du jeu à 13600 : sans cette règle
   la fiche s'ouvrirait DERRIÈRE le jeu, invisible, et l'application paraîtrait figée. On la
   remonte uniquement pendant une partie (`body.flag-game-open`), pour ne rien changer à
   l'empilement du reste de l'application.

   Le jeu reste monté dessous : refermer la fiche ramène au profil dévoilé et à ses deux
   boutons, la décision n'est pas perdue pour avoir voulu en savoir plus. */
body.flag-game-open #profile-drawer-overlay {
    z-index: 13700;
}

/* Le tap sur la photo n'est actif qu'une fois le visage net : avant, il n'y a rien à ouvrir.
   Le curseur le dit sur les pointeurs fins ; sur mobile, c'est la photo en plein écran qui
   fait l'affordance. */
.flag-game--reveal .flag-game__photo {
    cursor: pointer;
}

/* ---------------------------------------------------------- photo floutée

   Une personne se cache derrière la manche : sa photo occupe le haut de l'écran, floutée à
   50 px — assez pour qu'aucun visage ne soit identifiable, assez peu pour qu'on comprenne
   qu'il s'agit de quelqu'un. Elle change en fondu à chaque verdict rendu.

   `scale(1.25)` : un flou de 50 px étale les bords de l'image et laisserait un halo
   transparent sur le pourtour ; l'agrandissement repousse ces bords hors du cadre. */

/* Positionnée en ABSOLU et remontée jusqu'au bord physique de l'écran, en-tête compris : les
   décalages négatifs annulent le padding de `.flag-game` (safe-area en haut, 1 rem sur les
   côtés), qu'un `top: 0` classique respecterait puisqu'il se cale sur la boîte de padding.
   Le titre du jeu se lit donc PAR-DESSUS la photo, sans bande colorée au-dessus d'elle. */
/* Plein écran EN PERMANENCE, dès la première situation. Les décalages négatifs annulent le
   padding de `.flag-game` (safe-area en haut, 1 rem sur les côtés) : un `inset: 0` classique se
   calerait sur la boîte de padding et laisserait une bordure colorée tout autour.

   Pendant les situations, la photo est à **0,7 d'opacité** : le fond aurora reste perceptible
   au travers, et la personne cachée derrière la manche ne devient nette qu'à la révélation.
   L'ouverture ne joue donc plus sur la géométrie — seule l'opacité change, et il n'y a plus
   qu'une seule propriété à synchroniser avec le défloutage. */
.flag-game__photo {
    position: absolute;
    top: calc(-1 * max(0.75rem, env(safe-area-inset-top, 0px)));
    left: -1rem;
    right: -1rem;
    height: calc(100% + max(0.75rem, env(safe-area-inset-top, 0px)) + max(1rem, env(safe-area-inset-bottom, 0px)));
    overflow: hidden;
    /* Sous l'en-tête et sous la scène (tous deux en z-index 1), au-dessus du fond aurora. */
    z-index: 0;
    opacity: 0.7;
    transition: opacity 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Voile sombre sous l'en-tête : le titre et la croix sont blancs, et une photo floutée claire
   les rendrait illisibles maintenant qu'elle passe derrière eux. */
.flag-game__photo::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 30%;
    z-index: 1;
    background: linear-gradient(to bottom, rgb(var(--sy-brand-950-rgb) / 0.45), rgb(var(--sy-brand-950-rgb) / 0));
    pointer-events: none;
    transition: height 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}

.flag-game__photo-layer {
    position: absolute;
    inset: 0;
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    opacity: 0;
    filter: blur(50px);
    transform: scale(1.25);
    /* `filter` et `transform` sur 1,2 s : EXACTEMENT la durée de l'ouverture plein écran de
       `.flag-game__photo`. Le visage se révèle pendant que le cadre s'agrandit, les deux
       mouvements se terminent ensemble. Toute autre valeur ici désynchroniserait les deux. */
    transition:
        opacity 0.7s ease,
        filter 1.2s cubic-bezier(0.22, 1, 0.36, 1),
        transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}

.flag-game__photo-layer.is-active {
    opacity: 1;
}

/* Défloutage progressif du profil dévoilé. */
.flag-game--unblur .flag-game__photo-layer.is-active {
    filter: blur(0);
    transform: scale(1.02);
}

/* Plein écran : la photo prend tout l'overlay, le masque de fondu se déplace vers le bas pour
   laisser lisibles le nom et les deux décisions. */
/* Révélation : la photo était déjà plein écran, elle passe simplement à l'opacité pleine —
   en même temps que le défloutage, sur la même durée de 1,2 s. */
.flag-game--reveal .flag-game__photo {
    opacity: 1;
}

/* Le voile d'en-tête laisse place au dégradé plein écran (::after). */
.flag-game--reveal .flag-game__photo::before {
    height: 22%;
}

/* Dégradé de lisibilité du bas. Déclaré DÈS le départ à opacité nulle : créé seulement en
   `--reveal`, il n'aurait pas d'état de départ à interpoler et surgirait d'un coup. */
.flag-game__photo::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    opacity: 0;
    pointer-events: none;
    background: linear-gradient(to bottom, rgb(var(--sy-brand-950-rgb) / 0.15) 0%, rgb(var(--sy-brand-950-rgb) / 0) 38%, rgb(var(--sy-brand-950-rgb) / 0.82) 100%);
    transition: opacity 1.2s ease;
}

.flag-game--reveal .flag-game__photo::after {
    opacity: 1;
}

.flag-game__loading {
    font-size: 0.875rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.75);
    animation: flag-loading-pulse 1.4s ease-in-out infinite;
}

@keyframes flag-loading-pulse {
    0%, 100% { opacity: 0.45; }
    50%      { opacity: 1; }
}

/* Pas de cadre : la situation est posée à même le fond azur, en blanc. Le seul « contenant »
   du jeu reste l'écran lui-même — c'est ce qui donne au texte tout son poids et évite un
   deuxième cadre à l'intérieur d'un overlay qui en est déjà un. */
.flag-game__card {
    width: 100%;
    max-width: 460px;
    max-height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* `safe` : sur un contenu plus haut que l'écran (bilan final sur petit mobile), un
       centrage classique déborde vers le HAUT et rend le début inatteignable malgré
       `overflow-y: auto`. Ignoré par les moteurs qui ne le connaissent pas. */
    justify-content: safe center;
    overflow-y: auto;
    color: #fff;
    padding: 0.5rem 0.25rem;
    will-change: transform, opacity;
}

/* Entrée : rebond signature du projet (identique à .meeting-card-entrance). */
.flag-game__card--enter {
    animation: flagCardEnter 0.34s cubic-bezier(0.34, 1.45, 0.55, 1) both;
}

@keyframes flagCardEnter {
    0%   { opacity: 0; transform: translateX(34px) scale(0.92); }
    60%  { opacity: 1; transform: translateX(0) scale(1.03); }
    80%  { transform: scale(0.985); }
    100% { opacity: 1; transform: translateX(0) scale(1); }
}

/* Sortie : la carte jugée s'échappe vers la gauche avant que la suivante n'entre — sans ça,
   l'enchaînement était une simple substitution, et la révélation semblait « sauter ». */
.flag-game__card--leave {
    animation: flagCardLeave 0.22s cubic-bezier(0.4, 0, 1, 1) both;
    pointer-events: none;
}

@keyframes flagCardLeave {
    from { opacity: 1; transform: translateX(0) scale(1); }
    to   { opacity: 0; transform: translateX(-36px) scale(0.94); }
}

.flag-game__question {
    font-family: 'Raleway', 'Inter', sans-serif;
    font-size: 1.625rem;
    line-height: 1.3;
    font-weight: 700;
    text-align: center;
    text-wrap: balance;
    color: #fff;
    /* Le fond aurora bouge : une ombre portée douce garantit le contraste quel que soit
       l'endroit où passe un orbe clair. */
    text-shadow: 0 2px 12px rgb(var(--sy-brand-950-rgb) / 0.45);
}

/* ----------------------------------------------------- actions ET barres de résultat

   Les trois boutons de vote SONT les barres du résultat : à la révélation, chacun pousse
   vers le haut proportionnellement aux votes, le pourcentage s'incrémentant juste au-dessus.
   Aucun panneau de résultats n'apparaît — la réponse s'inscrit là où l'utilisateur vient
   d'appuyer, sans que son regard change de zone.

   La zone est dimensionnée dès le départ à la hauteur maximale des barres (`--flag-bar-max`),
   même quand elles sont au repos : sinon la carte remonterait d'un coup au moment du vote. */

.flag-game__actions {
    --flag-btn-min: 4.5rem;
    /* Valeur de repli seulement : `layoutBarMax()` (flagGameOverlay.js) la remplace à chaque
       situation par la place réellement libre sous la question, pourcentage compris. */
    --flag-bar-max: 13rem;
    display: flex;
    align-items: flex-end;
    gap: 0.625rem;
    flex-shrink: 0;
    /* Ce que la bande ajoute AU-DESSUS de la barre : padding du haut (8) + interligne (4) +
       ligne du pourcentage (20) = 32. Trop court, le contenu du slot déborde vers le haut et le
       pourcentage remonte d'autant — l'écart demandé sous la situation n'est plus respecté.
       En pixels et non en rem pour que `layoutBarMax()` puisse la lire directement : une custom
       property se lit telle qu'elle est déclarée, jamais résolue. */
    --flag-bar-extra: 32px;
    height: calc(var(--flag-bar-max) + var(--flag-bar-extra));
    padding-top: 0.5rem;
    /* Décollés du bas de l'écran : la bande respire et la situation reste bien au centre. */
    margin-bottom: 15vh;
    /* Transitionnable : à la révélation du profil, toute la bande se referme jusqu'à 0. */
    transition:
        height 0.7s cubic-bezier(0.22, 1, 0.36, 1),
        padding-top 0.7s cubic-bezier(0.22, 1, 0.36, 1),
        margin-bottom 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Entrée des boutons : déclenchée par la CHUTE de `--intro`, donc à la fin du générique.
   `:not(--revealing)` est indispensable : ce sélecteur est PLUS spécifique que la règle de
   fermeture plus bas, donc sans lui son `animation` l'emporterait sur le `animation: none`
   de la fermeture — et l'état final du keyframe (opacity 1) figerait la bande visible. */
.flag-game:not(.flag-game--intro):not(.flag-game--revealing) .flag-game__actions {
    animation: flag-actions-in 0.42s cubic-bezier(0.34, 1.45, 0.55, 1) both;
    animation-delay: 0.08s;
}

/* Écran de fin : plus de boutons, donc plus rien à réserver — toute la hauteur revient au
   bilan, qui est la carte la plus dense du jeu. */
.flag-game__actions:empty {
    height: 0;
    padding: 0;
    margin-bottom: 0;
}

@keyframes flag-actions-in {
    from { opacity: 0; transform: translateY(1rem); }
    to   { opacity: 1; transform: translateY(0); }
}

.flag-game__slot {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 0.25rem;
    height: 100%;
}

/* Typée en <number> pour que la hauteur s'interpole vraiment : une custom property non
   déclarée est traitée comme un jeton opaque, et le passage 0 → 0.6 sauterait d'un coup. */
@property --flag-fill {
    syntax: '<number>';
    inherits: true;
    initial-value: 0;
}

.flag-game__pct {
    height: 1.25rem;
    line-height: 1.25rem;
    text-align: center;
    font-size: 0.875rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: rgba(255, 255, 255, 0.85);
    opacity: 0;
    transform: translateY(0.375rem);
    transition:
        opacity 0.3s ease,
        transform 0.3s cubic-bezier(0.22, 1, 0.36, 1),
        height 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.flag-game__actions.is-revealed .flag-game__pct {
    opacity: 1;
    transform: translateY(0);
}

/* Le pourcentage du verdict choisi passe au premier plan. */
.flag-game__slot:has(.is-chosen) .flag-game__pct {
    color: #fff;
    font-size: 1rem;
    text-shadow: 0 1px 6px rgb(var(--sy-shadow-rgb) / 0.35);
}

.flag-game__btn {
    /* Hauteur = plancher du bouton + part des votes. C'est CETTE ligne qui transforme le
       bouton en barre ; `--flag-fill` est posé en JS à la révélation. */
    height: calc(var(--flag-btn-min) + var(--flag-fill, 0) * (var(--flag-bar-max) - var(--flag-btn-min)));
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Contenu ancré en bas : l'emoji et le libellé ne montent pas avec la barre. */
    justify-content: flex-end;
    /* Repère pour l'emoji de fond (::after), qui se cale sur toute la surface du bouton. */
    position: relative;
    gap: 0.25rem;
    padding: 0.75rem 0.5rem;
    /* Rayon FIXE, pas `9999px`. Une pilule vaut « la moitié de la plus petite dimension » : en
       grandissant, le bouton passait d'une pilule horizontale à un stade vertical, et l'arrondi
       semblait changer alors que seule la hauteur bougeait. 2,25 rem = 36 px, soit exactement
       le rayon d'une pilule à la hauteur de repos (4,5 rem) — l'état initial est donc identique
       à l'ancien, et les quatre coins ne bougent plus d'un pixel pendant la montée. */
    border-radius: 2.25rem;
    font-family: inherit;
    font-size: 0.8125rem;
    font-weight: 700;
    color: #fff;
    border: 1px solid rgb(var(--sy-white-rgb) / 0.22);
    background: rgb(var(--sy-white-rgb) / 0.12);
    overflow: hidden;
    transition:
        height 0.8s cubic-bezier(0.22, 1, 0.36, 1),
        transform 0.15s ease,
        box-shadow 0.2s ease,
        opacity 0.2s ease;
}

.flag-game__btn:active:not(:disabled) {
    transform: scale(0.94);
}

.flag-game__btn:disabled {
    cursor: default;
}

/* Enfoncement au vote, repris de @keyframes buttonPush (style.css). Sur `scale` uniquement :
   la montée de la barre est une transition de `height`, les deux ne se marchent pas dessus. */
.flag-game__btn.is-pushed {
    animation: flag-btn-push 0.3s cubic-bezier(0.34, 1.45, 0.55, 1);
}

@keyframes flag-btn-push {
    0%   { transform: scale(1); }
    45%  { transform: scale(0.88); }
    100% { transform: scale(1); }
}

/* Pendant la révélation, les barres non choisies restent parfaitement lisibles : elles
   portent désormais une information (leur pourcentage). Seul le choix de l'utilisateur est
   mis en avant, par un halo — pas par l'effacement des autres. */
.flag-game__actions.is-revealed .flag-game__btn:not(.is-chosen) {
    opacity: 0.85;
}

.flag-game__btn-emoji,
.flag-game__btn-label {
    /* Au-dessus de l'emoji de fond, qui est en z-index 0. */
    position: relative;
    z-index: 1;
    transition: opacity 0.3s ease;
}

/* L'emoji de réaction remplace le contenu du bouton : la pastille et le libellé s'effacent
   pendant qu'il apparaît. Les deux autres boutons gardent le leur — eux n'ont pas d'emoji. */
.flag-game__actions.is-revealed .flag-game__btn.is-chosen .flag-game__btn-emoji,
.flag-game__actions.is-revealed .flag-game__btn.is-chosen .flag-game__btn-label {
    opacity: 0;
}

.flag-game__btn-emoji {
    font-size: 1.5rem;
    line-height: 1;
}

/* ------------------------------------------------- emoji de fond au moment du verdict

   Le verdict rendu s'affiche en grand DANS le bouton pressé : une réaction, pas une icône.
   Plafonné à 50 % d'opacité — au-delà, il concurrence le pourcentage et le libellé, qui sont
   l'information utile. `overflow: hidden` (déclaré plus haut) le recadre quand la barre est
   encore basse. */

/* Fichiers SVG (Noto Emoji, Apache 2.0) rapatriés dans `images/UI/flags/`, et NON le caractère
   Unicode : les polices emoji système sont bitmap (CBDT/sbix), donc visiblement pixellisées dès
   qu'on les agrandit à la taille d'un bouton. Un SVG reste net à n'importe quelle échelle, et le
   rendu est identique sur toutes les plateformes — Android comme iOS. */
.flag-game__btn--green { --flag-btn-face: url('../../images/UI/flags/flag_green.svg'); }
.flag-game__btn--beige { --flag-btn-face: url('../../images/UI/flags/flag_beige.svg'); }
.flag-game__btn--red   { --flag-btn-face: url('../../images/UI/flags/flag_red.svg'); }

.flag-game__btn::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    /* `cover` : l'image couvre toute la surface du bouton et déborde sur la dimension la plus
       longue, recadrée par l'`overflow: hidden`. Les SVG portent un `viewBox` sans dimensions
       fixes, ils se redimensionnent donc exactement — plus rien à compenser, ni la cadratine
       d'un glyphe ni le padding du bouton, contrairement au rendu par police. */
    background-image: var(--flag-btn-face);
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    opacity: 0;
    transform: scale(0.55);
    pointer-events: none;
    transition:
        opacity 0.45s ease,
        transform 0.55s cubic-bezier(0.34, 1.45, 0.55, 1);
}

/* Seul le bouton VOTÉ réagit : c'est le retour au geste, pas une décoration des trois barres. */
.flag-game__actions.is-revealed .flag-game__btn.is-chosen::after {
    opacity: 0.5;
    transform: scale(1);
}

/* Il disparaît avec la bande, sans quoi il resterait visible pendant que le bouton se referme. */
.flag-game--revealing .flag-game__btn::after {
    opacity: 0;
}

/* Fonds OPAQUES : testés translucides sur le fond azur, les trois teintes viraient au
   bleu azur / doré / rose et le code couleur du jeu — vert, beige, rouge — n'était plus
   lisible d'un coup d'œil. C'est l'information la plus importante de l'écran. */
.flag-game__btn--green {
    background: linear-gradient(180deg, var(--sy-success-500), var(--sy-success-700));
    border-color: rgba(187, 247, 208, 0.6);
    box-shadow: 0 6px 18px rgb(var(--sy-success-700-rgb) / 0.45);
}

.flag-game__btn--beige {
    background: linear-gradient(180deg, var(--sy-warning-600), #a16207);
    border-color: rgb(var(--sy-warning-200-rgb) / 0.6);
    box-shadow: 0 6px 18px rgba(161, 98, 7, 0.45);
}

.flag-game__btn--red {
    background: linear-gradient(180deg, var(--sy-danger-500), var(--sy-danger-700));
    border-color: rgb(var(--sy-danger-200-rgb) / 0.6);
    box-shadow: 0 6px 18px rgb(var(--sy-danger-700-rgb) / 0.45);
}

.flag-game__btn--green.is-chosen { box-shadow: 0 0 0 3px rgba(134, 239, 172, 0.75), 0 6px 20px rgb(var(--sy-success-600-rgb) / 0.45); }
.flag-game__btn--beige.is-chosen { box-shadow: 0 0 0 3px rgb(var(--sy-warning-300-rgb) / 0.75), 0 6px 20px rgb(var(--sy-warning-700-rgb) / 0.45); }
.flag-game__btn--red.is-chosen   { box-shadow: 0 0 0 3px rgb(var(--sy-danger-300-rgb) / 0.75), 0 6px 20px rgb(var(--sy-danger-600-rgb) / 0.45); }

/* ============================================================ profil dévoilé

   Vue finale d'une manche : la photo est déjà en plein écran (voir plus haut), il ne reste
   qu'à poser le nom, l'accroche et les deux décisions. Le vocabulaire est celui de la page
   Swipe — même dégradé pour le like, même « Passer » sombre — sans en importer les styles,
   qui sont pilotés par les variables du geste de swipe. */

/* La situation s'efface AVEC la bande de vote : mêmes 0,7 s, même easing. Elle était remplacée
   d'un coup au moment du plein écran, ce qui la faisait disparaître bien après les boutons.

   `animation: none` est nécessaire : `flagCardEnter` est posée avec `both` sur
   `.flag-game__card--enter`, et l'état final d'une animation l'emporte sur une transition.
   Le sélecteur compte deux classes contre une, il gagne donc sur la règle d'entrée. */
.flag-game--revealing .flag-game__card {
    animation: none;
    opacity: 0;
    transform: translateY(1rem);
    pointer-events: none;
    transition:
        opacity 0.7s ease,
        transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Révélation : la bande de vote se referme jusqu'à 0 px au lieu de disparaître d'un coup.
   Les trois boutons rétrécissent AVEC elle — mettre `--flag-btn-min` et `--flag-bar-max` à 0
   fait retomber leur `height` calculée à zéro, et leur propre transition s'en charge : la
   bande ne se contente donc pas de les rogner, ils s'effacent avec elle.

   `animation: none` est indispensable : `flag-actions-in` est posée avec `both`, et l'état
   final d'une animation l'emporte sur une transition — sans ça, l'opacité resterait figée à 1.

   La règle vise `--revealing`, posée dès le début de la séquence et jamais retirée : la bande
   se referme donc pendant que la photo s'installe et se défloute, libérant l'écran à l'avance. */
.flag-game--revealing .flag-game__actions {
    animation: none;
    --flag-btn-min: 0rem;
    --flag-bar-max: 0rem;
    height: 0;
    padding-top: 0;
    margin-bottom: 0;
    overflow: hidden;
    pointer-events: none;
}

/* Pas de fondu : les boutons doivent RÉTRÉCIR jusqu'à disparaître, pas s'effacer avant que la
   bande ne soit refermée. `overflow: hidden` + hauteur 0 suffisent à les faire disparaître. */

/* Padding et bordure sont incompressibles : sans les annuler, la hauteur d'un bouton plancherait
   a 26 px (12 + 12 + 2) et les derniers pixels seraient ROGNES par le conteneur au lieu de
   disparaitre avec lui. Mesure en production avant correction : bande 0 px, bouton 26 px. */
.flag-game--revealing .flag-game__btn {
    padding-top: 0;
    padding-bottom: 0;
    border-top-width: 0;
    border-bottom-width: 0;
    transition:
        height 0.7s cubic-bezier(0.22, 1, 0.36, 1),
        padding 0.7s cubic-bezier(0.22, 1, 0.36, 1),
        border-width 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.flag-game--revealing .flag-game__pct {
    height: 0;
    opacity: 0;
}

/* SURTOUT PAS de `position: relative` ici : la scène est en `absolute; inset: 0` et le
   redéclarer la renverrait dans le flux, donc juste sous l'en-tête — le verdict, le nom et les
   deux boutons remontaient alors en haut de l'écran. Seul l'alignement change. */
.flag-game--reveal .flag-game__stage {
    z-index: 2;
    align-items: flex-end;
    padding-bottom: 0.5rem;
}

.flag-reveal {
    width: 100%;
    max-width: 460px;
    text-align: center;
    /* Retardée : le nom et les deux décisions arrivent une fois la photo nette et ouverte, pas
       par-dessus une image encore floue et en train de s'agrandir. */
    animation: flag-reveal-in 0.5s cubic-bezier(0.34, 1.45, 0.55, 1) both;
    animation-delay: 0.85s;
}

/* `pointer-events` dans les keyframes : avec `both`, la valeur de `from` s'applique DÈS le
   départ, donc pendant tout le délai. Sans ça, Like et Passer seraient invisibles mais déjà
   cliquables — un tap malheureux pendant l'ouverture likerait quelqu'un qu'on n'a pas vu. */
@keyframes flag-reveal-in {
    from { opacity: 0; transform: translateY(1.5rem); pointer-events: none; }
    to   { opacity: 1; transform: translateY(0); pointer-events: auto; }
}

.flag-reveal__verdict {
    font-size: 0.8125rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.85);
    text-shadow: 0 1px 8px rgb(var(--sy-shadow-rgb) / 0.6);
    margin-bottom: 0.375rem;
}

.flag-reveal__name {
    font-family: 'Raleway', 'Inter', sans-serif;
    font-size: 1.75rem;
    font-weight: 700;
    color: #fff;
    text-shadow: 0 2px 12px rgb(var(--sy-shadow-rgb) / 0.6);
}

.flag-reveal__age {
    margin-left: 0.5rem;
    font-size: 1.25rem;
    font-weight: 400;
    color: rgba(255, 255, 255, 0.8);
}

.flag-reveal__actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

.flag-reveal__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    min-width: 8rem;
    padding: 0.875rem 1.5rem;
    border-radius: 9999px;
    font-family: inherit;
    font-size: 0.9375rem;
    font-weight: 700;
    color: #fff;
    border: none;
    transition: transform 0.15s ease, box-shadow 0.18s ease, opacity 0.2s ease;
}

.flag-reveal__btn:active:not(:disabled) {
    transform: scale(0.96);
}

.flag-reveal__btn:disabled {
    opacity: 0.55;
    cursor: default;
}

.flag-reveal__btn--like {
    /* Même dégradé que .swipe-like-btn. */
    background: linear-gradient(to top right, var(--sy-brand-500), var(--sy-accent-600));
    box-shadow: 0 6px 20px rgb(var(--sy-brand-500-rgb) / 0.45);
}

.flag-reveal__btn--pass {
    background: rgb(var(--sy-brand-950-rgb) / 0.55);
    border: 1px solid rgb(var(--sy-white-rgb) / 0.3);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

.flag-reveal__btn i {
    font-size: 1.125rem;
}

/* Le bouton d'en-tête du Tribunal des Flags (`.header-flag-game-btn`) a été RETIRÉ le
   18/09/2026 : le point d'entrée vit désormais dans le HUD de la page Swipe
   (`#swipe-flag-game-btn`), stylé par `.browse-view-hud-btn--flag` dans `style.css` avec le
   même dégradé signature. Il n'y a plus de mesure de débordement ni de repli `is-compact` :
   dans le HUD la pastille a une taille fixe, et c'est `.browse-view-right-stack` qui la décale
   quand la bascule d'affichage apparaît (Premium Plus).
   Cf. Documentations/Gamification/tribunal_des_flags.md */


/* ================================================================ badges profil */

.flag-affinity__badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
}

.flag-affinity__badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.3125rem 0.6875rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 700;
    border: 1px solid transparent;
    /* Entrée staggerée, même easing que les pilules de titre de section. */
    animation: flag-affinity-badge-in 0.32s cubic-bezier(0.34, 1.45, 0.55, 1) both;
    animation-delay: calc(var(--flag-row, 0) * 70ms);
}

@keyframes flag-affinity-badge-in {
    from { opacity: 0; transform: scale(0.82); }
    to   { opacity: 1; transform: scale(1); }
}

.flag-affinity__badge--match {
    background: linear-gradient(90deg, var(--sy-success-50), var(--sy-success-100));
    color: rgb(var(--sy-success-700-ink-rgb));
    border-color: var(--sy-success-200);
}

.flag-affinity__badge--neutral {
    background: linear-gradient(90deg, var(--sy-brand-50), var(--sy-brand-100));
    color: rgb(var(--sy-brand-700-ink-rgb));
    border-color: var(--sy-brand-200);
}

.flag-affinity__clash {
    margin-top: 0.625rem;
    padding: 0.6875rem 0.8125rem;
    border-radius: 0.875rem;
    background: linear-gradient(135deg, var(--sy-violet-50), var(--sy-neutral-50));
    border: 1px solid var(--sy-brand-100);
    animation: flag-affinity-badge-in 0.34s cubic-bezier(0.22, 1, 0.36, 1) both;
    animation-delay: 0.2s;
}

/* Deuxième ligne : l'accord. Teinte verte au lieu de l'azur neutre, pour que les deux exemples
   se distinguent d'un coup d'oeil sans avoir à lire les verdicts, et décalage d'entrée pour
   qu'ils arrivent l'un après l'autre. */
.flag-affinity__clash--accord {
    background: linear-gradient(135deg, var(--sy-success-50), var(--sy-neutral-50));
    border-color: #bbf7d0;
    animation-delay: 0.28s;
}

.flag-affinity__clash-q {
    display: block;
    font-size: 0.8125rem;
    font-style: italic;
    color: rgb(var(--sy-neutral-700-ink-rgb));
    line-height: 1.4;
}

.flag-affinity__clash-vs {
    display: block;
    margin-top: 0.3125rem;
    font-size: 0.6875rem;
    font-weight: 600;
    color: rgb(var(--sy-neutral-500-ink-rgb));
}

.flag-affinity__meta {
    margin-top: 0.5rem;
    font-size: 0.6875rem;
    color: rgb(var(--sy-neutral-400-ink-rgb));
}

/* --------------------------------------------------------- badge slide swipe */

.flag-swipe-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    align-self: flex-start;
    padding: 0.1875rem 0.5625rem;
    margin-bottom: 0.3125rem;
    border-radius: 9999px;
    font-size: 0.6875rem;
    font-weight: 700;
    color: #fff;
    /* Fond OPAQUE : le bas du footer de slide est blanc, une pastille translucide y perdrait
       tout contraste avec son texte blanc (cf. .swipe-slide__meta, style.css). */
    animation: flag-affinity-badge-in 0.3s cubic-bezier(0.34, 1.45, 0.55, 1) both;
}

.flag-swipe-badge--match {
    background: linear-gradient(90deg, var(--sy-success-600), var(--sy-success-700));
    box-shadow: 0 2px 8px rgb(var(--sy-success-600-rgb) / 0.4);
}

/* ------------------------------------------------------------ accroche chat */

.flag-chat-opener {
    display: flex;
    align-items: stretch;
    gap: 0.375rem;
    margin-bottom: 0.5rem;
    animation: flag-chat-opener-in 0.34s cubic-bezier(0.34, 1.45, 0.55, 1) both;
}

@keyframes flag-chat-opener-in {
    from { opacity: 0; transform: translateY(0.625rem) scale(0.96); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.flag-chat-opener__btn {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    text-align: left;
    padding: 0.5625rem 0.8125rem;
    border-radius: 1.125rem;
    background: linear-gradient(135deg, var(--sy-violet-50), var(--sy-accent-50));
    border: 1px solid var(--sy-brand-200);
    color: rgb(var(--sy-brand-900-ink-rgb));
    font-size: 0.75rem;
    line-height: 1.35;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}

.flag-chat-opener__btn:active {
    transform: scale(0.98);
    background: linear-gradient(135deg, var(--sy-violet-100), var(--sy-accent-100));
}

.flag-chat-opener__icon {
    font-size: 1rem;
    flex-shrink: 0;
    color: rgb(var(--sy-brand-600-ink-rgb));
}

.flag-chat-opener__text {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.flag-chat-opener__dismiss {
    flex-shrink: 0;
    width: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 9999px;
    color: rgb(var(--sy-neutral-400-ink-rgb));
    font-size: 0.875rem;
    transition: color 0.15s ease, background 0.15s ease;
}

.flag-chat-opener__dismiss:active {
    color: rgb(var(--sy-neutral-600-ink-rgb));
    background: var(--sy-neutral-100);
}

/* ==================================================== accessibilité mouvement

   Même politique que le reste du projet (cf. .sy-section-title-wrap, aurora, bordure
   dégradée) : le fond se fige et toutes les entrées deviennent instantanées. Les états
   restent lisibles — rien ne dépend d'une animation pour être visible. */

@media (prefers-reduced-motion: reduce) {
    .flag-game,
    .flag-game--closing,
    .flag-game__bar,
    .flag-game__actions,
    .flag-game__card--enter,
    .flag-game__card--leave,
    .flag-game--intro .flag-game__brand,
    .flag-game--intro-leaving .flag-game__brand,
    .flag-game__intro,
    .flag-game--intro .flag-game__close,
    .flag-game__btn.is-pushed,
    .flag-affinity__badge,
    .flag-affinity__clash,
    .flag-swipe-badge,
    .flag-chat-opener {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }

    .flag-game__bg-gradient,
    .flag-game__bg-orb,
    .flag-game__loading {
        animation: none !important;
    }

    .flag-game__bg-gradient {
        background-size: 100% 100%;
        background-position: 50% 50%;
    }

    /* Les barres prennent DIRECTEMENT leur hauteur finale et les pourcentages apparaissent
       d'un coup : c'est le mouvement qu'on supprime, jamais l'information. */
    .flag-game__btn,
    .flag-game__btn::after,
    .flag-game__btn-emoji,
    .flag-game__btn-label,
    .flag-game__pct,
    .flag-game__actions,
    .flag-game__photo,
    .flag-game__photo-layer,
    .flag-game--revealing .flag-game__card {
        transition: none !important;
    }

    .flag-game:not(.flag-game--intro) .flag-game__photo,
    .flag-reveal {
        animation: none !important;
        animation-delay: 0s !important;
        opacity: 1 !important;
        transform: none !important;
    }

    .flag-game__photo::before,
    .flag-game__photo::after {
        transition: none !important;
    }
}
