/* Jeux de Carolina. Tout est préfixé .cj- ; les couleurs sont celles de la charte. */
.cj-galerie, .cj-jeu { --cj-bleu: #0B6ABA; --cj-profond: #0F3A71; --cj-brume: #F4F8FC; --cj-trait: #D5E2F0; --cj-ardoise: #3F4A5A; --cj-nuit: #0A1E38; --cj-ambre: #F0A94A; --cj-blanc: #FFFFFF; max-width: 960px; margin: 0 auto; }
.cj-cartes { list-style: none; margin: 0; padding: 0; display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.cj-carte { background: var(--cj-brume); border: 2px solid var(--cj-trait); border-radius: 12px; padding: 20px; display: flex; flex-direction: column; }
.cj-carte-vignette { display: block; width: 72px; height: 72px; margin: 0 0 12px; object-fit: contain; }
.cj-carte-titre { margin: 0 0 8px; font-size: 1.3em; }
.cj-carte p { margin: 0 0 12px; }
.cj-rythme { font-size: 0.9em; color: var(--cj-ardoise); }
.cj-carte .cj-bouton { margin-top: auto; align-self: flex-start; }

.cj-bouton { display: inline-block; min-height: 44px; padding: 10px 22px; border: 2px solid var(--cj-profond); border-radius: 8px; background: var(--cj-profond); color: var(--cj-blanc) !important; font: inherit; font-weight: 700; text-decoration: none !important; cursor: pointer; }
.cj-bouton:hover, .cj-bouton:focus-visible { background: var(--cj-bleu); border-color: var(--cj-bleu); }
.cj-bouton-clair { background: var(--cj-blanc); color: var(--cj-profond) !important; }
.cj-bouton-clair:hover, .cj-bouton-clair:focus-visible { background: var(--cj-brume); }
.cj-galerie :focus-visible, .cj-jeu :focus-visible { outline: 3px solid var(--cj-profond); outline-offset: 2px; box-shadow: 0 0 0 6px var(--cj-ambre); }
.cj-bouton[disabled] { opacity: 0.5; cursor: default; }

.cj-titre { margin: 0 0 8px; }
.cj-accroche { margin: 0 0 20px; }
.cj-live { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.cj-barre { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; margin: 0 0 12px; }
.cj-barre p { margin: 0; }
.cj-fin { background: var(--cj-brume); border: 2px solid var(--cj-trait); border-radius: 12px; padding: 20px; }
.cj-fin-titre { margin: 0 0 8px; }
.cj-fin-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0 0; }
.cj-pied { margin: 20px 0 0; }

/* Le métro : une grille de boutons, 44 px au moins, un pictogramme par type de case.
   Le sol est carrelé, les murs sont en briques : c'est un couloir de métro, pas un damier. */
.cj-grille { position: relative; display: grid; grid-template-columns: repeat(var(--cj-cols), minmax(0, 1fr)); gap: 4px; max-width: 560px; margin: 0 auto 16px; padding: 6px; background: var(--cj-trait); border-radius: 10px; touch-action: pan-y; }
/* Hauteur réservée : la grille arrive après « Cargando », sans elle la scène saute (CLS).
   `min(560px, 100vw)` ne réservait que la grille, et la scène en tient bien plus : mesurée
   montée, elle fait 678 px à 360 de large (barre 170, pastilles 70, grille 300, aide 109),
   657 px à 400 et 660 px à 430 — soit 318, 257 et 230 px de saut au montage, tout ce qui
   suit le jeu descendant d'autant. D'où les 300 px ajoutés : la réserve vaut 660 px à 360,
   700 à 400, 730 à 430. Un peu de blanc au-dessus de 400 px de large vaut mieux qu'une
   page qui saute sous les doigts au bout de deux secondes. */
.cj-jeu[data-jeu="metro"] .cj-scene { min-height: calc(min(560px, 100vw) + 300px); }
.cj-rangee { display: contents; }
.cj-case { position: relative; aspect-ratio: 1; min-width: 0; padding: 0; border: 2px solid var(--cj-trait); border-radius: 6px; cursor: pointer; display: grid; place-items: center;
	background-color: var(--cj-blanc);
	background-image: linear-gradient(var(--cj-trait) 1px, transparent 1px), linear-gradient(90deg, var(--cj-trait) 1px, transparent 1px);
	background-size: 33.34% 33.34%; background-position: -1px -1px; }
.cj-case svg { width: 74%; height: 74%; display: block; position: relative; }
.cj-case img { width: 88%; height: 88%; object-fit: contain; display: block; position: relative; }
.cj-case-mur { cursor: default; border-color: var(--cj-ardoise);
	background-color: var(--cj-ardoise);
	background-image: linear-gradient(var(--cj-nuit) 2px, transparent 2px), linear-gradient(90deg, var(--cj-nuit) 2px, transparent 2px), linear-gradient(90deg, transparent 50%, var(--cj-nuit) 50%, var(--cj-nuit) calc(50% + 2px), transparent calc(50% + 2px));
	background-size: 100% 25%, 50% 50%, 100% 50%; background-position: 0 0, 0 0, 0 12.5%; }
.cj-case-escalier { background-color: var(--cj-brume); }
.cj-case-toboggan { background-color: #FBE7C6; background-image: none; }
.cj-case-panne { background-color: var(--cj-brume); }
.cj-case-quai { background-color: var(--cj-bleu); background-image: none; border-color: var(--cj-bleu); }
.cj-case-carolina { border-color: var(--cj-ambre); box-shadow: 0 0 0 2px var(--cj-ambre); }
/* Carolina glisse au-dessus de la grille ; secousse sur un coup refusé, fondu dans l'ascenseur. */
.cj-carolina { position: absolute; left: 0; top: 0; z-index: 2; padding: 3%; box-sizing: border-box; object-fit: contain; pointer-events: none; will-change: transform; }
.cj-carolina-fondu { opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
	.cj-carolina { transition: transform 0.15s cubic-bezier(0.2, 0.8, 0.3, 1), opacity 0.13s; }
	.cj-carolina-saut { transition: opacity 0.13s; }
}
/* Les tuiles peintes, quand sprites.py les a produites : une classe par type sur la grille. */
.cj-tuile-sol .cj-case-sol, .cj-tuile-mur .cj-case-mur, .cj-tuile-escalier .cj-case-escalier, .cj-tuile-toboggan .cj-case-toboggan, .cj-tuile-panne .cj-case-panne, .cj-tuile-ascenseur .cj-case-ascenseur, .cj-tuile-quai .cj-case-quai { background-size: cover; background-position: center; border-color: transparent; }
.cj-tuile-sol .cj-case-sol { background-image: var(--cj-tuile-sol); }
.cj-tuile-mur .cj-case-mur { background-image: var(--cj-tuile-mur); }
.cj-tuile-escalier .cj-case-escalier { background-image: var(--cj-tuile-escalier); }
.cj-tuile-toboggan .cj-case-toboggan { background-image: var(--cj-tuile-toboggan); }
.cj-tuile-panne .cj-case-panne { background-image: var(--cj-tuile-panne); }
.cj-tuile-ascenseur .cj-case-ascenseur { background-image: var(--cj-tuile-ascenseur); }
.cj-tuile-quai .cj-case-quai { background-image: var(--cj-tuile-quai); }
.cj-grille .cj-case-carolina.cj-case-carolina { border-color: var(--cj-ambre); }
.cj-case-voisine { border-color: var(--cj-bleu); background-color: var(--cj-brume); }
.cj-grille[class*="cj-tuile-"] .cj-case-voisine { border-color: var(--cj-bleu); }
.cj-pastille { position: absolute; right: 4px; bottom: 4px; width: 10px; height: 10px; border-radius: 50%; background: var(--cj-bleu); box-shadow: 0 0 0 2px var(--cj-blanc); }
.cj-case-quai .cj-pastille { background: var(--cj-ambre); }
.cj-aide { font-size: 0.95em; color: var(--cj-ardoise); }
@keyframes cj-secousse { 0%, 100% { translate: 0 0; } 25% { translate: -4px 0; } 75% { translate: 4px 0; } }
.cj-secousse { animation: cj-secousse 0.15s ease-in-out 2; }
/* Sélecteur de niveaux : dix pastilles rondes, l'état visible avant même de cliquer. */
.cj-metro-niveaux { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }   /* la même marge que la barre : sans elle, la rangée des pastilles vient buter sur la grille */
.cj-metro-niveaux button { width: 32px; height: 32px; border-radius: 50%; border: 2px solid var(--cj-trait); background: var(--cj-blanc); color: var(--cj-profond); font: inherit; font-weight: 700; cursor: pointer; }
/* Les deux états passent par `button` : moins spécifiques, ils perdaient contre la base — chiffre blanc sur fond blanc, et pas d'anneau ambre. */
.cj-metro-niveaux button.cj-metro-niveau-fait { background: var(--cj-profond); color: var(--cj-blanc); border-color: var(--cj-profond); }
.cj-metro-niveaux button.cj-metro-niveau-courant { border: 3px solid var(--cj-ambre); }
/* Un niveau encore fermé s'estompe comme tout bouton désactivé du fichier, plutôt que d'écrire en couleur de trait. */
.cj-metro-niveaux button[disabled] { opacity: 0.5; cursor: default; }
/* Filet : le JS pose des `button` nus, mais une pastille qui hériterait de `cj-bouton` resterait ronde et de 32 px. */
.cj-metro-niveaux .cj-bouton { min-height: 0; padding: 0; }
/* L'étoile ne guide vers un escalier que s'il reste de la purpurina pour le transformer. */
/* L'ambre ne fait que 1,8:1 sur la brume : c'est le contour sombre, et non la couleur, qui rend l'étoile lisible sur toutes les tuiles. */
.cj-grille.cj-pincees .cj-case-escalier::after { content: '\2605'; position: absolute; top: 2px; left: 4px; font-size: 12px; color: var(--cj-ambre); text-shadow: -1px 0 var(--cj-nuit), 1px 0 var(--cj-nuit), 0 -1px var(--cj-nuit), 0 1px var(--cj-nuit); }
/* Le conseil qui suit un coup refusé se lit comme une consigne, pas comme une troisième étiquette de la barre : sa propre ligne. */
/* Scopé dans `.cj-barre`, sans quoi le `margin: 0` de `.cj-barre p` l'emporte et la ligne se recolle au compteur. */
.cj-barre .cj-metro-indice { flex-basis: 100%; margin: 4px 0 0; padding: 6px 10px; border-left: 4px solid var(--cj-ambre); background: var(--cj-brume); color: var(--cj-nuit); }

/* Le memory : des cartes carrées à deux faces, dos à motif de paillettes, qui se retournent vraiment. */
.cj-memory-bandeau { min-height: 1.6em; margin: 0 0 10px; padding: 6px 12px; border-radius: 8px; font-weight: 700; text-align: center; }
.cj-memory-bandeau:empty { padding: 0; }
.cj-memory-bandeau[data-etat="paire"] { background: #FBE7C6; color: var(--cj-nuit); }
.cj-memory-grille { display: grid; gap: 8px; grid-template-columns: repeat(4, 1fr); max-width: 520px; margin: 0 auto 16px; list-style: none; padding: 0; }
.cj-memory-grille.cj-memory-6 { grid-template-columns: repeat(3, 1fr); max-width: 400px; }
@media (min-width: 600px) { .cj-memory-grille.cj-memory-12 { grid-template-columns: repeat(6, 1fr); max-width: 760px; } }
/* `display: block` n'est pas décoratif : un bouton est en ligne par défaut, et la
   ligne réservait 11 px de descendante sous chaque carte — 44 px perdus sur quatre
   rangées, assez pour faire défiler le plateau en plein écran paysage. */
.cj-memory-carte { display: block; position: relative; aspect-ratio: 1; width: 100%; min-width: 44px; padding: 0; border: 0; border-radius: 8px; background: none; cursor: pointer; perspective: 600px; touch-action: manipulation; }
.cj-memory-dos, .cj-memory-face { position: absolute; inset: 0; border: 2px solid var(--cj-trait); border-radius: 8px; overflow: hidden; backface-visibility: hidden; }
.cj-memory-dos { background: var(--cj-profond) var(--cj-dos, radial-gradient(circle, var(--cj-ambre) 1.5px, transparent 2px)) 0 0 / 14px 14px; }
.cj-memory-grille[style*="--cj-dos"] .cj-memory-dos { background-size: cover; background-position: center; }
@keyframes cj-pulse-or { 50% { box-shadow: 0 0 0 6px var(--cj-ambre); } }
@media (prefers-reduced-motion: no-preference) { .cj-memory-pulse .cj-memory-face { animation: cj-pulse-or 0.6s; } }
.cj-memory-face { transform: rotateY(180deg); background: var(--cj-blanc); }
.cj-memory-face img { width: 100%; height: 100%; object-fit: contain; background: var(--cj-blanc); display: block; }
/* Le repli d'une vignette cassée : le titre du chapitre, centré dans la carte, sans débordement. */
.cj-memory-texte { display: grid; place-items: center; width: 100%; height: 100%; padding: 6px; box-sizing: border-box; font-size: 0.8em; line-height: 1.2; text-align: center; color: var(--cj-profond); background: var(--cj-blanc); }
.cj-memory-carte[data-face="visible"] .cj-memory-dos, .cj-memory-carte[data-face="trouvee"] .cj-memory-dos { transform: rotateY(180deg); }
.cj-memory-carte[data-face="visible"] .cj-memory-face, .cj-memory-carte[data-face="trouvee"] .cj-memory-face { transform: rotateY(0); }
.cj-memory-carte[data-face="trouvee"] { cursor: default; }
.cj-memory-carte[data-face="trouvee"] .cj-memory-face { border-color: var(--cj-ambre); box-shadow: 0 0 0 2px var(--cj-ambre); }
.cj-memory-liste { margin: 8px 0 0; padding-left: 20px; }
@media (prefers-reduced-motion: no-preference) { .cj-memory-dos, .cj-memory-face { transition: transform 0.35s; } }
/* Une carte qui n'est pas une paire tremble, comme Carolina refusée par un mur au métro — sous garde, comme le reste des animations du memory. */
@media (prefers-reduced-motion: no-preference) { .cj-memory-carte.cj-secousse { animation: cj-secousse 0.15s ease-in-out 2; } }

/* Le runner : le canvas prend la largeur, le décor reste net. */
.cj-runner-canvas { width: 100%; max-width: 960px; height: auto; display: block; border: 2px solid var(--cj-trait); border-radius: 8px; background: var(--cj-brume); touch-action: manipulation; }
.cj-runner-commandes { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 12px 0; }
.cj-runner-sopla { font-size: 1.2em; min-width: 140px; }
@keyframes cj-pulse { 50% { transform: scale(1.25); } }
@media (prefers-reduced-motion: no-preference) { .cj-pulse { animation: cj-pulse 0.3s; display: inline-block; } }
.cj-calque { position: absolute; inset: 0; z-index: 3; width: 100%; height: 100%; pointer-events: none; }
/* Bandeau d'annonce au-dessus du canvas (nouveau record, prochaine ville) : les couleurs des autres messages du jeu.
   Il reste dans le flux, toujours rendu, sa place tenue : un `hidden` qui allait et venait poussait le canvas de
   56 px à chaque ville (52 px en plein écran couché), deux secondes et demie durant — le jeu sautait sous
   les doigts. La hauteur réservée vaut exactement ce que le bandeau mesure rempli (12 px de rembourrage et
   une ligne de 1,1 em, d'où le `line-height` qui fige cette ligne), et `visibility` l'efface sans le retirer
   du flux ; `montrerBandeau` pose `data-actif`. */
.cj-runner-bandeau { box-sizing: border-box; min-height: calc(1.1em + 12px); margin: 0 auto 8px; padding: 6px 14px; border-radius: 8px; background: var(--cj-profond); color: var(--cj-blanc); font-size: 1.1em; line-height: 1.1; text-align: center; visibility: hidden; }
.cj-runner-bandeau[data-actif] { visibility: visible; }

/* Le plein écran (voir jeux/plein-ecran.js). La classe `cj-plein` fait tout : en natif
   comme en calque, la racine couvre la fenêtre et les jeux se calent sur le plus court
   des deux côtés — le runner garde son 480 × 200, les grilles restent carrées. Les
   cases du métro n'ont plus de largeur minimale : sept colonnes à 44 px débordaient
   d'un téléphone entre les marges d'Avada ; le plein écran est là pour les agrandir.

   Chaque mesure en `dvh` est doublée d'un repli en `vh`, déclaré avant elle : `dvh`
   suit la barre d'adresse qui se replie, mais un navigateur qui l'ignore laisse
   tomber la déclaration entière — et la grille perdrait alors toute borne de
   hauteur. Le glyphe ↻ du bandeau de rotation, lui, a quitté cette feuille :
   `plein-ecran.js` le pose dans un `span` que les lecteurs d'écran sautent. */
.cj-coquille { margin: 0 0 12px; }
.cj-rotation { margin: 0 0 12px; padding: 10px 14px; border-radius: 8px; background: var(--cj-profond); color: var(--cj-blanc); text-align: center; }
.cj-jeu.cj-plein { position: fixed; inset: 0; z-index: 100000; box-sizing: border-box; max-width: none; margin: 0; padding: 12px 16px; height: 100vh; height: 100dvh; overflow: auto; overscroll-behavior: contain; background: var(--cj-brume); color: var(--cj-nuit); }
.cj-jeu:fullscreen { background: var(--cj-brume); }
.cj-plein .cj-titre, .cj-plein .cj-accroche, .cj-plein .cj-aide, .cj-plein .cj-pied, .cj-plein .cj-memory-liste, .cj-plein .cj-memory-liste-titre { display: none; }
.cj-plein .cj-coquille { margin: 0 0 8px; }
.cj-plein .cj-plein-bouton { min-height: 36px; padding: 6px 14px; }
.cj-plein .cj-runner-canvas { max-width: none; width: min(100vw - 32px, (100vh - 170px) * 2.4); width: min(100vw - 32px, (100dvh - 170px) * 2.4); margin: 0 auto; }
.cj-plein .cj-grille { max-width: min(100vw - 32px, 100vh - 165px); max-width: min(100vw - 32px, 100dvh - 165px); }
/* La réserve anti-CLS de la scène du métro ne vaut que dans la page : en plein écran, c'est
   la fenêtre qui borne la grille, et 660 px réservés dans une fenêtre de 640 font défiler un
   écran qui doit tenir d'un bloc — mesuré à 360 × 640, 104 px de défilement au lieu de 0. */
.cj-jeu[data-jeu="metro"].cj-plein .cj-scene { min-height: 0; }
.cj-plein .cj-memory-grille, .cj-plein .cj-memory-grille.cj-memory-6, .cj-plein .cj-memory-grille.cj-memory-12 { max-width: min(100vw - 32px, (100vh - 150px) * 1.34); max-width: min(100vw - 32px, (100dvh - 150px) * 1.34); }
/* En paysage, la scène du runner devient une rangée : le canvas prend toute la largeur,
   la barre et les commandes se partagent la ligne du dessous — un étage de moins. */
@media (orientation: landscape) {
	.cj-jeu[data-jeu="runner"].cj-plein .cj-scene { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
	/* Le bandeau garde sa ligne au-dessus du canvas : sans `order`, il se glisserait à côté de lui dans la rangée. */
	.cj-jeu[data-jeu="runner"].cj-plein .cj-runner-bandeau { order: -1; flex-basis: 100%; }
	/* Le budget de hauteur retire 202 px et non 152 : la ligne du bandeau est désormais
	   tenue en permanence, et elle coûte 50 px mesurés — 33,77 px de boîte, 8 px de marge
	   et les 8 px de `gap` de la rangée qu'elle ouvre. Tant que le bandeau disparaissait,
	   152 px suffisaient *et* la scène débordait de 50 px chaque fois qu'il s'affichait ;
	   réservée, cette place se paie une fois pour toutes sur le canvas, qui passe de
	   499 × 210 à 379 × 162 sur un téléphone couché — en échange, plus rien ne défile. */
	.cj-jeu[data-jeu="runner"].cj-plein .cj-runner-canvas { order: 0; flex: 0 0 auto; width: min(100vw - 32px, (100vh - 202px) * 2.4); width: min(100vw - 32px, (100dvh - 202px) * 2.4); }
	.cj-jeu[data-jeu="runner"].cj-plein .cj-barre { order: 1; flex: 1 1 auto; margin: 0; }
	.cj-jeu[data-jeu="runner"].cj-plein .cj-runner-commandes { order: 2; margin: 0; }
	.cj-plein .cj-memory-grille.cj-memory-6 { grid-template-columns: repeat(6, 1fr); max-width: min(100vw - 32px, (100vh - 200px) * 3); max-width: min(100vw - 32px, (100dvh - 200px) * 3); }
	/* Le métro en paysage : les commandes passent en colonne à gauche et la grille
	   prend toute la hauteur. Empilées au-dessus d'elle — barre, dix pastilles,
	   ligne de fin de niveau — elles lui mangeaient trois étages : elle tombait à
	   195 px de côté sur un téléphone couché, soit 27 px par case. La hauteur
	   réservée contre le CLS n'a plus de sens ici : c'est la fenêtre qui borne la
	   grille, plus la largeur de la page. Le budget de hauteur retire 80 px et non
	   60 : mesurés, le rembourrage de la racine et la barre du plein écran en
	   prennent 77, et la grille dépassait d'autant — sa dernière rangée était
	   coupée. Une grille (et non un `flex`) parce que la colonne de gauche empile
	   trois frères de la grille, qu'aucun ordre de `flex-wrap` ne met l'un sous
	   l'autre à côté d'un quatrième plus haut. */
	.cj-jeu[data-jeu="metro"].cj-plein .cj-scene { display: grid; grid-template-columns: 210px minmax(0, 1fr); grid-template-rows: auto auto 1fr; align-items: start; gap: 8px 16px; min-height: 0; }
	.cj-jeu[data-jeu="metro"].cj-plein .cj-barre { grid-area: 1 / 1; flex-direction: column; align-items: flex-start; margin: 0; }
	.cj-jeu[data-jeu="metro"].cj-plein .cj-metro-niveaux { grid-area: 2 / 1; }
	.cj-jeu[data-jeu="metro"].cj-plein .cj-metro-suite { grid-area: 3 / 1; margin: 0; }
	.cj-jeu[data-jeu="metro"].cj-plein .cj-grille { grid-area: 1 / 2 / -1 / 2; margin: 0; max-width: min(100vw - 260px, 100vh - 80px); max-width: min(100vw - 260px, 100dvh - 80px); }
	/* Huit colonnes sans condition de hauteur : douze paires font vingt-quatre cartes,
	   donc sur un écran bas c'est la hauteur qui borne et moins de colonnes signifie
	   plus de rangées — cartes plus petites et plateau qui défile (mesuré à 800 × 360 :
	   46 px sans défilement en huit colonnes, 47 px avec 31 px de défilement en six). */
	.cj-plein .cj-memory-grille.cj-memory-12 { grid-template-columns: repeat(8, 1fr); max-width: min(100vw - 32px, (100vh - 200px) * 2.67); max-width: min(100vw - 32px, (100dvh - 200px) * 2.67); }
}
