/* ============================================================================
   style.css — Interface d'InZeMaze.
   Direction : "soirée jeux" — fond nuit indigo, couleurs bonbon très franches,
   typographie ronde (Baloo 2 / Nunito), gros boutons pour mains d'enfants.
   ============================================================================ */

/* --- Polices embarquées (aucun appel réseau : le jeu doit tourner hors ligne).
   Seules les graisses 700 et 800 sont utilisées par cette feuille. --------- */
@font-face {
  font-family: 'Baloo 2';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/baloo-2-latin-ext-700-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Baloo 2';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/baloo-2-latin-700-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Baloo 2';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../assets/fonts/baloo-2-latin-ext-800-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Baloo 2';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../assets/fonts/baloo-2-latin-800-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Nunito';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/nunito-latin-ext-700-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Nunito';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../assets/fonts/nunito-latin-700-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Nunito';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../assets/fonts/nunito-latin-ext-800-normal.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Nunito';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../assets/fonts/nunito-latin-800-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* LA PALETTE.
   Le fond était un indigo de nuit avec trois halos violet/bleu/rose : la
   teinte par défaut de toute application sombre, et celle qui met le moins en
   valeur des cartes crème. On passe à un VERT PROFOND de sous-bois, avec des
   halos chauds. Le contraste avec le crème et les emoji y gagne, et l'écran
   cesse de ressembler à tous les autres. L'encre suit — un brun-vert très
   foncé plutôt qu'un bleu-violet, sinon le texte flotte au-dessus du fond
   sans lui appartenir. */
:root {
  --ink: #16301f;
  --night: #0e8a4e;
  --night-2: #3fd07d;
  --cream: #fff6e4;
  --pink: #ff5d8f;
  --yellow: #ffb400;
  --sky: #38c8f5;
  --lime: #7be04b;
  --violet: #9d6bff;
  --radius: 22px;
  --shadow: 0 8px 0 rgba(0, 0, 0, 0.18);
}

* {
  box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
  /* Pas de double-tap-zoom ni de délai de 300 ms dans une WebView. */
  touch-action: manipulation;
}

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  /* Ni « pull-to-refresh » ni rebond élastique sur Android. */
  overscroll-behavior: none;
  font-family: 'Nunito', 'Segoe UI', system-ui, sans-serif;
  color: var(--ink);
  background: var(--night);
  /* Un appui long ne doit pas sélectionner l'interface ni ouvrir le menu
     contextuel de la WebView — sauf dans les champs de saisie. */
  user-select: none;
  -webkit-user-select: none;
}

input, textarea { user-select: text; -webkit-user-select: text; }

h1, h2, h3, .preset-name, .big-btn, .title {
  font-family: 'Baloo 2', 'Nunito', sans-serif;
}

.hidden { display: none !important; }

#scene {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* Les balayages du doigt pilotent le jeu : le navigateur ne doit pas les
     capter pour faire défiler ou zoomer (cf controls.js → bindSwipes). */
  touch-action: none;
}

/* Voile de téléportation. Il ne prend aucun clic et n'existe que le temps de
   son animation : hors de celle-ci, `opacity: 0`. Le violet dit « ce n'est
   pas le décor » — aucune autre chose du jeu n'est de cette couleur-là. */
#teleFlash {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(circle at 50% 50%, #fff, var(--violet) 55%, #2a1060 100%);
}
#teleFlash.on { animation: tele-flash 0.62s ease-out; }
@keyframes tele-flash {
  0%   { opacity: 0; }
  18%  { opacity: 0.92; }   /* on se dissout */
  46%  { opacity: 0.92; }   /* … le temps du trou de silence, côté son */
  100% { opacity: 0; }      /* on retombe quelque part */
}
/* Un enfant sensible au mouvement ne doit pas subir un éclair plein écran :
   le voile reste, en beaucoup plus doux, pour que l'information passe quand
   même. La supprimer laisserait la téléportation sans aucun retour.
                                                                     ⚠
   NOM DISTINCT, et changement d'`animation-name` — surtout pas une seconde
   `@keyframes tele-flash` dans la media query. Redéfinir un nom d'animation
   sous condition ne fait pas ce qu'on croit : Chromium retient la DERNIÈRE
   déclaration vue, la media query ne s'appliquant qu'à son contenu et non à
   l'enregistrement du nom. Résultat mesuré : l'animation existait, tournait,
   durait bien 0,62 s… et l'opacité restait à 0 d'un bout à l'autre. Un voile
   parfaitement invisible, sans la moindre erreur nulle part. */
@keyframes tele-flash-doux {
  0%, 100% { opacity: 0; }
  30%, 55% { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  #teleFlash.on { animation-name: tele-flash-doux; }
}

/* ============================= HUD ============================= */

#hud {
  position: fixed;
  top: calc(10px + env(safe-area-inset-top));
  left: calc(10px + env(safe-area-inset-left));
  right: calc(10px + env(safe-area-inset-right));
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  z-index: 20;
  pointer-events: none;
}

.hud-pill {
  background: var(--cream);
  border: 3px solid var(--ink);
  border-radius: 999px;
  padding: 5px 14px;
  font-weight: 800;
  font-size: 16px;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.25);
  display: flex;
  align-items: center;
  gap: 8px;
  pointer-events: auto;
}

#hudKey.found { background: #d8ffd0; }

#pelletSwatch {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2.5px solid var(--ink);
  background: var(--sky);
  display: inline-block;
}
#pelletSwatch.clickable { cursor: pointer; }

.hud-spacer { flex: 1; }

.hud-btn {
  pointer-events: auto;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 3px solid var(--ink);
  background: var(--yellow);
  font-family: 'Baloo 2', sans-serif;
  font-size: 20px;
  font-weight: 800;
  color: var(--ink);
  cursor: pointer;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.25);
}
.hud-btn:active { transform: translateY(2px); box-shadow: none; }

#compass {
  pointer-events: auto;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 3px solid var(--ink);
  background: var(--cream);
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.25);
  position: relative;
  display: grid;
  place-items: center;
}
#needle {
  font-size: 20px;
  color: var(--pink);
  transition: transform 0.08s linear;
  line-height: 1;
}
/* Repère du nord : une encoche en haut du cadran, pas une lettre. Le cadran ne
   tourne pas — c'est la flèche qui montre où l'on regarde. */
#compass::before {
  content: '';
  position: absolute;
  top: 3px;
  left: 50%;
  transform: translateX(-50%);
  width: 3px;
  height: 7px;
  border-radius: 2px;
  background: var(--ink);
  opacity: 0.5;
}

/* Aide */
#helpPanel {
  position: fixed;
  top: calc(var(--hud-h, 46px) + 14px + env(safe-area-inset-top));
  right: calc(10px + env(safe-area-inset-right));
  z-index: 25;
  background: var(--cream);
  border: 3px solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 18px;
  max-width: 340px;
  /* En allemand le panneau grandit : il doit défiler plutôt que sortir de
     l'écran (téléphone en paysage). */
  max-height: calc(100vh - var(--hud-h, 46px) - 28px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  overflow-y: auto;
  font-size: 14px;
  cursor: pointer;
}
#helpPanel h3 { margin: 0 0 6px; }
#helpPanel p { margin: 5px 0; }
.help-goal { font-weight: 800; }

/* ======================= Contrôles tactiles ======================= */

#touchControls {
  position: fixed;
  inset: 0;
  z-index: 30;
  pointer-events: none;
}

/* LE PAVÉ NE PREND QUE LA PLACE DE SES TOUCHES.
   `pointer-events: auto` sur le conteneur faisait de tout le rectangle — les
   gouttières et la cellule vide comprises — une surface morte pour le doigt.
   Mesuré : le pavé couvrait 44 % de la bande du pas de côté, c'est-à-dire
   exactement l'endroit où le pouce se pose. Les boutons prennent donc les
   appuis eux-mêmes, et le balayage passe entre eux. */
.tc-left {
  position: absolute;
  left: calc(14px + env(safe-area-inset-left));
  bottom: calc(16px + env(safe-area-inset-bottom)); /* au-dessus de la barre de gestes */
  display: grid;
  grid-template-columns: repeat(3, 64px);
  gap: 10px;
  pointer-events: none;
  transition: opacity 0.7s ease;
}

/* Reculer est seul sur sa rangée, sous avancer : les pas de côté ont quitté le
   pavé (ils sont doublés DEUX fois par le doigt — bande basse et appui sur un
   bord), et une croix à quatre branches se lit mieux qu'un carré de six. */
#tcBack { grid-column: 2; }

/* LES FLÈCHES S'EN VONT QUAND ON N'EN A PLUS BESOIN — voir `noteUnGeste`
   dans main.js. Elles ne reviennent pas : c'est ce qui les rend inoffensives
   pour qui balaye, et présentes pour qui débute. */
/* Et une touche effacée ne se presse plus : invisible mais cliquable, elle
   attraperait le pouce sans rien montrer — pire qu'une touche visible. */
.tc-left.efface { opacity: 0; }
.tc-left.efface .tc { pointer-events: none; }

.tc-right {
  position: absolute;
  right: calc(14px + env(safe-area-inset-right));
  bottom: calc(16px + env(safe-area-inset-bottom)); /* au-dessus de la barre de gestes */
  display: flex;
  flex-direction: column;
  gap: 12px;
  pointer-events: none;
}

.tc {
  width: 64px;
  height: 64px;
  border-radius: 20px;
  border: 3px solid var(--ink);
  background: rgba(255, 248, 236, 0.9);
  font-size: 26px;
  color: var(--ink);
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.3);
  touch-action: none;
  user-select: none;
  pointer-events: auto;   /* le conteneur, lui, laisse passer le doigt */
}
.tc.pressed { transform: translateY(3px); box-shadow: none; background: var(--yellow); }
.tc-big { width: 68px; height: 68px; border-radius: 50%; }
.tc-dot {
  display: inline-block;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 3px solid var(--ink);
  background: var(--pellet, var(--sky));
  vertical-align: middle;
}

/* ============================ Toast ============================ */

#toast {
  position: fixed;
  left: 50%;
  bottom: calc(110px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 70;
  background: var(--ink);
  color: var(--cream);
  /* Traduits, certains messages passent sur 2-3 lignes : la « pilule » devient
     alors un bloc arrondi plutôt qu'un ovale déformé. */
  border-radius: 22px;
  padding: 10px 22px;
  font-weight: 800;
  font-size: 16px;
  line-height: 1.35;
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.3);
  max-width: 92vw;
  text-align: center;
  animation: pop 0.25s ease-out;
}
@keyframes pop {
  from { transform: translateX(-50%) scale(0.7); opacity: 0; }
  to { transform: translateX(-50%) scale(1); opacity: 1; }
}

/* ============================ Carte ============================ */

#mapOverlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(24, 26, 52, 0.6);
  display: grid;
  place-items: center;
  padding: calc(12px + env(safe-area-inset-top)) calc(12px + env(safe-area-inset-right))
           calc(12px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left));
}

.map-card {
  background: var(--cream);
  border: 4px solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 12px;
  width: min(92vw, 560px);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.map-head {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Baloo 2', sans-serif;
  font-weight: 800;
  font-size: 18px;
}
.map-head span { flex: 1; min-width: 0; text-align: center; }

.map-btn {
  width: 42px;
  height: 42px;
  border-radius: 14px;
  border: 3px solid var(--ink);
  background: var(--sky);
  font-size: 22px;
  font-weight: 800;
  color: var(--ink);
  cursor: pointer;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.2);
}
.map-btn:disabled { opacity: 0.35; cursor: default; }
.map-btn:active:not(:disabled) { transform: translateY(2px); box-shadow: none; }
.map-close { background: var(--pink); }

#mapCanvas {
  width: 100%;
  height: min(60vh, 480px);
  background: #efe4cf;
  border: 3px solid var(--ink);
  border-radius: 14px;
}

.map-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  font-size: 13px;
  font-weight: 700;
  justify-content: center;
}
.lg { display: inline-block; width: 12px; height: 12px; vertical-align: -1px; }
.lg-player { background: #ff4d4d; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.lg-up { background: #ff8c42; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.lg-down { background: #8f5dff; clip-path: polygon(0 0, 100% 0, 50% 100%); }
.lg-pellet { background: var(--sky); border-radius: 50%; border: 2px solid var(--ink); }
/* La pastille de légende porte les DEUX signes d'une zone inversée : le ↻ des
   seuils, et le lavis violet de la région — exactement la même valeur que
   celle peinte par map2d.js, sinon la légende cesse d'en être une. */
/* Réglages de confort : toujours visibles sous les cartes de niveau, jamais
   dans le panneau Expert — voir index.html pour pourquoi. */
.confort {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  align-items: center;
  justify-content: center;
  margin: 10px 0 4px;
  font-size: 0.95rem;
}
.confort-range { display: flex; align-items: center; gap: 8px; }
.confort-range input[type="range"] { width: 120px; }

/* Aide générale : la phrase d'accroche d'abord, les commandes ensuite. */
.guide-lead {
  font-size: 17px;
  font-weight: 800;
  text-align: center;
  margin: 4px 0 14px;
}
.guide-goal {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 3px solid var(--ink);
  font-weight: 700;
  font-size: 14px;
}
#optionsOverlay .confort { flex-direction: column; align-items: flex-start; gap: 12px; }

.lg-flip {
  color: #7a4dff;
  background: rgba(122, 77, 255, 0.22);
  border-radius: 6px;
  padding: 0 5px;
}

/* --- Mode "petite carte" : dans un coin, le jeu continue derrière --- */
/* La petite carte se place SOUS le HUD réel : sa hauteur dépend de la langue
   (« Étage » / « Stockwerk » / « Verdieping »), elle est donc mesurée en JS et
   publiée dans --hud-h plutôt que devinée ici. */
#mapOverlay.mini {
  inset: auto;
  top: calc(var(--hud-h, 46px) + 14px + env(safe-area-inset-top));
  right: calc(10px + env(safe-area-inset-right));
  background: transparent;
  display: block;
  padding: 0;
  pointer-events: none;
}
#mapOverlay.mini .map-card {
  pointer-events: auto;
  width: min(62vw, 290px);
  padding: 8px;
  border-width: 3px;
  box-shadow: 0 5px 0 rgba(0, 0, 0, 0.25);
  opacity: 0.94;
}
#mapOverlay.mini #mapCanvas {
  height: min(52vw, 250px);
}
/* 4 boutons de 32px laissent peu de place au libellé : il se réduit tout seul
   plutôt que de casser l'en-tête sur deux lignes. */
#mapOverlay.mini .map-head { font-size: clamp(10px, 3.2vw, 14px); gap: 6px; }
#mapOverlay.mini .map-btn { width: 32px; height: 32px; font-size: 17px; border-radius: 10px; }
#mapOverlay.mini .map-legend { display: none; }

/* ====================== Écran de configuration ====================== */

#configScreen {
  position: fixed;
  inset: 0;
  z-index: 100;
  overflow-y: auto;
  /* Le vert était un vert de cave : sombre, mat, un peu vaseux là où les
     halos se croisaient. Il monte en clarté ET en saturation, et les halos
     passent au citron, à la menthe et à la turquoise — des couleurs qui
     ÉCLAIRENT au lieu de teinter. Un fond de jeu pour enfants n'a aucune
     raison d'être crépusculaire.

     Un premier essai en avait fait un vert sapin à peine plus clair : les
     halos, posés à 0,40 d'opacité sur un fond sombre, n'éclairaient rien du
     tout — on les devinait, on ne les voyait pas. Ce qui manquait n'était pas
     l'opacité mais LE FOND : un halo clair ne se lit que sur un vert déjà
     clair. La rampe part donc d'un vert printemps franc et descend vers un
     vert sûr, assez soutenu pour que les cartes pastel gardent leur relief. */
  background:
    radial-gradient(circle at 14% 16%, rgba(226, 255, 120, 0.62), transparent 48%),
    radial-gradient(circle at 90% 10%, rgba(110, 255, 196, 0.56), transparent 44%),
    radial-gradient(circle at 74% 94%, rgba(64, 236, 226, 0.52), transparent 50%),
    linear-gradient(160deg, var(--night-2), var(--night) 72%);
}

.config-inner {
  max-width: 720px;
  margin: 0 auto;
  padding: calc(34px + env(safe-area-inset-top)) calc(18px + env(safe-area-inset-right))
           calc(60px + env(safe-area-inset-bottom)) calc(18px + env(safe-area-inset-left));
  text-align: center;
}

/* ---------------------------------------------------------------------------
   LE TITRE ET SON HAMBURGER

   Le bouton est posé PAR-DESSUS la ligne du titre, en absolu, et non à côté
   de lui : dans une rangée, le titre se centrerait entre le bord gauche et
   le bouton, donc de travers à l'œil. Ici il reste centré sur la largeur
   entière et le bouton flotte à droite, aligné sur sa hauteur de majuscules.

   Discret veut dire : rien qu'un glyphe. Pas de cercle, pas de fond, pas
   d'ombre — six pastilles cerclées faisaient une rangée de gommettes plus
   voyante que les niveaux eux-mêmes. La cible tactile, elle, garde ses
   44 px : c'est le minimum d'Android, et il n'a aucune raison de se voir.
   --------------------------------------------------------------------------- */
/* Le titre et les cartes se touchaient : leurs BOÎTES sont contiguës, et les
   21 px de blanc qu'on voyait n'étaient que la descente de la police — de
   l'espace subi, pas de l'espace choisi. Le titre y était collé aux niveaux
   comme une étiquette sur un carton.

   La marge vaut exactement ce blanc-là : le doubler est la demande, et
   l'écrire ainsi le dit — sans elle, il n'y aurait rien du tout. */
.config-head { position: relative; margin-bottom: 21px; }
.burger {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 26px;
  line-height: 1;
  color: var(--cream);
  background: none;
  border: 0;
  cursor: pointer;
}
.burger:active { transform: translateY(-50%) scale(0.88); }

/* Le menu : une carte crème sous le bouton, alignée à droite comme lui.
   Chaque entrée porte son emoji dans une COLONNE de largeur fixe, ce qui
   aligne les libellés — sans cela, « 🎲 » et « ℹ️ » n'ont pas la même chasse
   et les six textes partent en escalier. */
#toolsMenu {
  position: absolute;
  z-index: 110;
  right: calc(18px + env(safe-area-inset-right));
  top: calc(78px + env(safe-area-inset-top));
  width: min(260px, calc(100vw - 36px));
  display: flex;
  flex-direction: column;
  padding: 6px;
  background: var(--cream);
  border: 3px solid var(--ink);
  border-radius: 16px;
  box-shadow: 0 8px 0 rgba(0, 0, 0, 0.22);
  text-align: left;
}
#toolsMenu.hidden { display: none; }
.tool-item {
  display: grid;
  grid-template-columns: 26px 1fr;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 8px 10px;
  font: inherit;
  font-size: 15px;
  font-weight: 800;
  color: var(--ink);
  text-align: left;
  background: none;
  border: 0;
  border-radius: 10px;
  cursor: pointer;
}
.tool-item:hover { background: rgba(0, 0, 0, 0.07); }
.tool-item:active { background: rgba(0, 0, 0, 0.14); }
.tool-emoji { font-size: 19px; line-height: 1; text-align: center; }

#langOverlay {
  position: fixed;
  inset: 0;
  /* 130, et non 120 comme les autres modales : celle-ci peut s'ouvrir PAR
     DESSUS une autre. Elle a vécu un temps dans le dialogue des options, à
     z-index égal et plus haut dans le document — donc peinte derrière lui,
     invisible et incliquable. Le bouton de langue est remonté dans la barre
     d'outils depuis, mais la règle reste : un dialogue appelable depuis un
     autre dialogue passe au-dessus. */
  z-index: 130;
  background: rgba(24, 26, 52, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
}
#langOverlay.hidden { display: none; }
.lang-card {
  background: var(--cream);
  border: 5px solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px 18px;
  width: min(420px, 100%);
  max-height: 86vh;
  overflow-y: auto;
}
.lang-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-top: 10px;
}

.lang-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 7px;
  margin: 0 0 20px;
}
.lang-btn {
  font: inherit;
  font-weight: 800;
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 11px;
  border: 3px solid var(--ink);
  border-radius: 999px;
  background: var(--cream);
  color: var(--ink);
  cursor: pointer;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.25);
}
.lang-btn:active { transform: translateY(2px); box-shadow: none; }
.lang-btn.active { background: var(--yellow); }
.lang-flag { font-size: 18px; line-height: 1; }

.title {
  color: var(--cream);
  font-size: clamp(42px, 9vw, 74px);
  font-weight: 800;
  margin: 0;
  letter-spacing: 1px;
  text-shadow: 0 6px 0 rgba(0, 0, 0, 0.35);
}
/* Le fragment mis en avant dans « InZeMaze ». */
.title-accent {
  color: var(--yellow);
  display: inline-block;
  transform: rotate(-6deg);
  text-shadow: 4px 4px 0 var(--pink), 0 6px 0 rgba(0, 0, 0, 0.35);
}

.subtitle {
  color: #cdd4ff;
  font-size: 18px;
  font-weight: 700;
  margin: 8px 0 26px;
}

.presets {
  display: grid;
  /* 160px : les descriptions traduites (allemand, néerlandais) sont bien plus
     longues qu'en français et n'ont plus de <br/> pour les couper. */
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}

/* ---------------------------------------------------------------------------
   LES CARTES DE NIVEAU.

   Retour au dessin d'avant : coins ronds, ombre douce, légère inclinaison —
   ça respire, ça fait jeu. La version « propre » qui l'avait remplacé, avec
   ses bandeaux alignés et son ombre au cordeau, était plus rangée et beaucoup
   plus terne : à force de mettre de l'ordre on avait enlevé la vie.

   Ce qui change, c'est LA COULEUR. Neuf cartes crème identiques ne se
   distinguaient que par leur texte, donc pas du tout pour un enfant qui ne
   lit pas encore ; chacune porte maintenant sa teinte. Elles restent pâles :
   c'est un fond de carte, pas un aplat.
   --------------------------------------------------------------------------- */
.preset {
  --teinte: #fff0c2;
  /* Un LÉGER dégradé sur toute la carte : un reflet clair en haut à gauche
     qui s'éteint vers un fond à peine assombri en bas à droite. C'est ce qui
     donne du volume à un aplat, sans rien changer à la couleur.

     Il est posé ICI, sur la carte entière, et non sur chacune des deux
     moitiés : le filtre gris de la moitié gauche s'applique PAR-DESSUS, donc
     le reflet traverse la coupe et les deux côtés restent une seule et même
     carte — l'un en couleur, l'autre en gris.

     LE CADRE SUIT LE MÊME DÉGRADÉ, en plus discret : éclairci en haut à
     gauche, pleine encre en bas à droite. Une carte éclairée d'un côté et
     cernée d'un trait parfaitement uniforme se contredit — le cadre a l'air
     collé par-dessus au lieu d'appartenir à l'objet.

     `border-image` ferait cela en une ligne mais annule le border-radius :
     des coins carrés sur une carte ronde. D'où la bordure TRANSPARENTE et
     trois couches de fond — le reflet et la teinte arrêtés au padding-box,
     le dégradé du cadre allant jusqu'au border-box, donc visible dans
     l'anneau que la bordure a laissé vide.

     La teinte est écrite en DÉGRADÉ D'UNE SEULE COULEUR, et non en couleur
     nue : dans un fond multicouche, une couleur ne peut occuper que la
     DERNIÈRE couche. Posée au milieu, elle rend toute la déclaration
     invalide — et le navigateur ne se plaint pas, il jette simplement le
     fond entier. Les cartes se retrouvent alors transparentes, sans teinte
     et sans cadre, sans que rien dans la page ne le dise. C'est arrivé deux
     fois de suite, la seconde à cause d'un commentaire mal refermé juste
     au-dessus : d'où le contrôle du style CALCULÉ dans la sonde. */
  background:
    linear-gradient(152deg,
      rgba(255, 255, 255, 0.78),
      rgba(255, 255, 255, 0) 44%,
      rgba(0, 0, 0, 0.075) 100%) padding-box,
    linear-gradient(var(--teinte), var(--teinte)) padding-box,
    linear-gradient(152deg, #3f6350, var(--ink) 62%) border-box;
  border: 4px solid transparent;
  border-radius: var(--radius);
  padding: 14px 8px 12px;
  cursor: pointer;
  transition: transform 0.12s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
/* PLUS DE VIE, à couleurs inchangées. Ce qui bougeait : une inclinaison de
   1,4° — assez pour salir l'alignement, pas assez pour qu'on la voie. Elle
   passe à 2-3°, sur QUATRE positions au lieu de deux : au-delà de deux
   valeurs, l'œil cesse de chercher le motif et lit « posées à la main ».

   Un essai leur donnait aussi des COINS INÉGAUX, un rayon différent par
   coin. Sur une carte isolée ça se défend ; en grille de neuf, les coins ne
   se répondaient plus d'une carte à l'autre et l'ensemble faisait bancal
   plutôt que dessiné à la main. Rayon unique, donc — le relief vient du
   dégradé, pas de la découpe.

   L'appui, LUI, reste : il enfonce la carte. C'est le retour qui manque le
   plus à un enfant — sans lui, on ne sait pas si le jeu a entendu. Il passait
   par une ombre qui se rétractait ; les ombres portées sont parties, donc
   c'est l'échelle seule qui le porte maintenant. */
.preset-pair:nth-child(4n+1) .preset { transform: rotate(-2.6deg); }
.preset-pair:nth-child(4n+2) .preset { transform: rotate(2.1deg); }
.preset-pair:nth-child(4n+3) .preset { transform: rotate(1.4deg); }
.preset-pair:nth-child(4n) .preset   { transform: rotate(-1.8deg); }
.preset:hover { transform: rotate(0deg) translateY(-4px) scale(1.02); }
.preset:active { transform: rotate(0deg) scale(0.95); }
/* La carte choisie : le cadre s'épaissit et la couleur monte. C'était une
   ombre de 8 px doublée d'un anneau — deux effets pour une seule idée, et le
   premier est justement celui qu'on vient d'enlever partout. */
.preset.selected {
  transform: rotate(0deg) scale(1.06);
  outline: 4px solid var(--ink);
  outline-offset: -1px;
  filter: saturate(1.7);
}
/* L'emoji respire : il grossit un peu quand la carte est choisie ou visée.
   C'est le seul élément que l'enfant regarde vraiment. */
.preset-emoji { transition: transform 0.16s cubic-bezier(0.34, 1.6, 0.64, 1); }
.preset:hover .preset-emoji,
.preset.selected .preset-emoji { transform: scale(1.18) rotate(-6deg); }

/* Une teinte par barreau, du jaune du poussin au corail du dragon. */
.preset-pair:nth-of-type(1) .preset { --teinte: #ffeeb8; }
.preset-pair:nth-of-type(2) .preset { --teinte: #ffdec2; }
.preset-pair:nth-of-type(3) .preset { --teinte: #ffd3e0; }
.preset-pair:nth-of-type(4) .preset { --teinte: #f3d6fb; }
.preset-pair:nth-of-type(5) .preset { --teinte: #dcd8ff; }
.preset-pair:nth-of-type(6) .preset { --teinte: #cceaff; }
.preset-pair:nth-of-type(7) .preset { --teinte: #c9f2da; }
.preset-pair:nth-of-type(8) .preset { --teinte: #ffd2c6; }
.preset-pair:nth-of-type(9) .preset { --teinte: #e8e6dc; }
/* L'échelle compte neuf cartes (huit barreaux + Expert) au lieu de quatre :
   emoji et titres resserrés, sinon le bouton Jouer part sous trois écrans de
   défilement. Le numéro de barreau dit l'ORDRE — un enfant qui ne lit pas
   encore voit quand même que le 5 vient après le 4. */
.preset { position: relative; }
/* Le numéro dit l'ORDRE — un enfant qui ne lit pas encore voit quand même que
   le 5 vient après le 4 — sans réclamer la vedette pour autant. */
.preset-rung {
  position: absolute;
  top: 6px;
  left: 9px;
  font-size: 13px;
  font-weight: 800;
  opacity: 0.45;
}
.preset-emoji { font-size: 32px; }
.preset-name { font-size: 18px; font-weight: 800; }
.preset-desc { font-size: 11.5px; font-weight: 700; opacity: 0.75; line-height: 1.25; }

/* ---------------------------------------------------------------------------
   LA CARTE COUPÉE : le gris à GAUCHE, la couleur à DROITE.

   DEUX VRAIS BOUTONS SUPERPOSÉS, découpés au clip-path — et non un fond
   dégradé sur un bouton unique. C'est la seule façon que la zone cliquable
   corresponde EXACTEMENT à ce qu'on voit : viser le gris donne le mode seul,
   pas « à peu près ». Chacun garde son libellé pour les lecteurs d'écran.

   La coupe a d'abord été horizontale, en bas de carte, et chaque moitié
   répétait l'emoji du barreau pour se faire comprendre. Deux erreurs d'un
   coup : une bande basse se lit comme un pied de page, et un contenu répété
   allonge la carte sans rien dire de plus.

   Verticale, il n'y a plus rien à répéter — c'est LA MÊME carte, dont le
   tiers gauche est désaturé. Le dessin, le titre et la description
   continuent à travers la coupe, en gris d'un côté, en couleur de l'autre.
   Rien n'est dupliqué, rien ne grandit, et le partage se voit d'un coup
   d'œil.
   --------------------------------------------------------------------------- */
.preset-pair { position: relative; display: grid; }
.preset-pair > .preset { grid-area: 1 / 1; }

.preset-seul {
  clip-path: polygon(0 0, 36% 0, 29% 100%, 0 100%);
  filter: grayscale(1) contrast(0.94);
}
.preset-tout {
  clip-path: polygon(36% 0, 100% 0, 100% 100%, 29% 100%);
}
/* Le trait de coupe : sans lui les deux côtés se fondent l'un dans l'autre,
   et la carte a l'air sale plutôt que partagée. */
.preset-seul::after {
  content: '';
  position: absolute;
  inset: 0;
  clip-path: polygon(34.4% 0, 36% 0, 29% 100%, 27.4% 100%);
  background: var(--ink);
  opacity: 0.5;
}

/* Panneau expert.
   Une hauteur maximale chiffrée finissait par rogner les dernières options dès
   que les libellés s'allongeaient (allemand : ~35 % de plus, et une seule
   colonne sous 600px). L'animation passe donc par grid-template-rows, qui
   s'anime jusqu'à la hauteur RÉELLE du contenu, quelle que soit la langue. */
#expertPanel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s ease;
}
#expertPanel.open { grid-template-rows: 1fr; }
#expertPanel > .grid-wrap { overflow: hidden; min-height: 0; }

#expertPanel .grid {
  background: var(--cream);
  border: 4px solid var(--ink);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px;
  margin-bottom: 18px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px 22px;
  text-align: left;
}

#expertPanel label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-weight: 800;
  font-size: 14px;
}
#expertPanel label.check { flex-direction: row; align-items: center; gap: 8px; }
#expertPanel output { color: var(--pink); }
#expertPanel .dual { display: flex; gap: 8px; }
#expertPanel .dual input { flex: 1; }

input[type='range'] { accent-color: var(--pink); height: 26px; }
input[type='checkbox'] { width: 20px; height: 20px; accent-color: var(--pink); }

select, #inSeed {
  font-family: 'Nunito', sans-serif;
  font-weight: 800;
  font-size: 15px;
  color: var(--ink);
  border: 3px solid var(--ink);
  border-radius: 12px;
  padding: 8px 10px;
  background: #fff;
}

/* Graine. Le bloc a quitté le fond vert de l'accueil pour le crème de son
   dialogue : l'encre y remplace le crème, sinon le code s'écrirait en blanc
   sur blanc. Le libellé, lui, est devenu le TITRE du dialogue — plus rien à
   faire tenir sur une ligne, donc plus de retour à la ligne à prévoir. */
.seed-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--ink);
  font-weight: 800;
}
#inSeed {
  width: 150px;
  text-align: center;
  letter-spacing: 2px;
  text-transform: uppercase;
}
#btnRandomSeed {
  width: 46px;
  height: 46px;
  font-size: 22px;
  border-radius: 14px;
  border: 3px solid var(--ink);
  background: var(--lime);
  cursor: pointer;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.25);
}
#btnRandomSeed:active { transform: translateY(2px); box-shadow: none; }
.seed-hint {
  color: var(--ink);
  opacity: 0.75;
  font-size: 13px;
  font-weight: 700;
  margin: 12px 2px 2px;
  text-align: center;
}

/* Gros boutons */
.big-btn {
  border: 4px solid var(--ink);
  border-radius: 999px;
  padding: 14px 34px;
  font-size: 22px;
  font-weight: 800;
  color: var(--ink);
  cursor: pointer;
  transition: transform 0.1s ease;
}
.big-btn:active { transform: scale(0.95); }

.btn-play {
  background: repeating-linear-gradient(-45deg, var(--yellow) 0 18px, #ffc93c 18px 36px);
  /* 64px de marge intérieure de chaque côté débordaient sur un écran de 320px
     dès que le libellé s'allongeait (« ▶ Spelen »). */
  font-size: clamp(23px, 6.5vw, 28px);
  padding: 16px clamp(28px, 12vw, 64px);
  max-width: 100%;
}
.btn-blue { background: var(--sky); }
.btn-pink { background: var(--pink); color: #fff; }
.btn-ghost { background: var(--cream); }

/* Ces deux blocs vivaient sur le fond sombre de l'accueil ; ils sont
   maintenant DANS les fenêtres Aide et Options, sur crème. Leur bleu pâle y
   était presque effacé, et le `b` en crème carrément invisible — un « Sur
   l'écran : » blanc sur blanc. L'encre du texte courant, et l'accent porté
   par un fond plutôt que par une couleur de lettre : ça se lit sur n'importe
   quel papier. */
.controls-help {
  margin-top: 22px;
  color: var(--ink);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.75;
  text-align: left;
}
.controls-help b {
  color: var(--ink);
  background: rgba(255, 180, 0, 0.3);
  border-radius: 5px;
  padding: 1px 5px;
}

/* Sens des balayages : une préférence de main, posée avec l'aide aux
   commandes plutôt que dans le panneau Expert — celui-ci se replie dès qu'on
   choisit un niveau, et la case y serait inatteignable. Cible tactile pleine
   hauteur : on la règle au pouce, souvent en pleine partie. */
.swipe-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  min-height: 44px;
  color: var(--ink);
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
  text-align: left;
}
.swipe-opt.hidden { display: none; }
.swipe-opt input { width: 20px; height: 20px; flex: none; }

/* ======================== Écran de victoire ======================== */

#victoryOverlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(24, 26, 52, 0.65);
  display: grid;
  place-items: center;
  overflow-y: auto;
  padding: calc(16px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right))
           calc(16px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left));
}

.victory-card {
  background: var(--cream);
  border: 5px solid var(--ink);
  border-radius: 28px;
  box-shadow: 0 12px 0 rgba(0, 0, 0, 0.3);
  padding: 26px 30px;
  text-align: center;
  max-width: 460px;
  width: 100%;
  animation: bounceIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes bounceIn {
  from { transform: scale(0.5); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.victory-card h1 {
  margin: 0;
  font-size: 46px;
  color: var(--pink);
  text-shadow: 3px 3px 0 var(--yellow);
}
.victory-sub { font-weight: 800; margin: 4px 0 16px; }

.stats { display: grid; gap: 8px; margin-bottom: 14px; }
.stat {
  display: flex;
  justify-content: space-between;
  gap: 12px; /* sinon libellé et valeur se touchent une fois traduits */
  background: #fff;
  border: 3px solid var(--ink);
  border-radius: 14px;
  padding: 8px 16px;
  font-weight: 800;
}
.stat-label { text-align: left; }
.stat-value { color: var(--pink); }

.seed-line { font-size: 13px; font-weight: 700; opacity: 0.7; margin: 0 0 16px; }

.victory-buttons { display: flex; flex-direction: column; gap: 10px; }
.victory-buttons .big-btn { font-size: 19px; padding: 12px 20px; }

/* ============================ Confettis ============================ */

#confetti {
  position: fixed;
  inset: 0;
  z-index: 95;
  pointer-events: none;
}

/* ============================ Divers ============================ */

@media (max-width: 560px) {
  .hud-pill { font-size: 13px; padding: 4px 10px; }
  .tc { width: 56px; height: 56px; font-size: 22px; }
  .tc-left { grid-template-columns: repeat(3, 56px); }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ============================= Hall of fame ============================= */

.hof-menu-btn { margin-top: 10px; }

.btn-gold {
  background: linear-gradient(180deg, #ffd95e, #ffb300);
  color: #4a3200;
}

.hof-submit {
  margin: 14px auto 4px;
  padding: 12px 14px;
  border: 3px solid var(--ink);
  border-radius: 16px;
  background: #fff8e6;
  max-width: 420px;
}
.hof-submit-title { font-weight: 800; margin: 0 0 8px; }
.hof-submit-row { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.hof-submit-row .big-btn { padding: 10px 22px; font-size: 18px; }
.hof-submit-row input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-weight: 700;
  padding: 10px 12px;
  border: 3px solid var(--ink);
  border-radius: 12px;
}
.hof-submit-result { font-weight: 800; margin: 8px 0 0; min-height: 1.2em; }

/* Les fenêtres modales passent AU-DESSUS de tout, écran de configuration
   compris (z-index 100) : ouvertes depuis le menu, elles étaient sinon peintes
   derrière lui — donc invisibles.
                                                                     ⚠
   UNE SEULE règle pour les quatre, et non quatre copies. Les deux dernières
   nées — Aide et Options — n'avaient QUE leurs styles de contenu : sans
   `position: fixed`, elles restaient dans le flux, en haut du document,
   derrière l'écran de configuration. Elles s'ouvraient bien, on ne les voyait
   pas, et la croix se faisait cliquer à travers par une carte de niveau. Le
   jour où une cinquième arrive, elle s'ajoute ICI. */
#hofOverlay,
#aboutOverlay,
#guideOverlay,
#optionsOverlay,
#seedOverlay,
#quitOverlay {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  padding: calc(16px + env(safe-area-inset-top)) calc(16px + env(safe-area-inset-right))
           calc(16px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left));
  background: rgba(30, 26, 60, 0.55);
}
/* `.hidden` doit gagner contre le `display: grid` ci-dessus : sans cette
   ligne, une fenêtre « cachée » resterait affichée par-dessus le jeu. */
#hofOverlay.hidden,
#aboutOverlay.hidden,
#guideOverlay.hidden,
#optionsOverlay.hidden,
#seedOverlay.hidden,
#quitOverlay.hidden { display: none; }

/* Quitter le niveau. Cette fenêtre-ci s'ouvre PENDANT une partie, donc
   au-dessus du jeu et non de l'accueil : 140, plus haut que toutes les
   autres. Les deux réponses sont côte à côte et de même taille — « je
   continue » d'abord, en bleu, parce que c'est le choix inoffensif. */
#quitOverlay { z-index: 140; }
.quit-card { width: min(94vw, 380px); text-align: center; }
.quit-card h2 { margin: 0 0 6px; }
.quit-text { font-weight: 700; margin: 0 0 16px; }
.quit-actions { display: flex; gap: 10px; justify-content: center; }
.quit-actions .big-btn { flex: 1; min-width: 0; font-size: 17px; padding: 12px 10px; }
.hof-card {
  width: min(94vw, 520px);
  max-height: 88vh;
  overflow: auto;
  background: var(--paper, #fffdf6);
  border: 4px solid var(--ink);
  border-radius: 22px;
  box-shadow: 0 8px 0 rgba(0, 0, 0, 0.25);
  padding: 14px 16px 12px;
}
.hof-head { display: flex; align-items: center; justify-content: space-between; }
.hof-head h2 { margin: 0; }
.hof-tabs { display: flex; gap: 8px; margin: 10px 0; }
.hof-tab {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-weight: 800;
  /* 3 onglets à parts égales dans 94vw : « Schwierig » ou « Gemiddeld » ne
     tiennent pas à 16px sur un téléphone. */
  font-size: clamp(12px, 3.4vw, 16px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 8px 6px;
  border: 3px solid var(--ink);
  border-radius: 12px;
  background: #fff;
  cursor: pointer;
}
.hof-tab.active { background: #ffd95e; }
.tab-emoji { font-size: 1.05em; }

.hof-table { width: 100%; border-collapse: collapse; font-size: 15px; }
.hof-table th, .hof-table td { padding: 6px 8px; text-align: left; }
.hof-table th { border-bottom: 3px solid var(--ink); }
.hof-table tbody tr:nth-child(odd) { background: rgba(0, 0, 0, 0.045); }
.hof-table td.num, .hof-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.hof-table tbody tr:nth-child(1) td:first-child::before { content: '🥇 '; }
.hof-table tbody tr:nth-child(2) td:first-child::before { content: '🥈 '; }
.hof-table tbody tr:nth-child(3) td:first-child::before { content: '🥉 '; }
.hof-msg { text-align: center; font-weight: 700; padding: 18px 6px; }

/* ============================== À propos ============================== */

/* Cadre et fond : voir la règle commune aux quatre fenêtres, plus haut. */
.about-card { max-width: 440px; }
.about-card p { font-weight: 700; line-height: 1.5; margin: 12px 2px; }
/* L'icône de l'application, pas un emoji de remplacement : c'est la seule
   image de cette boîte, autant que ce soit la bonne. Le cadre reprend celui
   des cartes de niveau — l'icône a déjà son fond plein cadre. */
.about-logo {
  display: block;
  margin: 8px auto 4px;
  width: 104px;
  height: 104px;
  border-radius: 24px;
  border: 4px solid var(--ink);
  box-shadow: var(--shadow);
}
.about-copyright {
  text-align: center;
  font-weight: 800 !important;
  opacity: 0.7;
  border-top: 3px solid var(--ink);
  padding-top: 10px;
  margin-bottom: 2px !important;
}
/* Le mouchard de rotation (js/diagnostic.js). Volontairement laid et lisible :
   il n'est là que pour être photographié et lu, jamais pour décorer. */
#diagVoile {
  position: fixed;
  top: calc(50px + env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  padding: 10px 14px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.82);
  color: #fff;
  font-family: ui-monospace, 'Cascadia Mono', Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.55;
  text-align: center;
  white-space: nowrap;
}
#diagVoile b { color: #ffd34d; }
.diag-ok { color: #7be04b; }
.diag-mal { color: #ff5d8f; font-weight: 800; }

/* Le tampon de build : discret, mais lisible et sélectionnable — on doit
   pouvoir le recopier dans un message quand quelque chose cloche. */
.about-build {
  text-align: center;
  font-family: ui-monospace, 'Cascadia Mono', Menlo, Consolas, monospace;
  font-size: 12px;
  opacity: 0.55;
  margin: 2px 0 0 !important;
  user-select: text;
  -webkit-user-select: text;
}

.hof-note { font-size: 12.5px; opacity: 0.75; margin: 10px 2px 0; }

/* ---------------------------------------------------------------------------
   LE SÉLECTEUR DE FORME — au-dessus des cartes, parce que le choix vaut pour
   les huit barreaux et non pour l'un d'eux.

   C'est un vrai `<input type="range">` : il se traîne au pouce, se pousse aux
   flèches du clavier et s'annonce aux lecteurs d'écran, ce qu'une rangée de
   `<div>` cliquables ne fait pas. Le curseur natif est rendu TRANSPARENT et
   posé PAR-DESSUS les marques ; ce qu'on voit est la marque active, agrandie
   et remplie. La zone de saisie couvre donc toute la piste, alors que le
   dessin, lui, reste petit.

   Les polygones sont tracés par js/formes.js à partir de la topologie même,
   pas d'un fichier d'icônes : une forme nouvelle apparaît ici sans qu'on
   dessine quoi que ce soit.
   --------------------------------------------------------------------------- */
.forme-pick {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 18px auto 6px;
  padding: 10px 16px;
  max-width: 520px;
  border: 3px solid transparent;
  border-radius: var(--radius);
  /* Même recette que les cartes : un reflet en haut à gauche, la teinte, et
     un cadre qui suit le même dégradé — sinon l'objet a l'air rapporté. */
  background:
    linear-gradient(152deg,
      rgba(255, 255, 255, 0.72),
      rgba(255, 255, 255, 0) 46%,
      rgba(0, 0, 0, 0.07) 100%) padding-box,
    linear-gradient(#fff2d8, #fff2d8) padding-box,
    linear-gradient(152deg, #3f6350, var(--ink) 62%) border-box;
}
.monde-pick { margin-top: 8px; }
.monde-choix { display: flex; gap: 10px; flex: 1 1 auto; justify-content: center; }
.monde-btn {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 15px;
  border: 3px solid var(--ink);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.55);
  font-family: 'Baloo 2', system-ui, sans-serif;
  font-weight: 800;
  font-size: clamp(13px, 3.4vw, 16px);
  color: var(--ink);
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.22);
}
.monde-btn .monde-emoji { font-size: 1.25em; }
/* « EN TRAVAUX » : un ruban lisible mais discret, sur le bouton et non à côté.
   Le mode urbain n'est pas fini, et l'annoncer AVANT le clic vaut mieux que de
   laisser le découvrir. Il ne doit pas pour autant crier plus fort que le nom
   du mode : petit, en capitales, sur un fond orangé. */
.monde-btn .monde-essai {
  font-size: 0.68em;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 2px 7px;
  border-radius: 999px;
  background: #ff8c42;
  color: #fff;
  border: 2px solid var(--ink);
  white-space: nowrap;
}
/* Le choix retenu doit se voir SANS lire : c'est le même jaune que la touche
   pressée du pavé, pas une nuance de gris qu'un enfant ne distingue pas. */
.monde-btn.active { background: var(--yellow); transform: translateY(2px); box-shadow: 0 2px 0 rgba(0, 0, 0, 0.22); }

.forme-titre {
  font-family: 'Baloo 2', system-ui, sans-serif;
  font-weight: 800;
  color: var(--ink);
  font-size: clamp(14px, 3.6vw, 17px);
}
.forme-piste {
  position: relative;
  flex: 1 1 190px;
  min-width: 150px;
  height: 46px;
}
.forme-marques {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 6px;
  pointer-events: none;
}
/* La barre qui relie les stops : elle dit « c'est un curseur », pas « ce sont
   des boutons ». Posée derrière les marques, jamais devant. */
.forme-marques::before {
  content: '';
  position: absolute;
  left: 16px;
  right: 16px;
  top: 50%;
  height: 6px;
  margin-top: -3px;
  border-radius: 3px;
  background: linear-gradient(90deg, rgba(22, 48, 31, 0.16), rgba(22, 48, 31, 0.28));
}
.forme-marque {
  position: relative;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--cream);
  border: 2px solid rgba(22, 48, 31, 0.22);
  transition: transform 0.16s ease, background 0.16s ease, border-color 0.16s ease;
}
.forme-marque svg { display: block; }
.forme-marque polygon {
  fill: none;
  stroke: rgba(22, 48, 31, 0.42);
  stroke-width: 2.4;
  stroke-linejoin: round;
  transition: fill 0.16s ease, stroke 0.16s ease;
}
.forme-marque.active {
  transform: scale(1.22);
  background: linear-gradient(152deg, #ffffff, var(--lime) 130%);
  border-color: var(--ink);
}
.forme-marque.active polygon { fill: var(--lime); stroke: var(--ink); }

/* Le curseur natif : invisible, mais c'est LUI qu'on manipule. */
.forme-piste input[type="range"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
}
.forme-piste input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 44px;
  height: 44px;
}
.forme-piste input[type="range"]::-moz-range-thumb {
  width: 44px;
  height: 44px;
  border: 0;
}
/* Le focus clavier doit se voir : le curseur étant transparent, c'est le
   cadre du bloc entier qui le porte. */
.forme-piste input[type="range"]:focus-visible ~ .forme-marques .forme-marque.active,
.forme-pick:focus-within .forme-marque.active {
  box-shadow: 0 0 0 3px var(--sky);
}
.forme-nom {
  font-family: 'Baloo 2', system-ui, sans-serif;
  font-weight: 700;
  color: var(--ink);
  font-size: clamp(13px, 3.4vw, 16px);
  min-width: 5.5em;
  text-align: left;
}
