/* ═══════════════════════════════════════════════════════════
   jeux.css — grille des jeux (calquée sur .icons) + lecteur
═══════════════════════════════════════════════════════════ */

/* Grille (mêmes règles que .icons) */
.jeux {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 22px;
}
.jeux a {
  flex-basis: calc(20% - 22px);
  max-width: calc(20% - 22px);
  display: flex; align-items: center; justify-content: center;
  transition: filter 0.25s, transform 0.2s;
}
.jeux a:hover {
  filter: drop-shadow(0 0 10px rgba(240,235,220,0.7)) brightness(1.2);
  transform: translateY(-2px);
}
.jeux a:active { transform: scale(0.97); }
.jeux img { max-width: 100%; height: auto; display: block; border-radius: 22%; }
@media (max-width: 720px) {
  .jeux a {
    flex-basis: calc(33.333% - 22px);
    max-width: calc(33.333% - 22px);
  }
}

/* ───────────── Lecteur de jeu ───────────── */

.jeu-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.jeu-retour, .jeu-fullscreen {
  background: rgba(0,0,0,0.55);
  border: 1px solid rgba(240,235,220,0.18);
  border-radius: 999px;
  padding: 7px 16px;
  color: rgba(240,235,220,0.85);
  font-family: monospace;
  font-size: 12px;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s;
}
.jeu-retour:hover, .jeu-fullscreen:hover {
  background: rgba(240,235,220,0.15);
  border-color: rgba(240,235,220,0.4);
}
.jeu-titre {
  font-family: monospace;
  font-size: 14px;
  color: rgba(240,235,220,0.85);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin: 0;
  flex: 1;
  text-align: center;
}

/* Cadre : hugge son contenu, pas de min-height, pas de centrage flex */
.jeu-cadre {
  background: rgba(0,0,0,0.55);
  border: 1px solid rgba(240,235,220,0.18);
  border-radius: 22px;
  padding: 14px;
  overflow: hidden;
}

/* Container Ruffle : position relative pour que le player en absolute fill.

   jeu-hauteur-marker (13/09/2026) — BUG 20260913-210801, volet « fiche jeu ».
   LE CADRE NE SE SOUCIAIT QUE DE LA LARGEUR. « width:100% + aspect-ratio 4/3 »
   décide de la hauteur à partir de la largeur, sans jamais regarder si cette
   hauteur tient dans l'écran. Mesuré sur un téléphone couché, 699 x 274 : le
   cadre faisait 641 x 481 px, dont 49 px seulement au-dessus de la ligne de
   flottaison. Le jeu était injouable sans passer par « Plein écran ».

   max-height borne par la place réelle. Quand elle mord, le rapport 4/3 est
   abandonné et le cadre devient large et bas — le SWF, lui, garde ses
   proportions à l'intérieur et se pose entre deux bandes noires. C'est le bon
   compromis : mieux vaut un jeu entier et petit qu'un jeu grand dont on ne
   voit pas la moitié.

   La variable permet à la fiche de dire, par palier, combien de place prend ce
   qu'il y a au-dessus du cadre (barre, titre, badges, boutons). */
#ruffle-container {
  --jeu-entete: 210px;
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  max-height: calc(100svh - var(--jeu-entete));
  margin-inline: auto;
  background: #000;
  border-radius: 14px;
  overflow: hidden;
}
/* Couché et bas de plafond : ce qui entoure le jeu se resserre, donc la place
   pour le jeu grandit d'autant. Le résumé et les badges s'effacent — sur un
   écran haut comme trois lignes, ils coûtent plus qu'ils n'apprennent, et ils
   restent lisibles dans la grille. Le titre et les deux boutons restent : sans
   « Plein écran » à portée, la fiche n'aurait plus d'issue.

   ⚠️ --jeu-entete: 128px est une ESTIMATION, pas une mesure. Le miroir local
   n'a pas les .swf, je n'ai donc pas pu afficher une vraie fiche Flash ici : le
   nombre vient de l'addition des éléments qui restent (barre 48 + en-tête ~44 +
   marges ~36). S'il est trop bas, le jeu déborde un peu ; trop haut, il reste
   une bande noire. C'est une seule valeur à retoucher, c'est pour ça qu'elle
   est une variable. */
@media (orientation: landscape) and (max-height: 480px) {
  #ruffle-container { --jeu-entete: 128px; }
  .jeu-fiche { display: none; }
  .jeu-header { margin-bottom: 6px; }
  .jeu-titre { font-size: 18px; }
}

/* Le <ruffle-player> remplit tout le container.
   !important parce que Ruffle pose ses propres width/height inline
   une fois le SWF chargé. */
#ruffle-container > * {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  display: block !important;
  border-radius: 14px;
  max-width: none;
}

/* Plein écran */
.jeu-cadre:fullscreen {
  background: #000;
  padding: 0;
  border-radius: 0;
}
.jeu-cadre:fullscreen #ruffle-container {
  width: 100vw;
  height: 100vh;
  aspect-ratio: auto;
  border-radius: 0;
}
/* jeu-iframe-size-marker
   Un <iframe> sans width/height retombe sur 300x150.
   Les jeux HTML5 doivent occuper tout le cadre. */
/* jeu-cadre-border-box-marker (05/09/2026)
   Encadrement asymétrique, tous écrans confondus.
   .jeu-cadre était en content-box (défaut) : width:100% donnait la largeur du
   contenu, à laquelle s'ajoutaient 14+14 de padding et 1+1 de bordure. Le cadre
   dépassait donc de 30px la zone de .bloc-page. Comme il démarre après les 14px
   de marge gauche, tout le dépassement partait à droite :
     393px de large  ->  cadre de 14 à 409, marge gauche 14, marge droite -16
   body{overflow-x:hidden} masquait le débordement en rognant simplement le bord
   droit — d'où un cadre visible à gauche et coupé à droite.
   Mesuré identique en 775px de large : -16 également. */
.jeu-cadre{
  width:100%;
  box-sizing:border-box;
}
.jeu-iframe{
  display:block;
  width:100%;
  height:min(76vh, 780px);
  min-height:420px;
  border:0;
  border-radius:14px;
  background:#07201b;
}
@media (max-width:700px){
  .jeu-iframe{
    height:min(84vh, 760px);
    min-height:520px;
  }

}

/* jeu-fit-viewport-marker (05/09/2026)
   BUG 20260819-141949 : plateau mahjong tronqué en bas sur mobile.
   Les hauteurs ci-dessus (min(84vh,760px) + min-height) ne retranchaient ni
   la topbar fixe (56px), ni le .jeu-header, ni les paddings .bloc-page /
   .jeu-cadre. Mesuré en 480x858 : bas du .bloc-page à 881px pour 858px de
   viewport, soit 23px rognés par .jeu-cadre{overflow:hidden}.

   On cale donc le lecteur sur la hauteur réellement visible et on laisse
   flex répartir : plus aucune constante à maintenir, et le .jeu-header peut
   passer sur deux lignes sans rien tronquer. 100dvh (et non 100vh) pour
   suivre la barre d'URL mobile.

   Les règles au-dessus restent le repli pour un moteur sans :has(). */
.bloc-page:has(> .jeu-cadre > .jeu-iframe){
  display:flex;
  flex-direction:column;
  height:calc(100dvh - var(--topbar-h, 56px));
  box-sizing:border-box;
}
.bloc-page:has(> .jeu-cadre > .jeu-iframe) > .jeu-header{
  flex:0 0 auto;
}
.jeu-cadre:has(> .jeu-iframe){
  flex:1 1 auto;
  min-height:0;          /* sans ça un enfant flex refuse de descendre sous sa taille de contenu */
  display:flex;
}
.jeu-cadre:has(> .jeu-iframe) > .jeu-iframe{
  flex:1 1 auto;
  height:auto;
  min-height:0;          /* neutralise le min-height:420/520px du repli */
}

/* ═══ jeux-fiches-marker (12/09/2026) — la fiche du jeu, au-dessus du cadre ═══
   « des descriptions et des images comme les films ». Même hiérarchie que la
   fiche média de Vision : une étiquette de genre, puis le résumé en blanc avec
   une ombre portée (descr-blanche-marker : le blanc pur sur un fond clair se
   lit mal, c'est l'ombre qui rend le contraste que le gris donnait). */
.jeu-fiche {
  margin: 2px 0 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 760px;
}
.jeu-genre {
  align-self: flex-start;
  padding: 3px 10px;
  border-radius: 999px;
  font-family: monospace;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(240, 235, 220, .85);
  background: rgba(0, 0, 0, .55);
  border: 1px solid rgba(255, 255, 255, .28);
}
.jeu-desc {
  margin: 0;
  font-size: 15px;
  line-height: 1.55;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}
@media (max-width: 720px) {
  .jeu-desc { font-size: 14px; }
}


/* ══════════════════════════════════════════════════════════════════════════
   jeux-badges-marker (13/09/2026) — BUG 20260913-144146
   Deux formes pour le même objet : la pastille complète (icône + mot) sur la
   fiche du jeu, la puce (icône seule) sur la tuile de la grille.
   ══════════════════════════════════════════════════════════════════════════ */

.jeu-badges { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: middle; }

.jeu-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .5);
  border: 1px solid rgba(240, 235, 220, .22);
  color: rgba(240, 235, 220, .85);
  font-family: monospace;
  font-size: 11px;
  white-space: nowrap;
}
.jeu-badge svg { width: 13px; height: 13px; flex-shrink: 0; }

/* Les deux badges techniques se distinguent des badges d'usage : ils disent
   d'où vient le jeu, pas comment on y joue. */
.jeu-badge--cizi { border-color: rgba(120, 220, 190, .55); color: #9fe8d2; }
.jeu-badge--swf  { border-color: rgba(255, 200, 120, .5);  color: #ffcf8a; }

/* ── Sur la tuile : icônes seules, en bas à droite ──
   Le libellé du jeu occupe déjà le bas de la vignette (styles/icons.css) : les
   puces se posent dans le coin, au-dessus, sans lui disputer la ligne. À cette
   taille le mot serait illisible de toute façon. */
.icons a { position: relative; }
.jeu-badges--puce {
  position: absolute;
  right: 5%;
  top: 5%;
  flex-direction: column;
  gap: 3px;
  pointer-events: none;
}
.jeu-badges--puce .jeu-badge {
  padding: 3px;
  border-radius: 50%;
  background: rgba(0, 0, 0, .62);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.jeu-badges--puce .jeu-badge svg { width: 11px; height: 11px; }
.jeu-badges--puce .jeu-badge-mot { display: none; }

/* En liste et en détail, l'image tombe à 28 px : les puces n'y tiendraient pas,
   et la ligne a de la place pour les mots. On repasse donc en pastilles. */
.icons.mode-liste .jeu-badges--puce,
.icons.mode-detail .jeu-badges--puce {
  position: static;
  flex-direction: row;
  margin-left: auto;
  padding-right: 10px;
}
.icons.mode-liste .jeu-badges--puce .jeu-badge,
.icons.mode-detail .jeu-badges--puce .jeu-badge {
  border-radius: 999px;
  padding: 2px 8px 2px 6px;
}
.icons.mode-liste .jeu-badges--puce .jeu-badge-mot,
.icons.mode-detail .jeu-badges--puce .jeu-badge-mot { display: inline; }

/* Sous 420 px, une tuile fait moins de 80 px : on ne garde que le badge
   technique, le premier de la liste. Trois puces empilées mangeraient la
   vignette. */
@media (max-width: 420px) {
  .icons.mode-icones .jeu-badges--puce .jeu-badge:not(:first-child) { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   jeux-etats-marker (19/09/2026) — BUG 20260913-150531-22f9a7
   L'ÉTAT D'ANALYSE : cinq valeurs, une couleur chacune, et une barre de
   filtres au-dessus de la grille.

   POURQUOI LA COULEUR PLUTÔT QU'UNE ICÔNE SEULE. Les badges d'usage se
   distinguent par leur dessin ; l'état, lui, se lit en balayant la grille du
   regard, sans s'arrêter sur chaque tuile. La couleur est le seul signal qui
   fonctionne à cette vitesse. Chaque pastille garde son icône ET son mot
   partout où la place existe — la couleur ne porte jamais l'information toute
   seule, sinon huit pour cent des hommes ne verraient rien.
   ══════════════════════════════════════════════════════════════════════════ */

.jeu-etat {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .5);
  border: 1px solid rgba(240, 235, 220, .28);
  color: rgba(240, 235, 220, .85);
  font-family: monospace;
  font-size: 11px;
  white-space: nowrap;
  vertical-align: middle;
}
.jeu-etat svg { width: 13px; height: 13px; flex-shrink: 0; }

.jeu-etat--a-analyser     { border-color: rgba(200, 200, 205, .45); color: #c9c9ce; }
.jeu-etat--ok-pc          { border-color: rgba(120, 200, 255, .60); color: #8fccff; }
.jeu-etat--ok-portable    { border-color: rgba(120, 225, 160, .60); color: #8fe3ad; }
.jeu-etat--a-retravailler { border-color: rgba(255, 200, 110, .60); color: #ffcf82; }
.jeu-etat--inexploitable  { border-color: rgba(255, 130, 130, .60); color: #ff9090; }

/* Sur la tuile : au coin HAUT GAUCHE, en face des badges techniques qui
   occupent le coin droit. Les deux ne se chevauchent donc jamais, quelle que
   soit la largeur. */
.jeu-etat--puce {
  position: absolute;
  left: 5%;
  top: 5%;
  padding: 3px;
  border-radius: 50%;
  background: rgba(0, 0, 0, .62);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  pointer-events: none;
}
.jeu-etat--puce svg { width: 11px; height: 11px; }
.jeu-etat--puce .jeu-etat-mot { display: none; }

/* En liste et en détail, la place existe : le mot revient, et la pastille
   reprend sa place dans le flux au lieu de flotter sur la vignette. */
.icons.mode-liste .jeu-etat--puce,
.icons.mode-detail .jeu-etat--puce {
  position: static;
  border-radius: 999px;
  padding: 2px 8px 2px 6px;
  margin-left: 10px;
}
.icons.mode-liste .jeu-etat--puce .jeu-etat-mot,
.icons.mode-detail .jeu-etat--puce .jeu-etat-mot { display: inline; }

/* ── La barre de filtres ────────────────────────────────────────────────── */
.jeux-filtres {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  margin: 0 auto 14px;
  padding: 0 12px;
  max-width: 1100px;
}
.jeux-filtres:empty { display: none; }   /* sans JavaScript, rien ne s'affiche */

.jeu-filtre {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .45);
  border: 1px solid rgba(240, 235, 220, .22);
  color: rgba(240, 235, 220, .8);
  font-family: monospace;
  font-size: 12px;
  cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.jeu-filtre:hover { border-color: rgba(240, 235, 220, .5); color: #fff; }
.jeu-filtre.on { background: rgba(240, 235, 220, .92); color: #14161a; border-color: #fff; font-weight: 700; }
/* Le compteur : lisible, mais jamais plus fort que le mot qu'il accompagne. */
.jeu-filtre-n {
  font-variant-numeric: tabular-nums;
  opacity: .62;
  padding-left: 1px;
}
.jeu-filtre.on .jeu-filtre-n { opacity: .55; }
.jeu-filtre--ok-pc          { border-color: rgba(120, 200, 255, .45); }
.jeu-filtre--ok-portable    { border-color: rgba(120, 225, 160, .45); }
.jeu-filtre--a-retravailler { border-color: rgba(255, 200, 110, .45); }
.jeu-filtre--inexploitable  { border-color: rgba(255, 130, 130, .45); }

/* display:none et non visibility : une tuile masquée ne doit pas laisser son
   trou dans la grille, sinon filtrer donnerait une page pleine de vides. */
.icons a.jeu-filtre-hors { display: none !important; }

.jeux-filtres-vide {
  text-align: center;
  margin: 0 0 16px;
  color: rgba(240, 235, 220, .55);
  font-family: monospace;
  font-size: 13px;
}

/* ── L'éditeur, sur la fiche du jeu ─────────────────────────────────────── */
.jeu-classer {
  max-width: 900px;
  margin: 0 auto 14px;
  border: 1px solid rgba(240, 235, 220, .2);
  border-radius: 12px;
  background: rgba(0, 0, 0, .35);
}
.jeu-classer > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  cursor: pointer;
  font-family: monospace;
  font-size: 13px;
  color: rgba(240, 235, 220, .88);
  list-style: none;
}
.jeu-classer > summary::-webkit-details-marker { display: none; }
.jeu-classer > summary::after {
  content: "▾";
  margin-left: auto;
  opacity: .6;
  transition: transform .15s;
}
.jeu-classer[open] > summary::after { transform: rotate(180deg); }
/* Dans le repli du résumé, la pastille reprend son mot : la vignette n'est pas
   là pour l'expliquer, et « ▾ » seul ne dirait pas dans quel état on est. */
.jeu-classer > summary .jeu-etat--puce {
  position: static;
  border-radius: 999px;
  padding: 2px 8px 2px 6px;
}
.jeu-classer > summary .jeu-etat--puce .jeu-etat-mot { display: inline; }

.jeu-classer-corps { padding: 2px 14px 14px; }
.jeu-classer-aide,
.jeu-classer-note {
  margin: 0 0 10px;
  font-size: 12px;
  color: rgba(240, 235, 220, .55);
}
.jeu-classer-note { margin: 10px 0 0; }
.jeu-classer-bloc {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
}
.jeu-classer-lbl {
  flex: 0 0 auto;
  min-width: 86px;
  font-family: monospace;
  font-size: 12px;
  color: rgba(240, 235, 220, .6);
}
.jeu-classer-choix { display: flex; flex-wrap: wrap; gap: 6px; }

.jeu-choix {
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(240, 235, 220, .25);
  color: rgba(240, 235, 220, .8);
  font-family: monospace;
  font-size: 12px;
  cursor: pointer;
  transition: border-color .15s, color .15s, background .15s;
}
.jeu-choix:hover { border-color: rgba(240, 235, 220, .55); color: #fff; }
.jeu-choix.on { background: rgba(240, 235, 220, .92); color: #14161a; border-color: #fff; font-weight: 700; }

.jeu-classer-etat {
  margin: 10px 0 0;
  min-height: 1.2em;
  font-family: monospace;
  font-size: 12px;
  color: rgba(240, 235, 220, .6);
}
.jeu-classer-etat.ok { color: #8fe3ad; }
.jeu-classer-etat.ko { color: #ff9090; }

/* Sous 520 px, l'étiquette passe au-dessus de ses boutons : côte à côte, il ne
   resterait pas 200 px pour cinq états. */
@media (max-width: 520px) {
  .jeu-classer-bloc { display: block; }
  .jeu-classer-lbl { display: block; margin-bottom: 6px; }
}

/* .jeu-fiche est une colonne flex : sans align-self, la pastille d'état
   s'étirerait sur toute la largeur du bloc et ressemblerait à une barre.
   Même correctif que .jeu-genre juste au-dessus, pour la même raison. */
.jeu-fiche > .jeu-etat { align-self: flex-start; }

/* ══════════════════════════════════════════════════════════════════════════
   fiche-compacte-marker (19/09/2026)

   Quatre demandes, et elles tirent toutes dans le même sens : rendre au JEU la
   place que la fiche lui prenait.
     · « le jeu ne doit pas descendre plus bas que le haut du bloc de
       navigation » ;
     · « les badges arcade / flash / à analyser sur la même ligne » ;
     · « la description peut occuper toute la largeur disponible » ;
     · « retour et plein écran juste au-dessus du jeu ».
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Les étiquettes, sur une ligne ─────────────────────────────────────────
   `flex-wrap` et non `nowrap` : sur un téléphone de 360 px, genre + Flash +
   Mobile + PC + état dépassent la largeur. Elles se replient alors, plutôt que
   de déborder ou de rétrécir jusqu'à l'illisible. */
.jeu-etiquettes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
/* align-self:flex-start servait à empêcher l'étirement dans la COLONNE. Dans
   une rangée, il aligne verticalement en haut et désaligne les pastilles entre
   elles — on le neutralise ici, et seulement ici. */
.jeu-etiquettes > .jeu-genre,
.jeu-etiquettes > .jeu-etat { align-self: center; }

/* ── La description sur toute la largeur ───────────────────────────────────
   Les 760 px venaient de la mesure de confort en typographie — au-delà, l'œil
   perd la ligne suivante. Ça vaut pour un article ; pas pour deux phrases de
   résumé au-dessus d'un plateau de jeu, où la contrainte coûtait une ligne de
   plus et donc de la hauteur prise au jeu. */
.jeu-fiche { max-width: none; }

/* ── Retour et Plein écran, collés au cadre ────────────────────────────── */
.jeu-barre-jeu {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 10px 0 8px;
  flex-wrap: wrap;
}
/* L'en-tête ne porte plus que le titre : sa marge basse n'a plus à ménager une
   rangée de boutons qui n'y est plus. */
.jeu-header { margin-bottom: 8px; }

/* ══════════════════════════════════════════════════════════════════════════
   LE JEU S'ARRÊTE AU-DESSUS DU BLOC DE NAVIGATION

   La hauteur du lecteur se calculait sur « l'écran moins la barre du haut ».
   Le bloc du bas — la pastille de catégorie et sa couronne — est en
   position:fixed : il ne participe pas au flux, donc rien ne le retranchait, et
   le bas du jeu passait dessous. On ne peut pas y jouer, et les boutons du
   joystick deviennent des pièges au-dessus d'un plateau.

   On retranche donc --joy-encombrement, la variable de styles/topbar.css qui
   donne déjà la hauteur du groupe (bas + demi-pastille + rayon extérieur +
   16 px de jour). Pas un nombre écrit ici : le groupe change de taille selon la
   largeur de l'écran et se décale de l'encoche du téléphone.

   Conditionné à `body.pj-couronne-visible`, la classe que pose
   scripts/pastille-joystick.js APRÈS avoir mesuré la couronne. Là où elle ne
   s'affiche pas — plein écran vidéo, page sans barre —, la règle ne s'applique
   pas et le jeu reprend toute la hauteur. C'est la même classe qui pose déjà le
   padding-bas de <body> : les deux se complètent au lieu de s'additionner, et
   la page tient exactement dans l'écran, sans ascenseur.
   ══════════════════════════════════════════════════════════════════════════ */
/* LE FLASH PASSE SOUS LE MÊME RÉGIME QUE LE HTML5, et c'est la vraie
   correction. Sa hauteur venait d'un rapport 4/3 borné par --jeu-entete, une
   ESTIMATION de ce qui le surplombe — 210 px, écrits à la main le 13/09. Dès
   qu'on touche à la fiche, l'estimation ment : au banc, après le déplacement
   des boutons, le cadre Flash dépassait de neuf pixels sous le bloc de
   navigation et la page prenait un ascenseur.
   En le plaçant dans la même colonne flexible, il n'y a plus rien à estimer :
   ce qui est au-dessus prend ce qu'il prend, le cadre absorbe le reste. Le SWF
   garde ses proportions À L'INTÉRIEUR (letterbox), donc un cadre large et bas
   ne le déforme pas — il se pose entre deux bandes noires, ce qui était déjà
   l'arbitrage assumé de jeu-hauteur-marker. */
.bloc-page:has(> .jeu-cadre > .jeu-iframe),
.bloc-page:has(> .jeu-cadre > #ruffle-container) {
  display: flex;
  flex-direction: column;
  height: calc(100dvh - var(--topbar-h, 56px));
  box-sizing: border-box;
}
body.pj-couronne-visible .bloc-page:has(> .jeu-cadre > .jeu-iframe),
body.pj-couronne-visible .bloc-page:has(> .jeu-cadre > #ruffle-container) {
  height: calc(100dvh - var(--topbar-h, 56px) - var(--joy-encombrement, 0px));
}
/* Tous les blocs au-dessus du cadre gardent leur taille ; seul le cadre absorbe
   ce qui reste. Écrit une fois pour tous plutôt qu'une règle par bloc — il y en
   a quatre maintenant, et il y en aura cinq un jour. */
.bloc-page:has(> .jeu-cadre > .jeu-iframe) > *,
.bloc-page:has(> .jeu-cadre > #ruffle-container) > * { flex: 0 0 auto; }
.bloc-page:has(> .jeu-cadre > .jeu-iframe) > .jeu-cadre,
.bloc-page:has(> .jeu-cadre > #ruffle-container) > .jeu-cadre {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
}
.bloc-page:has(> .jeu-cadre > #ruffle-container) > .jeu-cadre > #ruffle-container {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  aspect-ratio: auto;    /* c'est la colonne qui décide, plus le 4/3 */
  max-height: none;      /* ... donc --jeu-entete n'a plus voix au chapitre */
}

/* ══════════════════════════════════════════════════════════════════════════
   cadre-plancher-marker (19/09/2026) — LE JEU NE DOIT PAS S'ÉVAPORER QUAND ON
   OUVRE « Classer ce jeu ».

   Dans la colonne à hauteur fixe, le cadre est le seul bloc élastique : il
   absorbe donc tout ce que les autres prennent. Panneau déplié sur une fenêtre
   de 600 px de haut, mesuré au banc : le cadre tombait à 30 px. Le jeu
   disparaissait au moment précis où l'on venait de l'essayer pour le classer.

   Un plancher, et de quoi défiler au-dessus. 240 px n'est pas beaucoup, mais
   c'est assez pour que le plateau reste visible et pour que le bloc garde un
   sens ; le reste se rejoint à l'ascenseur, qui n'apparaît que dans ce cas.
   ══════════════════════════════════════════════════════════════════════════ */
.bloc-page:has(> .jeu-cadre > .jeu-iframe),
.bloc-page:has(> .jeu-cadre > #ruffle-container) { overflow-y: auto; }
.bloc-page:has(> .jeu-cadre > .jeu-iframe) > .jeu-cadre,
.bloc-page:has(> .jeu-cadre > #ruffle-container) > .jeu-cadre { min-height: 240px; }


/* ══════════════════════════════════════════════════════════════════════════
   jeux-tactile-marker (21/09/2026) — LE GESTE DOIT REVENIR AU JEU, PAS AU
   NAVIGATEUR.

   scripts/jeux-tactile.js transforme les glissements en flèches. Il appelle
   preventDefault() dès qu'il dirige, mais ça ne suffit pas seul : sur mobile,
   le navigateur décide du défilement AVANT de livrer le premier touchmove, et
   un geste vers le haut part en défilement de page avant qu'on ait pu dire
   non. `touch-action: none` prévient le navigateur en amont — sur le cadre du
   jeu seulement, jamais sur la page.

   Le zoom à deux doigts est perdu DANS le cadre. C'est le prix, et il est
   juste : un jeu qu'on dirige au doigt n'est pas une image qu'on agrandit, et
   le reste de la page garde son zoom.

   Réservé au pointeur grossier : sur un écran tactile de bureau, rien ne
   change, et à la souris le clavier reste le clavier.
   ══════════════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) {
  #ruffle-container,
  #ruffle-container > * {
    touch-action: none;
  }
}
