/* ============================================================
   app.css - coque, ecrans, composants
   ============================================================ */

/* ---------- coque ---------- */
/* Coque d'application : hauteur fixe, entete et onglets hors du flux
   de defilement, et une seule zone qui defile. Sans conteneur borne,
   aucun contenu ne peut se comprimer pour tenir dans l'ecran. */
#appli{height:100dvh;display:flex;flex-direction:column;overflow:hidden}

/* ------------------------------------------------------------
   Pourquoi l'entete et les onglets n'ont PAS de backdrop-filter
   ------------------------------------------------------------
   Les deux barres portaient saturate(160%) blur(14px) sur un fond
   deja opaque a 88 et 92 %. Un flou d'arriere-plan se recalcule a
   chaque image tant que quelque chose bouge dessous - donc pendant
   tout le defilement de #vue, sur toute la largeur, en permanence,
   des deux cotes de l'ecran. C'est le poste le plus cher de
   l'application sur un iPhone, et a cette opacite il ne se voyait
   pratiquement pas.

   Les barres sont donc opaques, et le flou reste la ou il raconte
   quelque chose : les voiles qui passent - modale, fete, ticket -
   qui durent quelques secondes et masquent un ecran arrete.
   ------------------------------------------------------------ */
#entete{
  flex:none;z-index:30;
  padding:calc(var(--haut) + 10px) 16px 10px;
  display:flex;align-items:center;gap:12px;
  background:var(--fond);
  border-bottom:1px solid transparent;
  transition:border-color .2s;
}
#entete.defile{border-bottom-color:var(--trait)}
#entete .qui{flex:1;min-width:0}
#entete .qui b{display:block;font-family:'Fredoka';font-size:1.15rem;line-height:1.1}
#entete .qui small{display:block;font-size:.76rem;color:var(--gris);font-weight:700}
#entete .rond{
  flex:none;width:44px;height:44px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--papier);
  box-shadow:var(--rebord), var(--arete), var(--ombre-s);
  color:var(--gris);
  transition:transform .18s var(--ressort), color .18s;
}
#entete .rond:active{color:var(--saison-encre)}
#entete .rond:active{transform:scale(.9)}
.avatar{
  flex:none;width:46px;height:46px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-family:'Fredoka';font-size:1.25rem;color:#fff;
  background:var(--saison);box-shadow:var(--ombre-s);
}

#vue{
  flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  padding:8px 16px 24px;max-width:760px;width:100%;margin:0 auto;
}

#onglets{
  flex:none;z-index:30;
  display:grid;grid-template-columns:repeat(4,1fr);
  padding:6px 8px calc(var(--bas) + 6px);
  /* opaque, et sans flou : voir le commentaire de #entete */
  background:var(--papier);
  border-top:1px solid var(--trait);
}
#onglets a{
  display:flex;flex-direction:column;align-items:center;gap:2px;
  padding:8px 4px;min-height:56px;border-radius:var(--r-m);
  color:var(--gris);text-decoration:none;
  font-family:'Fredoka';font-size:.72rem;
  transition:color .2s, transform .2s var(--ressort);
}
#onglets a .ico{
  display:flex;align-items:center;justify-content:center;height:26px;
  transition:transform .3s var(--ressort);
}
#onglets a .ico svg{display:block}
#onglets a.actif{color:var(--saison-encre)}
#onglets a.actif .ico{transform:translateY(-3px) scale(1.12)}
/* L'onglet actif se pose sur une pastille de saison : le seul marqueur
   etait la couleur du trait, invisible d'un coup d'oeil. */
#onglets a.actif::before{
  content:"";position:absolute;inset:2px 6px;border-radius:var(--r-m);
  background:color-mix(in srgb, var(--saison) 13%, transparent);
  z-index:-1;
  animation:pose .3s var(--doux) both;
}
#onglets a{position:relative;isolation:isolate}
#onglets a:active{transform:scale(.93)}

/* ---------- la coque sur un ecran court ----------
   Sur un iPhone SE, l'entete et les onglets prennent 141 px des
   667 disponibles, soit un cinquieme de l'ecran pour deux barres.
   On les resserre : les cibles tactiles restent au-dessus de 44 px,
   et les 22 px recuperes vont au texte du defi. */
@media (max-height:700px){
  #entete{padding:calc(var(--haut) + 6px) 16px 6px}
  #entete .avatar-figurine .figurine{width:38px;height:38px}
  #entete .qui b{font-size:1.05rem}
  #entete .rond{width:40px;height:40px}
  #onglets{padding:4px 8px calc(var(--bas) + 4px)}
  #onglets a{min-height:50px;padding:6px 4px}
  #onglets a .ico{height:24px}
}

/* ---------- chargement ---------- */
/* Une annee qui defile derriere trois compagnons. Le detail du parti
   pris est en tete du bloc, dans index.html ; ici, deux choses
   comptent :

   1. RIEN N'EST CALE SUR UNE HAUTEUR D'ECRAN. Le ciel s'etire
      (preserveAspectRatio="none" sur un viewBox de 10 de haut), le
      sol et les compagnons sont ancres EN BAS, et les particules
      tombent en `vh`. La maquette etait figee en 390x844 ; ici ca
      doit tenir du SE a l'ordinateur.
   2. LE FOND DE #chargement N'EST PAS DECORATIF. app.js remplace son
      contenu par un simple <p> quand le carnet ne s'ouvre pas : le
      decor disparait alors, et le message doit rester lisible sur
      une couleur pleine. D'ou ce fond, et le centrage qui reste. */
#chargement{
  position:fixed;inset:0;z-index:90;overflow:hidden;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  background:#FBDFC9;
}
/* UNE TUILE D'UNE ANNEE, REPETEE PAR LE NAVIGATEUR.
   ------------------------------------------------------------
   Le ciel et le sol faisaient 3360 px de large (deux annees bout a
   bout) et glissaient en `transform`. C'etait fluide sur un
   ordinateur et lourd sur un telephone : 61 Mo de texture a DPR 2,
   le double a DPR 3 - mesure, et signale par Xavier qui voyait
   l'ouverture ramer.

   Ici les deux elements font la taille de l'ECRAN. Le motif d'une
   annee (1680 px) est repete par `background-repeat`, et c'est la
   POSITION du fond qui avance. Deux conditions pour que la
   repetition ne se voie pas, et elles valent aussi pour la tuile du
   sol : la couleur a 0 et a 1680 est la meme, et les ondulations ont
   des periodes qui divisent 1680 (420 et 560).

   La tuile du sol est un SVG GENERE - collines, sol et huit arbres.
   Elle est ecrite ici plutot que dans un fichier a part pour que cet
   ecran ne depende d'aucune requete : c'est le premier affiche, avant
   tout le reste. Sa recette est dans CLAUDE.md, avec celle des
   compagnons. */
.ch-ciel{
  position:absolute;inset:0;
  background-image:linear-gradient(90deg,
    #FBDFC9 0px, #D9EAF3 420px, #DCEFE1 840px, #F8E7C0 1260px, #FBDFC9 1680px);
  background-size:1680px 100%;
  background-repeat:repeat-x;
}
.ch-sol{
  position:absolute;bottom:0;left:0;right:0;height:420px;
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='1680' height='420' viewBox='0 0 1680 420'><defs><linearGradient id='l' x1='0' y1='0' x2='1' y2='0'><stop offset='0%' stop-color='%23B7CE97'/><stop offset='25%' stop-color='%23E4EFF4'/><stop offset='50%' stop-color='%23A7DEB1'/><stop offset='75%' stop-color='%23DCC77E'/><stop offset='100%' stop-color='%23B7CE97'/></linearGradient><linearGradient id='p' x1='0' y1='0' x2='1' y2='0'><stop offset='0%' stop-color='%2395AE6E'/><stop offset='25%' stop-color='%23CBDDE6'/><stop offset='50%' stop-color='%2376C48C'/><stop offset='75%' stop-color='%23C0A552'/><stop offset='100%' stop-color='%2395AE6E'/></linearGradient></defs><path fill='url(%23l)' d='M0 184 q140 -48 280 0 t280 0 t280 0 t280 0 t280 0 t280 0 V420 H0 Z'/><path fill='url(%23p)' d='M0 244 q105 -11 210 0 t210 0 t210 0 t210 0 t210 0 t210 0 t210 0 t210 0 V420 H0 Z'/><g><rect x='96' y='194' width='9' height='46' rx='4' fill='%239A5A22'/><circle cx='100' cy='176' r='34' fill='%23C4682A'/><circle cx='112' cy='164' r='22' fill='%23E0561F' opacity='.75'/></g><g><rect x='296' y='202' width='7' height='38' rx='3' fill='%239A5A22'/><circle cx='299' cy='186' r='25' fill='%23D9832F'/></g><g><rect x='516' y='198' width='8' height='42' rx='4' fill='%237A5A3A'/><path d='M520 128 l30 46 h-60 z' fill='%234A7A5E'/><path d='M520 158 l34 44 h-68 z' fill='%235D8E72'/></g><g><rect x='716' y='208' width='7' height='34' rx='3' fill='%237A5A3A'/><path d='M719 156 l24 38 h-48 z' fill='%235D8E72'/><path d='M719 180 l27 34 h-54 z' fill='%234A7A5E'/></g><g><rect x='936' y='196' width='9' height='46' rx='4' fill='%238A6B45'/><circle cx='940' cy='178' r='33' fill='%236BB47C'/><circle cx='952' cy='166' r='20' fill='%238FD0A0' opacity='.85'/><circle cx='928' cy='168' r='4.5' fill='%23FFC8E6'/><circle cx='954' cy='186' r='4' fill='%23FFB8E0'/></g><g><rect x='1136' y='206' width='7' height='36' rx='3' fill='%238A6B45'/><circle cx='1139' cy='190' r='24' fill='%238FD0A0'/><circle cx='1131' cy='182' r='4' fill='%23FFC8E6'/></g><g><rect x='1356' y='194' width='9' height='48' rx='4' fill='%238A6B45'/><circle cx='1360' cy='174' r='35' fill='%235FA070'/><circle cx='1373' cy='162' r='21' fill='%237FB86A' opacity='.8'/></g><g fill='%23C0A552'><rect x='1548' y='208' width='4' height='34' rx='2'/><rect x='1566' y='214' width='4' height='28' rx='2'/><rect x='1584' y='210' width='4' height='32' rx='2'/><ellipse cx='1550' cy='206' rx='6' ry='9' fill='%23DCC77E'/><ellipse cx='1568' cy='212' rx='5' ry='8' fill='%23DCC77E'/><ellipse cx='1586' cy='208' rx='6' ry='9' fill='%23DCC77E'/></g></svg>");
  background-size:1680px 420px;
  background-repeat:repeat-x;
}
/* Les compagnons ne defilent pas : ils sont centres sur l'ecran, a
   toute largeur, et ancres au meme sol que la bande qui passe. */
.ch-perso{
  position:absolute;bottom:0;left:50%;margin-left:-195px;
  width:390px;height:420px;display:block;
}
.ch-meteo{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.ch-p{position:absolute;left:var(--x);top:0;line-height:0}
.ch-w4 .ch-p{top:auto;bottom:0}

/* La marque reste au centre, remontee pour ne pas tomber dans le
   paysage : c'est la seule mesure qui depend de la hauteur du sol. */
.ch-marque{
  position:relative;z-index:2;
  display:flex;flex-direction:column;align-items:center;gap:16px;
  margin-bottom:200px;
}
.ch-logo-boite{position:relative;display:flex;align-items:center;justify-content:center}
.ch-halo{
  position:absolute;width:190px;height:190px;border-radius:50%;
  filter:blur(44px);opacity:.3;background:#E0561F;
}
.ch-souffle{position:relative}
.ch-logo{display:block;filter:drop-shadow(0 12px 24px rgba(22,35,63,.22))}
.ch-nom{
  font-family:'Fredoka';font-weight:700;font-size:2.2rem;line-height:1.05;
  color:var(--encre);text-align:center;margin:0;
}
/* Les trois points respirent l'un apres l'autre : c'est ce qui dit
   que quelque chose travaille, sans barre de progression - on ne sait
   pas combien de temps ca va prendre, on ne fera donc pas semblant. */
.ch-attente{
  display:flex;align-items:center;gap:4px;margin:0;
  font-family:'Fredoka';font-size:.94rem;font-weight:600;color:var(--gris);
}
.ch-attente i{
  width:5px;height:5px;border-radius:50%;background:var(--gris);
  display:inline-block;
}
.ch-attente i:first-of-type{margin-left:5px}

@media (max-height:700px){
  .ch-marque{margin-bottom:170px;gap:12px}
  .ch-nom{font-size:1.9rem}
  .ch-logo{width:92px;height:92px}
}

/* ---------- bandeau hors ligne ---------- */
#horsligne{
  position:fixed;left:12px;right:12px;bottom:calc(var(--bas) + 76px);z-index:40;
  padding:10px 16px;border-radius:var(--r-m);
  background:var(--encre);color:#fff;font-size:.85rem;font-weight:700;text-align:center;
  box-shadow:var(--ombre-m);cursor:pointer;
  transition:opacity .3s, transform .3s;
}
/* il se retire au bout de quelques secondes (7.0.0) : voir
   surveillerReseau() dans js/app.js */
#horsligne.s-efface{opacity:0;transform:translateY(8px)}

/* ============================================================
   Écran d'accueil : illustration pleine page + carte d'accès
   ============================================================ */
/* La porte d'entree ne defile jamais : elle tient dans l'ecran, quel
   qu'il soit. Le fond reprend la teinte haute du ciel - c'est aussi ce
   que certains navigateurs echantillonnent pour teinter la barre
   d'etat en application installee, et un bleu pale y faisait une bande
   froide au-dessus d'un ciel peche. */
.porte{
  position:fixed;inset:0;display:flex;flex-direction:column;
  overflow:hidden;background:#FFE3BE;
}

/* ---- l'illustration ---- */
/* L'illustration occupe tout ce que la carte d'acces laisse : il ne
   peut donc plus rester de blanc sous les boutons. Elle cede de la
   hauteur quand le formulaire e-mail se deplie, plutot que de pousser
   les boutons hors de l'ecran. */
.hero-scene{
  position:relative;flex:1 1 38vh;width:100%;min-height:0;
  overflow:hidden;
  /* meme teinte que le haut du ciel : ce qui depasse du dessin se fond */
  background:#FFE3BE;
}
/* Le dessin garde ses proportions et s'ancre en bas ; c'est le bandeau
   qui le rogne par le haut quand il manque de hauteur. Etire a la
   hauteur de la boite, il se reduisait a un timbre-poste centre des
   que le formulaire e-mail depliait la carte d'acces. Au-dela de sa
   hauteur naturelle, min-height reprend la main et le complement se
   fond dans la teinte haute du ciel, comme avant. */
.hero-fond{
  display:block;position:absolute;left:0;right:0;bottom:0;
  width:100%;height:auto;min-height:100%;
}
.hero-perso{
  transform-box:fill-box;transform-origin:center bottom;
  filter:drop-shadow(0 4px 5px rgba(22,35,63,.24));
  animation:perso-flotte 3.6s ease-in-out infinite;
  animation-delay:var(--d);
}
/* La rotation sur 44 s etait imperceptible, et coutait une animation
   permanente sur le tout premier ecran - celui qui en fait deja tourner
   une douzaine. Retiree : c'est ce qui finance le reste. */
.hero-soleil{transform-origin:48px 44px}
.hero-nuage.n1{animation:nuage-derive 26s linear infinite}
.hero-nuage.n2{animation:nuage-derive 34s linear infinite reverse}
.hero-chemin-tirets{animation:chemin-avance 5s linear infinite}
.hero-coffre{transform-box:fill-box;transform-origin:center;animation:respire 3s ease-in-out infinite}
.hero-etincelles .e1{animation:etincelle-lueur 2.4s ease-in-out infinite}
.hero-etincelles .e2{animation:etincelle-lueur 2.4s .5s ease-in-out infinite}
.hero-etincelles .e3{animation:etincelle-lueur 2.4s 1s ease-in-out infinite}

/* ---- la carte d'accès ---- */
.porte-carte{
  /* Elle garde sa hauteur naturelle et ne cede rien : c'est le dessin
     qui se resserre. Dans le cas extreme - petit ecran, formulaire
     e-mail ouvert - elle se plafonne a l'ecran et defile en dedans,
     pour qu'aucun bouton ne soit jamais hors d'atteinte. */
  flex:0 0 auto;max-height:100%;overflow-y:auto;overscroll-behavior:contain;
  margin-top:-26px;
  background:var(--fond);
  border-radius:28px 28px 0 0;
  box-shadow:0 -8px 30px rgba(22,35,63,.14);
  padding:24px 22px calc(var(--bas) + 22px);
  display:flex;flex-direction:column;gap:9px;
  width:100%;max-width:460px;margin-left:auto;margin-right:auto;
  animation:monte .5s var(--doux) both;
}
.porte-marque{display:flex;justify-content:center;margin-bottom:2px}
.porte-promesse{
  text-align:center;color:var(--gris);font-size:.93rem;line-height:1.45;
  margin-bottom:8px;
}
.porte-carte .erreur{
  background:var(--automne-clair);color:var(--automne-fonce);
  padding:12px 16px;border-radius:var(--r-m);font-size:.88rem;font-weight:700;
}
.porte-carte form{display:flex;flex-direction:column;gap:0;animation:monte .3s var(--doux)}
.porte-carte .lien-bas{margin-top:14px;text-align:center;font-size:.88rem;color:var(--gris)}
.porte-carte .lien-bas button{color:var(--hiver-fonce);font-weight:800;text-decoration:underline}

/* ---- le logo ---- */
.logo{display:inline-flex;align-items:center;gap:10px}
.logo-marque{flex:none;filter:drop-shadow(0 3px 6px rgba(224,86,31,.3))}
.logo-mots{display:flex;flex-direction:column;line-height:1;text-align:left}
.logo-mots b{
  font-family:'Fredoka';font-weight:700;font-size:calc(var(--h) * .46);
  letter-spacing:-.02em;color:var(--encre);
}
.logo-mots em{
  font-family:'Fredoka';font-style:normal;font-weight:600;
  font-size:calc(var(--h) * .38);color:var(--automne-fonce);letter-spacing:.01em;
}

.bouton-google{
  width:100%;min-height:56px;border-radius:var(--r-m);
  background:var(--papier);box-shadow:inset 0 0 0 2px var(--trait);
  display:flex;align-items:center;justify-content:center;gap:10px;
  font-family:'Fredoka';font-size:1.05rem;
  transition:transform .18s var(--ressort);
}
.bouton-google:active{transform:scale(.97)}
.bouton-google svg{width:20px;height:20px;flex:none}

/* ============================================================
   Ecran enfants
   ============================================================ */
.liste-enfants{display:flex;flex-direction:column;gap:12px;margin-bottom:22px}
/* la ligne : le carnet, et la corbeille à côté — deux boutons frères,
   parce qu'un bouton dans un bouton n'est pas du HTML valide */
.ligne-enfant{display:flex;align-items:center;gap:8px}
.ligne-enfant .tuile-enfant{flex:1;min-width:0}
.tuile-supprimer{
  flex:none;width:44px;height:44px;border-radius:var(--r-m);
  display:flex;align-items:center;justify-content:center;
  background:var(--papier);box-shadow:var(--ombre-s);
  opacity:.55;
  transition:transform .18s var(--ressort), opacity .2s;
}
.tuile-supprimer:active{transform:scale(.9);opacity:1}
@media (hover:hover){ .tuile-supprimer:hover{opacity:1} }
.tuile-enfant{
  display:flex;align-items:center;gap:14px;width:100%;text-align:left;
  background:var(--papier);border-radius:var(--r-l);padding:16px;
  box-shadow:var(--ombre-s);
  transition:transform .18s var(--ressort), box-shadow .18s;
}
.tuile-enfant:active{transform:scale(.98)}
.tuile-enfant .nom{flex:1;min-width:0}
.tuile-enfant .nom b{display:block;font-family:'Fredoka';font-size:1.2rem}
.tuile-enfant .nom small{color:var(--gris);font-weight:700;font-size:.82rem}
.tuile-enfant .fleche{color:var(--trait);font-size:1.3rem}

/* ============================================================
   Ecran accueil
   ============================================================ */
.bandeau-semaine{
  display:flex;align-items:center;justify-content:space-between;gap:8px;margin:6px 0 14px;
}
.bandeau-semaine .nav{
  width:44px;height:44px;border-radius:50%;background:var(--papier);
  display:flex;align-items:center;justify-content:center;color:var(--gris);
  box-shadow:var(--ombre-s);font-size:1.1rem;
  transition:transform .18s var(--ressort);
}
.bandeau-semaine .nav:active{transform:scale(.88)}
.bandeau-semaine .nav:disabled{opacity:.25}
.bandeau-semaine .centre{text-align:center;flex:1}
.bandeau-semaine .centre b{display:block;font-family:'Fredoka';font-size:1.05rem}
.bandeau-semaine .centre small{font-size:.76rem;color:var(--gris);font-weight:700}

/* Le halo d'angle est un FOND, pas un pseudo-élément.
   ------------------------------------------------------------
   Il était un disque en position absolue, ce qui obligeait la carte à
   `overflow:hidden` pour le rogner. Or `overflow:hidden` annule la
   taille minimale automatique d'un élément flex : la carte acceptait
   alors de se réduire en dessous de son propre contenu, et tranchait
   son action au passage. En fond, le halo est rogné par le
   border-radius tout seul, et la carte peut retrouver un
   `min-height:auto` qui la protège.

   Un dégradé, pas un aplat : l'ancien disque de --saison-clair à 75 %
   d'opacité lisait comme une tache posée sur la carte. Même emprise,
   mais une lumière qui entre par l'angle et se dissipe. */
.carte-defi{
  position:relative;
  background:
    radial-gradient(150px 150px at calc(100% - 4px) 56px,
      color-mix(in srgb, var(--saison) 26%, #fff) 0%,
      color-mix(in srgb, var(--saison) 9%, #fff) 46%,
      transparent 72%),
    var(--grain),
    var(--papier);
  border-radius:var(--r-xl);padding:24px 22px;
  box-shadow:var(--rebord), var(--ombre-m);
}
.carte-defi .haut{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px}
.carte-defi .numero{
  display:inline-flex;align-items:center;gap:6px;
  font-family:'Fredoka';font-weight:700;font-size:1rem;color:var(--saison-encre);
}
.carte-defi .numero .signe{flex:none}
.carte-defi .saison-carte{display:none;white-space:pre}
.ecran-jeu:has(.ou-suis-je) .carte-defi .saison-carte{display:inline}
.carte-defi .pastille svg{flex:none}
.carte-defi h2{font-size:1.75rem;margin-bottom:8px}
.carte-defi .domaine{
  font-family:'Fredoka';font-size:.9rem;color:var(--gris);margin-bottom:14px;
}
.carte-defi .quoi{font-size:1.05rem;color:var(--encre-douce);line-height:1.55}
.carte-defi.est-coffre{border-top-color:var(--coffre)}
/* même halo, dans la teinte des coffres */
.carte-defi.est-coffre{
  background:
    radial-gradient(150px 150px at calc(100% - 4px) 56px,
      color-mix(in srgb, var(--coffre) 26%, #fff) 0%,
      color-mix(in srgb, var(--coffre) 9%, #fff) 46%,
      transparent 72%),
    var(--grain),
    var(--papier);
}
.carte-defi.est-coffre .numero{color:var(--coffre-encre)}

.ruban-fait{
  display:flex;align-items:center;gap:10px;margin-top:18px;padding:14px 16px;
  background:var(--printemps-clair);border-radius:var(--r-m);
  font-weight:800;color:var(--printemps-encre);font-size:.95rem;
}
.ruban-fait .coche{
  flex:none;width:30px;height:30px;border-radius:50%;background:var(--printemps);
  color:#fff;display:flex;align-items:center;justify-content:center;font-size:.95rem;
}
.ruban-jeton{background:var(--coffre-clair);color:var(--coffre-encre)}
.ruban-jeton .coche{background:var(--coffre)}

/* soirs */
.bloc-soirs{margin-top:20px}
.bloc-soirs .consigne{
  font-size:.86rem;color:var(--gris);line-height:1.45;margin-bottom:14px;
}
/* La phrase de contexte, SOUS la ligne des soirs : elle la commente,
   donc elle n'a pas de marge apres elle - celle de .consigne laissait
   14 px de vide au bas du bloc, ce qui suffisait a pousser la rangee
   des trois chiffres sous les onglets en etat jeton. */
.bloc-soirs .consigne--note{
  margin-top:14px;margin-bottom:0;border-color:var(--note, var(--trait));
}
.bloc-soirs .consigne--fort{color:var(--note);font-weight:800}
.soirs{display:flex;gap:10px;justify-content:space-between}
.soir{
  flex:1;aspect-ratio:1/1.15;min-width:0;min-height:60px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  /* Une etiquette de papier, plus un champ de formulaire (7.2.0) : le
     cadre gris de 2,5 px faisait « case a remplir ». Rien n'est pose
     sur un soir non coche pour autant - ni pointilles, ni lanterne
     eteinte : juste du papier, et son nom. */
  background:var(--papier);border:0;border-radius:var(--r-m);
  box-shadow:0 1px 1px rgba(74,48,24,.10), 0 3px 8px rgba(74,48,24,.07),
             inset 0 -3px 0 rgba(74,48,24,.05);
  font-family:'Fredoka';color:var(--encre-douce);
  transition:transform .2s var(--ressort), background .25s, border-color .25s, color .25s;
}
/* Le nom du jour, en entier. Il reste léger : petite graisse, une
   seule ligne, jamais de coupure — c'est une étiquette, pas un titre. */
.soir .lettre{
  font-size:.82rem;font-weight:600;line-height:1;
  letter-spacing:-.015em;text-transform:capitalize;
  max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:clip;
}
/* cinq soirs dans la même largeur : « mercredi » est le mot le plus
   long du carnet à cet endroit, c'est lui qui fixe la taille */
.soirs--cinq .soir .lettre{font-size:.68rem;letter-spacing:-.03em}
/* La flamme remplace la coche DANS la meme hauteur : l'ecran de jeu
   contraint les cases a 66 px, 58 sur un ecran court, et rien ne doit
   s'ajouter a cote. */
.soir .etat{
  display:flex;align-items:center;justify-content:center;
  height:19px;line-height:1;
}
.soir .flamme{display:block;filter:drop-shadow(0 1px 2px rgba(240,144,44,.5))}
.soir:active{transform:scale(.92)}
.soir.coche{
  background:var(--printemps-fonce);color:#fff;
  box-shadow:0 0 0 3px color-mix(in srgb, #FFD166 28%, transparent),
             0 5px 14px color-mix(in srgb, var(--printemps) 38%, transparent);
}

/* ---------- la ligne de lanternes ---------- */
/* Une ligne pleine se lit d'un coup d'oeil, sans qu'on ait a compter.
   Et rien, jamais, n'est pose sur les cases non cochees. */
.soirs{position:relative}
.soirs.pleine .soir.coche{
  box-shadow:0 4px 16px color-mix(in srgb, #F0902C 34%, transparent),
             0 0 0 2px color-mix(in srgb, #FFD166 44%, transparent);
}
/* le filet lumineux qui relie les lanternes, au moment ou la derniere
   s'allume : un seul balayage, jamais en boucle */
.soirs.s-allume::after{
  content:"";position:absolute;left:0;right:0;top:50%;height:3px;
  transform:translateY(-50%);border-radius:2px;pointer-events:none;
  background:linear-gradient(90deg,
    rgba(255,209,102,0) 0%, rgba(255,241,190,.95) 48%, rgba(255,209,102,0) 100%);
  background-size:55% 100%;background-repeat:no-repeat;
  animation:filet-lumiere .64s var(--doux) both;
}
/* chaque flamme monte d'un cran, de gauche a droite */
.soirs.s-allume .soir.coche .flamme{
  animation:flamme-monte .5s var(--ressort) both;
  animation-delay:calc(var(--i, 0) * 85ms);
}

/* ---------- progression, version compacte ----------
   Tout l'écran d'accueil doit tenir sans défilement sur un téléphone :
   une barre, une ligne de chiffres, une ligne de contexte. */
.progression{margin-top:2px}
.barre{
  position:relative;height:14px;border-radius:999px;background:#E4E7EE;
  overflow:visible;
}
/* La barre de l'année ne se fige jamais.
   ------------------------------------------------------------
   Elle ne bougeait qu'une fois par semaine, le temps d'une
   transition de largeur. Entre deux, c'était un trait peint. Deux
   mouvements très lents s'y superposent : un reflet qui traverse le
   chemin parcouru, et une respiration de la couleur. Rien n'y compte
   ni n'y clignote - c'est de la matière vivante, pas une alerte. */
.barre span{
  display:block;height:100%;border-radius:999px;
  background-image:linear-gradient(90deg,var(--automne) 0%,var(--hiver) 30%,
    var(--printemps) 58%,var(--ete) 86%,var(--coffre) 100%);
  background-repeat:no-repeat;
  transition:width .9s var(--doux);
  position:relative;overflow:hidden;
  animation:barre-respire 7s ease-in-out infinite;
}
/* Le reflet se DEPLACE, il ne se repeint pas.
   Il animait background-position : une propriete que le compositeur ne
   sait pas jouer seul, donc un repeint a chaque image, en boucle et
   pour toujours, sur l'ecran que l'enfant ouvre tous les soirs. Une
   bande large posee a cote, glissee par transform, donne exactement le
   meme passage de lumiere et ne repeint plus rien. */
.barre span::after{
  content:"";position:absolute;top:0;bottom:0;
  left:-60%;width:60%;
  background:linear-gradient(100deg,
    rgba(255,255,255,0) 0%, rgba(255,255,255,.5) 50%, rgba(255,255,255,0) 100%);
  animation:barre-reflet 5.2s linear infinite;
}

/* Le titre de l'année garde ses distances avec la barre : les coffres
   débordent de 13 px au-dessus d'elle, et un coffre qui sautille montait
   jusque dans le « 50 % ». */
.progression .titre-section{margin-bottom:34px}

/* ---------- les quatre coffres, posés sur la barre ---------- */
.jalon-barre{
  position:absolute;top:50%;transform:translate(-50%,-50%);
  width:27px;height:27px;border-radius:50%;padding:0;
  background:#E4E7EE;border:2.5px solid var(--papier);
  display:flex;align-items:center;justify-content:center;
  transition:background .3s, transform .3s var(--ressort);
}
/* La cible tactile fait 44 px, comme partout, sans que la pastille
   grossisse : les quatre sont espacés de 86 px, elles ne se marchent
   pas dessus. */
.jalon-barre::before{content:"";position:absolute;inset:-10px;border-radius:50%}
.jalon-barre .ico-svg{display:block;vertical-align:0}
/* Fermé, il garde sa couleur - le carnet papier annonce ses quatre
   coffres dès la première page, il n'y a rien à cacher - mais il ne
   brille pas : pastille neutre, pas de halo, pas de mouvement. */
.jalon-barre:not(.ouvert) .ico-svg{opacity:.9}
.jalon-barre.ouvert{
  background:var(--coffre-clair);border-color:var(--papier);
  box-shadow:0 2px 6px rgba(122,59,150,.28);
}
/* Gagné mais pas encore vu : il sautille, et il s'arrête dès qu'on est
   allé le voir. Le halo derrière lui fait qu'on l'attrape du coin de
   l'œil sans avoir à chercher. */
.jalon-barre.sautille{
  animation:coffre-sautille 1.9s var(--ressort) infinite;
  z-index:2;
}
.jalon-barre.sautille::after{
  content:"";position:absolute;inset:-7px;border-radius:50%;
  background:radial-gradient(circle,
    rgba(255,209,102,.75) 0%, rgba(255,209,102,0) 70%);
  z-index:-1;
  animation:coffre-halo 1.9s ease-in-out infinite;
}

/* ---------- le compagnon sur la barre (7.2.0) ----------
   Il remplace les trois tuiles de chiffres. Debout SUR la barre : son
   bas touche le haut du trait, et il passe devant un coffre quand il y
   arrive, ce qui est exactement ce qu'il fait. Borne a 14 px des deux
   bouts pour ne jamais sortir du cadre, en semaine 1 comme en 36. */
.pion-barre{
  position:absolute;top:50%;z-index:2;pointer-events:none;
  left:clamp(14px, var(--part, 0%), calc(100% - 14px));
  width:36px;height:36px;transform:translate(-50%,-92%);
  filter:drop-shadow(0 2px 2px rgba(74,48,24,.22));
  transition:left 1.1s var(--doux);
}
.pion-barre svg{display:block;width:100%;height:100%}

.annee-ligne{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin-top:14px;font-family:'Fredoka';font-size:1rem;color:var(--encre-douce);
}
.annee-ligne b{font-size:1.3rem;color:var(--saison-encre);margin-right:5px}
.annee-ligne .jetons{display:inline-flex;align-items:center;gap:2px;color:var(--gris)}
.annee-ligne .jetons b{font-size:1rem;color:var(--coffre-encre);margin:0 0 0 4px}
.annee-ligne .jetons svg{display:block}
.prochain-coffre{
  text-align:center;color:var(--gris);font-size:.84rem;margin-top:12px;
}

/* jetons */
.jetons{display:flex;gap:7px;align-items:center;justify-content:center;margin-top:4px}
.jeton-pion{
  width:24px;height:24px;border-radius:50%;
  border:2.5px dashed var(--coffre);color:var(--coffre);
  display:flex;align-items:center;justify-content:center;font-size:.7rem;font-weight:800;
}
.jeton-pion.plein{background:var(--coffre);border-style:solid;color:#fff}
.jeton-pion.use{opacity:.25}

/* ============================================================
   Ecran plateau
   ============================================================ */
/* Le plateau traverse les quatre terres dans l'ordre reel : Automne,
   Hiver, Printemps, Ete, chacune occupant un quart exact (9 semaines
   sur 36, toujours). Un degrade fixe en CSS pur suffit donc - pas de
   JS, pas de mesure au rendu : l'ordre et les proportions ne varient
   jamais, contrairement a la carte du defi de l'accueil qui, elle,
   depend de la semaine qu'on feuillette (voir ui/accueil.js).

   TOUJOURS LES TEINTES -CLAIR, JAMAIS LES TEINTES DE BASE.
   ------------------------------------------------------------
   `.entete-saison h3` n'a pas de fond a elle : le texte, en
   `--t-encre`, flotte directement sur ce qui est derriere
   `.saison-bloc`. Une premiere version de ce degrade avec les
   teintes de base (var(--automne) etc.) posait donc un texte fonce
   sur un fond sature de la MEME teinte - quasi illisible, signale
   par Xavier sur une maquette avant que la moindre ligne ne soit
   ecrite ici. Les teintes -clair sont exactement le fond sur lequel
   le reste du carnet pose deja du texte -fonce/-encre (la pastille de
   l'accueil : `.pastille{background:var(--saison-clair);
   color:var(--saison-fonce)}`) - la meme paire, deja validee.

   SUBTIL VEUT DIRE CONTENU, PAS ETALE (demande explicite de Xavier).
   Le degrade reste DANS la boite du plateau (padding + border-radius,
   pas de fuite hors de #vue) et les zones plates de chaque teinte
   sont larges : la transition ne se voit vraiment que dans le
   gap de 10px entre deux blocs et sous l'entete de saison, jamais au
   milieu d'une grille de neuf cases - qui, elles, restent blanches et
   inchangees (`.case-plateau{background:var(--papier)}`), tout comme
   le bandeau illustre de chaque terre, deja peint sur son propre fond
   opaque dans icones.js (`TERRES[cle]()` commence par un `<rect
   fill="...">`) : rien de tout ca ne peut se mettre a mal lire. */
.plateau{
  display:flex;flex-direction:column;gap:10px;
  padding:10px 0;border-radius:var(--r-xl);
  background:linear-gradient(180deg,
    var(--automne-clair) 0%, var(--automne-clair) 22%,
    var(--hiver-clair) 28%, var(--hiver-clair) 47%,
    var(--printemps-clair) 53%, var(--printemps-clair) 72%,
    var(--ete-clair) 78%, var(--ete-clair) 100%);
}
.saison-bloc .entete-saison{
  display:flex;align-items:baseline;gap:8px;margin:14px 2px 8px;
}
.saison-bloc .entete-saison h3{font-size:1.05rem;color:var(--t-encre)}

/* ---------- le bandeau d'une terre ---------- */
/* preserveAspectRatio="none" est acceptable ici : ce sont des masses
   sans detail fin, et le bandeau doit traverser toute la largeur. */
.bandeau-terre{
  display:block;width:100%;height:44px;
  border-radius:var(--r-m);
  /* Les sceaux de validation depassent de 9 px au-dessus des cases :
     sans cette marge, ils venaient se poser dans le paysage. */
  margin:2px 0 14px;
  box-shadow:var(--rebord), var(--arete);
}
.saison-bloc .entete-saison small{font-size:.76rem;color:var(--gris);font-weight:800}
.grille-cases{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.case-plateau{
  position:relative;text-align:left;
  background:var(--papier);border:2.5px solid var(--t);border-radius:var(--r-m);
  padding:10px 10px 12px;min-height:104px;
  display:flex;flex-direction:column;gap:4px;
  transition:transform .18s var(--ressort), box-shadow .2s;
}
.case-plateau:active{transform:scale(.96)}
.case-plateau .n{font-family:'Fredoka';font-size:1.15rem;font-weight:700;color:var(--t-encre);line-height:1}
.case-plateau .nom{font-family:'Fredoka';font-size:.82rem;line-height:1.2;flex:1}
.case-plateau .dom{font-size:.68rem;color:var(--gris);font-weight:700}
/* la marque dessinée de la case : coffre, ou éclair.
   Le coffre est franchement plus gros que l'éclair : une case coffre
   est le bout d'une terre, elle doit se repérer d'un coup d'œil dans
   les trente-six. */
.case-plateau .marque-case{display:inline-flex;align-items:center;vertical-align:-.22em}
.case-plateau .marque-case .ico-svg{vertical-align:0}
/* ---------- le coffre d'une case coffre ----------
   Posé sur le coin haut-droit, à cheval sur le bord, et SORTI DU FLUX :
   inline dans la ligne du numéro, il s'asseyait sur le titre dès qu'on
   le grossissait — « La Dictée Préparée » passait sous un couvercle.
   Là, il ne recouvre plus rien et il est enfin à la taille de ce qu'il
   annonce : le bout d'une terre.

   Il remplace aussi le sceau, qui occupait le même coin : ouvert, il
   dit déjà que la case est gagnée. Un grand défi ne peut pas recevoir
   de jeton (voir regles.peutPoserJeton), donc le sceau n'y disait
   jamais rien d'autre. */
.case-plateau .marque-coffre{
  position:absolute;right:-10px;top:-12px;
  pointer-events:none;
  filter:drop-shadow(0 3px 4px rgba(74,48,24,.4));
}
.case-plateau.grande .sceau{display:none}
/* le titre commence sous le coffre, jamais dessous au sens propre */
.case-plateau.grande .n{line-height:1;height:26px}

/* ---------- un défi spécial se reconnaît au premier coup d'œil ----------
   Le trait pointillé était le seul signal, et il passait inaperçu au
   milieu de neuf cases. « Défi spécial » prend donc l'or du carnet —
   la seule teinte qui n'appartient à aucune des quatre terres, donc la
   seule qui dise « celui-ci sort du lot » dans les quatre blocs. */
.case-plateau.speciale{border-style:dashed}
.case-plateau.speciale .dom{
  color:var(--ete-encre);font-weight:800;letter-spacing:.01em;
}
/* sur la case violette d'un grand défi, l'encre reste blanche */
.case-plateau.grande.speciale .dom{color:#fff}
.case-plateau.grande{background:var(--coffre);border-color:var(--coffre);color:#fff}
.case-plateau.grande .n,.case-plateau.grande .dom{color:#fff}
.case-plateau.faite{
  background:color-mix(in srgb, var(--t) 12%, var(--papier));
}
/* Un grand defi valide cumulait .grande (texte blanc) et .faite (fond
   pale) : .faite gagnait le fond, .grande gardait l'encre blanche, et
   le titre du coffre devenait illisible - blanc sur creme, 1,2 de
   contraste. La case reste violette, et s'assombrit en etant gagnee. */
.case-plateau.grande.faite{
  background:var(--coffre-fonce);border-color:var(--coffre-fonce);
}
/* une semaine a venir reste voilee, mais lisible */
.case-plateau.verrou .nom{opacity:.7}
.case-plateau .sceau{
  position:absolute;top:-9px;right:-9px;width:26px;height:26px;border-radius:50%;
  background:var(--printemps);color:#fff;display:flex;align-items:center;justify-content:center;
  font-size:.8rem;box-shadow:var(--ombre-s);
}
.case-plateau .sceau.jeton{background:var(--coffre)}
.case-plateau.courante{
  box-shadow:0 0 0 4px color-mix(in srgb, var(--t) 28%, transparent), var(--ombre-m);
}
/* ---------- le compagnon, posé sur la case du jour ----------
   Au coin haut-droit, à cheval sur le bord : exactement là où une
   case gagnée porte son sceau. Le même coin dit donc toujours où en
   est cette case. En bas, il mangeait la ligne du domaine, qui passait
   alors sur deux lignes dans toutes les cases du carnet.
   Il ne prend aucun clic - c'est la case qui s'ouvre. */
.case-plateau .pion-case{
  position:absolute;right:-22px;top:-14px;
  width:64px;height:64px;pointer-events:none;
  filter:drop-shadow(0 4px 5px rgba(22,35,63,.26));
  transform-origin:center bottom;
  animation:pion-danse 8.5s ease-in-out infinite;
}
.case-plateau .pion-case .figurine{display:block;width:100%;height:100%}
/* Le compagnon est le plus gros objet du plateau : sur SA case, le
   titre commence donc plus bas, pour passer sous ses pattes. Une case
   sur trente-six, et c'est justement celle qu'on regarde.
   Le décalage vers le haut est borné à 14 px : au-delà, le compagnon
   monte dans le bandeau de la terre, qui le coupe net. */
.case-plateau.courante .nom{margin-top:18px}

/* ============================================================
   Ecran coffres et trésor final
   ------------------------------------------------------------
   La carte d'un coffre est une LIGNE, pas une colonne : le coffre à
   gauche, le texte à droite. Empilée, elle faisait 400 px à elle
   seule, et il y en a quatre — l'écran demandait 2 500 px de
   défilement pour montrer quatre moments et un trésor.
   ============================================================ */
.sous-coffres{color:var(--gris);margin:6px 0 20px;font-size:.95rem;line-height:1.5}

.coffre-carte{
  position:relative;overflow:hidden;margin-bottom:12px;
  background:var(--papier);border-radius:var(--r-l);padding:14px 16px;
  box-shadow:var(--rebord), var(--arete), var(--ombre-s);
  display:flex;align-items:flex-start;gap:14px;text-align:left;
}
.coffre-carte.ouvert{
  background:linear-gradient(120deg,color-mix(in srgb,var(--t) 10%,#fff),var(--papier));
  box-shadow:var(--ombre-m);
}

.coffre-visuel{
  position:relative;flex:none;width:92px;align-self:center;
  transition:transform .2s var(--ressort);
}
.coffre-visuel:active{transform:scale(.92)}
.coffre-illu{width:100%;height:auto;display:block;overflow:visible}
/* Un coffre fermé n'est pas désaturé — un bois gris lit comme
   « non fini » alors que l'intention est « pas encore éclairé ». Il
   garde sa couleur, et prend un voile froid. */
.coffre-carte.ferme .coffre-illu{filter:saturate(.88) brightness(.96)}
.cadenas{
  position:absolute;right:2%;bottom:20%;
  filter:drop-shadow(0 2px 3px rgba(22,35,63,.25));
}

.coffre-texte{min-width:0;flex:1}
.coffre-carte .semaine{
  font-size:.7rem;font-weight:800;color:var(--gris);
  text-transform:none;letter-spacing:0;
}
.coffre-carte h3{font-size:1.1rem;margin:2px 0 6px;color:var(--t-encre)}
.coffre-carte p{font-size:.88rem;color:var(--encre-douce);line-height:1.45}
.coffre-carte .statut{
  display:inline-flex;align-items:center;gap:5px;margin-top:10px;
  padding:6px 12px;border-radius:999px;font-size:.76rem;font-weight:800;
  background:#EDF0F5;color:var(--gris);
}
.coffre-carte.ouvert .statut{background:var(--printemps-fonce);color:#fff}

/* ---- le souvenir d'un coffre vécu ---- */
/* La phrase du parent se lit comme une citation, pas comme un champ
   de formulaire : c'est un souvenir, pas une saisie. */
.coffre-souvenir{
  margin-top:10px;padding:10px 14px;
  background:color-mix(in srgb, var(--t) 8%, #fff);
  border-radius:var(--r-m);
  font-style:italic;
}
.coffre-carte .coffre-souvenir{color:var(--encre)}
.coffre-vecu-action{
  margin-top:10px;min-height:40px;padding:8px 16px;
  font-size:.88rem;width:auto;
}
/* Une fois le souvenir écrit, la retouche s'efface : on ne redemande
   jamais à un parent de revenir sur une soirée déjà vécue. */
.coffre-vecu-retouche{
  margin-top:6px;min-height:40px;font-size:.82rem;
  font-family:'Nunito';font-weight:600;
  text-decoration:underline;text-decoration-color:var(--trait);
  text-underline-offset:3px;
}

/* ============================================================
   Le trésor de fin d'année
   ------------------------------------------------------------
   L'aboutissement de neuf mois. Il n'avait aucune image : un titre,
   deux paragraphes, trois jauges et un rectangle mauve. Il a
   maintenant le plus gros coffre du carnet — fermé tant que le
   contrat n'est pas rempli, ouvert le jour où il l'est.
   ============================================================ */
.tresor-final{
  margin-top:22px;padding:20px 18px 18px;
  border:3px solid var(--coffre);border-radius:var(--r-xl);
  background:linear-gradient(180deg,var(--coffre-clair),var(--papier) 58%);
  text-align:center;
}
.tresor-coffre{width:168px;max-width:58%;margin:0 auto 2px}
.tresor-coffre .coffre-illu{width:100%;height:auto;display:block;overflow:visible}
/* Pas encore gagné : le coffre garde ses couleurs et prend le même
   voile froid que les quatre autres. Jamais de gris — un bois gris
   dit « raté », alors qu'il ne dit que « pas encore ». */
.tresor-final:not(.gagne) .coffre-illu{filter:saturate(.9) brightness(.97)}
.tresor-sur{
  font-size:.74rem;font-weight:800;color:var(--coffre);
  text-transform:none;letter-spacing:0;
}
.tresor-nom{
  font-family:'Fredoka';font-size:1.3rem;line-height:1.25;
  color:var(--coffre-encre);margin:4px 0 18px;
}
.tresor-conditions{list-style:none;text-align:left}
.condition{margin-bottom:14px}
.condition:last-child{margin-bottom:0}
.condition .ligne{
  display:flex;justify-content:space-between;align-items:baseline;
  gap:10px;margin-bottom:5px;
}
.condition .ligne b{font-size:.9rem;font-weight:800}
.condition .ligne span{
  font-family:'Fredoka';font-size:.88rem;color:var(--gris);white-space:nowrap;
}
.condition .jauge{height:10px;border-radius:999px;background:#E4E7EE;overflow:hidden}
.condition .jauge i{
  display:block;height:100%;border-radius:999px;
  background:var(--coffre);transition:width .9s var(--doux);
}
.condition small{
  display:block;margin-top:4px;font-size:.76rem;color:var(--gris);line-height:1.35;
}
.condition.atteinte .jauge i{background:var(--printemps)}
.condition.atteinte .ligne span{color:var(--printemps-encre)}
.tresor-note{
  margin-top:16px;font-size:.78rem;color:var(--gris);line-height:1.45;
}

/* ============================================================
   Ecran bonus : la pioche et la reserve
   ------------------------------------------------------------
   Ces regles avaient disparu lors d'un nettoyage de CSS juge mort :
   bonus.js posait toujours .pioche, .carte-piochee et .cat-bonus,
   mais plus rien ne les stylait. L'ecran se resumait alors a un
   petit bouton noir et a du texte nu colle dessous — c'est la
   forme sous laquelle le bug a ete signale.

   La zone de pioche est plus grande qu'a l'origine (padding 30 px,
   bouton pleine largeur de 58 px) : c'est la SEULE action de
   l'ecran, et tout le reste — les quatre volets — est de la
   consultation. Un bouton de la taille des autres boutons de l'app
   ne disait pas cela.

   La carte tiree REMPLACE l'accroche au lieu de s'ajouter dessous
   (.pioche--tiree) : un defi qui apparait sous un bouton se lit
   comme une note de bas de page, alors que c'est l'evenement de
   l'ecran. L'ordre est inverse en flex plutot que dans le DOM,
   pour que le bouton garde sa place dans l'ordre de tabulation.

   Pas de regle pour .cat-bonus h3 : les titres de famille sont
   maintenant des <summary>, habilles par .pliant.
   ============================================================ */
.pioche{
  background:linear-gradient(135deg,var(--coffre),#9D5BBE);
  color:#fff;border-radius:var(--r-l);padding:30px 22px;text-align:center;
  margin-bottom:22px;box-shadow:var(--ombre-m);
}
.pioche h3{font-size:1.35rem;margin-bottom:16px}
.pioche p{font-size:.95rem;opacity:.92;margin-bottom:22px;line-height:1.5}
.pioche .bouton{
  background:#fff;color:var(--coffre);
  width:100%;min-height:58px;font-size:1.1rem;font-weight:600;
}
.pioche .bouton:active{background:#F3E9F7}

.pioche--tiree{display:flex;flex-direction:column}
.pioche--tiree > h3, .pioche--tiree > p{display:none}
.pioche--tiree > #resultat{order:1}
.pioche--tiree > .bouton{order:2;margin-top:18px;min-height:52px;font-size:1rem}

/* ============================================================
   Le bloc du petit jeu, sous la pioche
   ------------------------------------------------------------
   Meme gabarit que .pioche, au mot pres : meme padding de 30 px,
   meme bouton pleine largeur de 58 px, meme rythme de titre et de
   texte. Il etait d'abord une carte basse et discrete, ce qui le
   faisait lire comme une note de bas de page sous le gros bloc
   violet — alors que ce sont deux propositions du meme rang :
   piocher un defi, ou jouer.

   Ce qui les distingue est la couleur, pas la taille : violet pour
   la reserve, vert Terre de Printemps pour le jeu.

   Consequence voulue : les deux blocs remplissent l'ecran, et la
   liste des 32 defis passe sous la ligne de flottaison. On y
   descend quand on la cherche.
   ============================================================ */
.jeu-bloc{
  background:linear-gradient(135deg,var(--printemps),#5FB073);
  color:#fff;border-radius:var(--r-l);padding:30px 22px;text-align:center;
  margin-bottom:22px;box-shadow:var(--ombre-m);
}
.jeu-bloc h3{font-size:1.35rem;margin-bottom:16px}
.jeu-bloc p{font-size:.95rem;opacity:.92;margin-bottom:22px;line-height:1.5}
.jeu-bloc .bouton{
  background:#fff;color:var(--printemps-encre);
  width:100%;min-height:58px;font-size:1.1rem;font-weight:600;
}
/* Les TROIS jeux, a parts egales, et l'icone AU-DESSUS du libelle.
   ------------------------------------------------------------
   A deux, ils tenaient cote a cote sur une ligne, icone a gauche du
   texte. A trois, c'est arithmetiquement impossible : le bloc offre
   320 px de large sur un iPhone ordinaire, donc 100 px par bouton,
   quand « Le serpent » avec son icone en demande 135.

   Les trois solutions possibles etaient : perdre une ligne en
   empilant deux boutons puis un (une mise en page qui se lit comme
   une erreur), rogner les libelles jusqu'a « Mots », ou passer
   l'icone au-dessus. La troisieme ne coute que 12 px de hauteur et
   garde les trois noms entiers.

   Le libelle a le droit de passer sur deux lignes ici - la grille
   donne la meme hauteur aux trois, donc rien ne se decale. */
.jeu-boutons{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}
.jeu-boutons .bouton{
  flex-direction:column;gap:4px;min-height:72px;padding:10px 4px;
  font-size:.82rem;line-height:1.15;white-space:normal;
}
.jeu-bloc .bouton:active{background:#E8F3EB}

/* Les trois jeux que les coffres ouvrent (3.0.0).
   ------------------------------------------------------------
   Ils restent VISIBLES, dans la grille, a leur place definitive : le
   carnet annonce ses quatre coffres des la premiere page, il n'a pas
   de raison de cacher ce qu'ils contiennent. Un jeu qui surgirait de
   nulle part ne se serait jamais fait attendre - et il decalerait
   toute la grille le jour ou il arrive.

   Ce qu'ils ne font PAS : dire ce qui manque. Pas de barre de
   progression, pas de « plus que 4 semaines », pas de gris triste.
   Un cadenas, le numero du coffre, et c'est tout. Le carnet ne tient
   aucun compte a rebours sur le travail d'un enfant.

   Le libelle reste en toutes lettres : un bouton verrouille dont on
   ne peut pas lire le nom n'annonce rien du tout. L'attenuation
   porte donc sur le FOND, pas sur le texte. */
.jeu-boutons .bouton.jeu-ferme{
  background:color-mix(in srgb, #fff 62%, transparent);
  color:color-mix(in srgb, var(--printemps-encre) 72%, #fff);
  box-shadow:none;
  cursor:default;
}
.jeu-boutons .bouton.jeu-ferme:active{
  background:color-mix(in srgb, #fff 62%, transparent);
  transform:none;
}
.jeu-boutons .bouton.jeu-ferme .ico-svg{opacity:.85}
.jeu-serrure{
  display:block;font-size:.62rem;font-weight:800;letter-spacing:0;
  text-transform:none;opacity:.82;
}

/* ============================================================
   Les deux jeux : la coque commune, puis chacun
   ------------------------------------------------------------
   `.jeu-*` est la coque partagee par le serpent et le memory : la
   boite, l'entete a trois chiffres, le carre du plateau, le voile et
   la ligne d'aide. Elle s'appelait `.snake-*` du temps ou il n'y
   avait qu'un jeu ; le memory l'a reprise telle quelle plutot que
   d'en faire une copie, sans quoi toute retouche serait a porter
   deux fois - le piege que planche.css et print.css tendent deja
   ailleurs dans ce projet.

   Ce qui reste propre a chacun garde son prefixe : `.snake-choix`
   pour le choix de difficulte, `.memo-*` pour la grille de cartes,
   et le canvas est en `#snake canvas`.

   Plein ecran, au-dessus de tout sauf des modales (90) : un jeu
   se joue sans que la coque de l'application depasse.

   Le plateau est un CARRE, et c'est lui qui commande : sa taille
   se mesure en JS puis se pose sur le canvas. La zone qui
   l'entoure porte donc `min-height:0` et `flex:1`, sans quoi un
   canvas de 100 % pousse son parent au lieu de s'y adapter, et le
   jeu deborde par le bas sur un iPhone court.

   touch-action:none sur TOUT l'ecran du jeu, et pas seulement sur le
   plateau : iOS prendrait sinon le glissement pour un defilement, et
   la commande se prend partout (voir snake.js) parce qu'un serpent
   qui longe le bord bas ne laisse plus la place de partir du doigt.
   ============================================================ */
#snake, #memory, #mots, #pendu, #saut, #course, #quiz{
  position:fixed;inset:0;z-index:86;
  display:flex;align-items:center;justify-content:center;
  padding:calc(var(--haut) + 12px) 14px calc(var(--bas) + 14px);
  background:color-mix(in srgb, var(--fond) 97%, transparent);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  animation:monte .3s var(--doux);
  touch-action:none;
  /* RIEN NE SE SELECTIONNE DANS UN JEU (4.2.0).
     ------------------------------------------------------------
     Signale par Xavier sur le saut : un doigt garde sur l'ecran -
     ce qui est la commande meme du jeu - declenchait la selection
     de texte d'iOS, le texte passait en surbrillance bleue et la
     loupe apparaissait par-dessus la partie. `touch-action:none`
     ne protege pas de ca : il regle le defilement et le zoom, pas
     la selection. Il fallait les trois lignes.
     Le champ de reponse du quiz, lui, garde le droit de se
     selectionner - on y tape du texte. */
  user-select:none;-webkit-user-select:none;
  -webkit-touch-callout:none;
  -webkit-tap-highlight-color:transparent;
}
#quiz input, #quiz textarea{
  user-select:text;-webkit-user-select:text;
}
.jeu-boite{
  display:flex;flex-direction:column;gap:12px;
  width:100%;max-width:460px;height:100%;max-height:640px;
}
.jeu-tete{display:flex;align-items:center;gap:12px;flex:none}
.jeu-chiffres{display:flex;gap:8px;flex:1;min-width:0}
.jeu-chiffres span{
  flex:1;text-align:center;font-size:.68rem;font-weight:800;color:var(--gris);
  text-transform:none;letter-spacing:0;
  background:var(--papier);border-radius:var(--r-m);padding:8px 4px;
  box-shadow:var(--rebord), var(--arete);
}
.jeu-chiffres b{
  display:block;font-family:'Fredoka';font-size:1.3rem;font-weight:600;
  letter-spacing:0;text-transform:none;color:var(--printemps-encre);
}
.jeu-fermer{
  flex:none;width:44px;height:44px;border-radius:50%;
  font-size:1.5rem;line-height:1;color:var(--gris);
  background:var(--papier);box-shadow:var(--rebord), var(--arete), var(--ombre-s);
}
.jeu-plateau{
  flex:1;min-height:0;position:relative;
  display:flex;align-items:center;justify-content:center;
  /* La zone devient un conteneur de requete pour que le memory puisse
     tailler son carre en `cqh` : sans cela, le seul moyen de rendre un
     carre borne EN HAUTEUR est de le mesurer en JS, ce que fait le
     serpent parce qu'il a un canvas dont il faut fixer les attributs.
     Le memory n'a qu'une grille, le CSS suffit. */
  container-type:size;
}
/* Le carré : la taille du plateau est posée en JS, et c'est lui qui
   cale le voile sur le canvas plutôt que sur la zone disponible. */
.jeu-carre{position:relative;flex:none}
#snake canvas{
  display:block;border-radius:var(--r-l);
  box-shadow:var(--arete), var(--ombre-m);
  /* le cadre prend la couleur de la terre traversee : le jeu
     appartient au carnet, il en suit les saisons */
  outline:3px solid var(--saison);outline-offset:0;
}
.jeu-voile{
  position:absolute;inset:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:10px;padding:22px;text-align:center;
  background:color-mix(in srgb, var(--papier) 88%, transparent);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  border-radius:var(--r-l);
}
.jeu-voile-titre{
  font-family:'Fredoka';font-size:1.5rem;font-weight:600;
  color:var(--printemps-encre);line-height:1.1;
}
.jeu-voile-texte{font-size:.92rem;color:var(--gris);max-width:16em;line-height:1.4}
.jeu-voile .bouton{min-width:160px;margin-top:4px}

/* Le choix de la difficulté, sur le voile.
   ------------------------------------------------------------
   C'est le segment des réglages, resserré : un choix de plus dans le
   carnet, pas un composant de jeu à part. Il est posé sur le plateau,
   donc il n'a pas la hauteur d'un segment de 52 px — 44 px reste le
   plancher du projet, et le sous-titre « ×2 points » passe en seconde
   ligne plutôt qu'en largeur, qui manque sur un écran de 375 px.

   `flex-wrap:nowrap` : les deux modes doivent rester CÔTE À CÔTE.
   Empilés, ils prennent 44 px de plus, et sur un carré d'iPhone SE le
   bouton « Jouer » sortait du voile. */
.snake-choix{width:100%;max-width:300px;gap:8px;flex-wrap:nowrap}
.snake-choix[hidden]{display:none}
.snake-choix label{
  min-width:0;min-height:44px;padding:4px 2px;
  flex-direction:column;gap:1px;font-size:.95rem;line-height:1.1;
}
/* hérite de la couleur du label : blanc sur la teinte de saison quand
   il est choisi, gris sinon */
.snake-choix small{font-size:.62rem;letter-spacing:.02em;opacity:.9}
.jeu-aide{
  flex:none;text-align:center;font-size:.78rem;color:var(--gris);line-height:1.35;
}

/* Sur un iPhone court, la ligne d'aide et les chiffres mangent la
   place du plateau : on resserre plutot que de laisser le carre
   retrecir. Meme seuil que le reste de l'application. */
@media (max-height:700px){
  .jeu-aide{display:none}
  .jeu-chiffres span{padding:5px 4px;font-size:.62rem}
  .jeu-chiffres b{font-size:1.1rem}
  .jeu-boite{gap:9px}
}

/* ============================================================
   Le memory
   ------------------------------------------------------------
   Six par six, trente-six cases, dix-huit paires. Le carre n'est
   pas mesure en JS comme celui du serpent, et il n'a pas a l'etre :
   il n'y a pas de canvas dont il faudrait fixer les attributs, donc
   `aspect-ratio` suffit - la hauteur commande, la largeur suit, et
   `max-width` reprend la main sur un ecran plus haut que large.

   La carte est un bouton, jamais un div : c'est la seule facon
   qu'elle soit atteignable au clavier et annoncee comme cliquable.
   Sur un ecran de 375 px, une case fait environ 53 px de cote, donc
   au-dessus du plancher de 44 px du projet.
   ============================================================ */
/* Le cote du carre : la plus petite des deux dimensions de la zone.
   `aspect-ratio` seul ne suffisait pas - avec une hauteur a 100 %, la
   largeur etait bien bornee par `max-width` mais la HAUTEUR restait
   celle du parent, et le plateau sortait en 362 x 519. */
.memo-carre{width:min(100cqw, 100cqh);height:min(100cqw, 100cqh)}
.memo-grille{
  display:grid;grid-template-columns:repeat(6,1fr);grid-template-rows:repeat(6,1fr);
  gap:5px;width:100%;height:100%;
}
.memo-carte{
  position:relative;padding:0;border:0;background:none;
  /* la profondeur du retournement : sans perspective, la carte
     tourne a plat et on ne voit qu'un ecrasement */
  perspective:620px;-webkit-tap-highlight-color:transparent;
}
.memo-face{
  position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  border-radius:var(--r-m);
  backface-visibility:hidden;-webkit-backface-visibility:hidden;
  transition:transform .34s var(--doux);
}
/* Le dos prend la terre traversee, comme le cadre du serpent : le
   jeu appartient au carnet, il en suit les saisons. Le semis de
   points lui donne sa matiere - un aplat seul fait carton. */
.memo-dos{
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,.3) 21%, transparent 22%)
      0 0/9px 9px,
    linear-gradient(140deg, var(--saison-clair), var(--saison));
  box-shadow:var(--arete), var(--ombre-s);
  transform:rotateY(0deg);
}
.memo-avant{
  background:var(--papier);
  box-shadow:var(--arete), var(--ombre-s);
  transform:rotateY(-180deg);
}
.memo-avant svg{width:70%;height:70%}
.memo-carte.ouverte .memo-dos{transform:rotateY(180deg)}
.memo-carte.ouverte .memo-avant{transform:rotateY(0deg)}
/* Une paire trouvee : un lisere dore et un fond creme. On ajoute de
   la lumiere sur ce qui est gagne, on ne grise jamais le reste. */
/* L'or du carnet, la seule teinte qui n'appartient a aucune des quatre
   terres : une paire trouvee ne change donc pas de saison, elle sort
   du lot. */
.memo-carte.trouvee .memo-avant{
  background:var(--ete-clair);
  box-shadow:inset 0 0 0 2px var(--ete), var(--ombre-s);
}
.memo-carte.trouvee .memo-avant svg{animation:memo-paire .5s var(--ressort)}

@media (max-height:700px){
  .memo-grille{gap:4px}
}

/* ============================================================
   Les mots caches
   ------------------------------------------------------------
   Une grille de lettres, des barres arrondies posees dessus, et la
   liste des mots en bas. Trois choses valent d'etre sues avant d'y
   toucher :

   1. LE CARRE N'EST PAS UN CARRE. Dix colonnes sur douze lignes, donc
      un rapport de 0,8333 - pose par le JS dans `--rapport`, parce
      que les deux nombres qui le font vivent la-bas. `aspect-ratio`
      donne la hauteur, et le `min()` borne la largeur par la HAUTEUR
      disponible : sans ce second terme, la grille sortait du plateau
      par le bas sur un ecran plus haut que large (le meme piege que
      le memory avait avant son `min(100cqw, 100cqh)`).

   2. TROIS COUCHES EMPILEES, et leur ordre est le jeu lui-meme : la
      trame et le papier sur le carre, les barres dans un SVG, les
      lettres par-dessus. Si la grille portait la trame, son fond
      recouvrirait les barres - c'est la seule raison pour laquelle la
      trame est sur le parent.

   3. LES BARRES SONT EN UNITES DE CASE. Le SVG a pour viewBox
      « 0 0 10 12 », donc un trait de 0,78 d'epaisseur fait 78 % d'une
      case a n'importe quelle taille d'ecran, et rien n'est a
      recalculer au redimensionnement. C'est ce qui evite au jeu la
      mesure en JS que le serpent est oblige de faire pour son canvas.
   ============================================================ */
/* Le plafond de 640 px de `.jeu-boite` vient du serpent et du memory,
   dont le plateau est CARRE : au-dela, leur carre devenait un pave sur
   une tablette sans rien apporter. Ici la grille est plus haute que
   large, et ce plafond lui coutait cher - mesure sur un iPhone de
   812 px de haut, il laissait 146 px inutilises sous le jeu et ramenait
   la case de 34,7 a 32,7 px, soit 6 % de cible en moins pour le doigt.
   C'est la LARGEUR qui doit commander la taille de la grille, comme
   prevu ; le plafond releve la lui rend. La largeur, elle, reste bornee
   a 460 px par la coque commune. */
#mots .jeu-boite, #pendu .jeu-boite{max-height:800px}
/* Le quiz a besoin d'encore un peu plus : un enonce de trois lignes,
   quatre reponses de 48 px, et un pied qui ne se comprime pas. Il n'a
   pas de plateau CARRE, donc rien ne le tire vers le bas. */
#quiz .jeu-boite{max-height:840px}

/* ============================================================
   Le pendu (3.0.0)
   ------------------------------------------------------------
   Trois blocs empiles dans le plateau commun : la potence, le mot,
   le clavier. Le seul qui se comprime est la POTENCE - le mot doit
   rester lisible et les touches doivent garder 44 px, c'est ce qui
   decide de l'ordre de priorite ici comme sur l'ecran de jeu.

   Le clavier tient sur SEPT colonnes, et ce n'est pas un chiffre
   rond : 26 lettres en 6 colonnes font 5 rangees, soit 44 px de plus
   que la scene n'en a sur un iPhone SE ; en 8 colonnes, la touche
   tombe a 38 px de large et c'est le premier appui - celui qui
   demande de viser - qui se rate. Sept colonnes, quatre rangees,
   deux places vides a la fin.

   `touch-action:manipulation` plutot que le `none` des autres jeux :
   aucun geste de glissement ici, et `none` empecherait la scene de
   defiler le jour ou un ecran plus court que prevu la ferait
   deborder. Le double tap reste coupe, comme partout.
   ============================================================ */
#pendu{touch-action:manipulation}
.pendu-scene{
  display:flex;flex-direction:column;align-items:center;
  justify-content:space-between;gap:10px;
  width:100%;height:100%;min-height:0;
}
/* La potence est calee EN HAUT, pas centree : centree dans une zone
   souple, elle laissait une bande vide entre l'entete et elle, et le
   dessin semblait flotter. Le vide se met la ou il ne gene pas -
   entre le theme et le mot. */
.pendu-haut{
  flex:none;display:flex;flex-direction:column;
  align-items:center;justify-content:flex-start;gap:6px;width:100%;
  min-height:0;
}
.pendu-potence{display:flex;align-items:center;min-height:0}
/* La potence est PLAFONNEE, et c'est une mesure, pas une precaution.
   Laissee libre sur `flex:1`, elle prenait 400 des 812 px d'un
   iPhone : le mot - la seule chose qu'on soit venu lire - faisait
   alors le douzieme de la hauteur du dessin qui compte les erreurs.
   Le plafond est en `cqh`, donc relatif a la zone de jeu, parce que
   `.jeu-plateau` est deja un conteneur de requete pour les mots
   caches. */
.pendu-dessin{
  height:min(46cqh, 300px);width:auto;max-width:100%;max-height:min(46cqh, 300px);
  display:block;
}
/* Les six morceaux arrivent a l'encre, jamais d'un coup : un trait
   qui surgit sans transition se lit comme un defaut d'affichage. */
.pendu-part{opacity:0;transition:opacity .3s ease}
.pendu-part.vu{opacity:1;animation:pendu-encre .34s var(--doux)}
.pendu-theme{
  flex:none;font-size:.74rem;font-weight:800;letter-spacing:0;
  text-transform:none;color:var(--gris);text-align:center;
}
.pendu-mot{
  flex:none;display:flex;flex-wrap:wrap;justify-content:center;
  gap:5px 6px;width:100%;
}
/* Une case vide est un TRAIT, pas un rectangle : c'est la forme que
   prend le pendu sur un cahier, et elle ne promet pas une lettre
   qu'on n'aurait plus qu'a poser dedans. */
.pendu-case{
  display:inline-flex;align-items:flex-end;justify-content:center;
  min-width:26px;height:38px;padding-bottom:2px;
  font-family:'Fredoka';font-size:1.7rem;font-weight:600;font-style:normal;
  color:var(--encre);border-bottom:3px solid var(--trait);
}
.pendu-case.pleine{border-bottom-color:var(--saison);animation:pop .3s var(--ressort)}
.pendu-liaison{
  display:inline-flex;align-items:flex-end;height:38px;padding-bottom:2px;
  font-family:'Fredoka';font-size:1.7rem;font-weight:600;font-style:normal;
  color:var(--gris);
}
/* Un mot long tient sur UNE ligne, quitte a retrecir ses cases : le
   mot coupe en deux se relit comme deux mots, et c'est precisement
   ce qu'on demande a l'enfant de deviner. Mesure sur 375 px de large :
   treize signes a 26 px debordent de 43 px, a 19 px ils passent. */
.pendu-mot--long .pendu-case{min-width:19px;height:32px;font-size:1.25rem}
.pendu-mot--long .pendu-liaison{height:32px;font-size:1.25rem}
.pendu-clavier{
  flex:none;display:grid;grid-template-columns:repeat(7,1fr);
  gap:5px;width:100%;
}
.pendu-touche{
  min-height:44px;border-radius:var(--r-m);
  font-family:'Fredoka';font-size:1.05rem;font-weight:600;
  color:var(--encre);background:var(--papier);
  box-shadow:var(--rebord), var(--arete), var(--ombre-s);
  transition:transform .12s, background .2s, color .2s, box-shadow .2s;
}
.pendu-touche:active:not(:disabled){transform:scale(.94)}
/* Une lettre juste prend la couleur de la terre traversee ; une
   lettre ratee s'efface, elle ne rougit pas. Le carnet ne marque
   jamais une erreur en rouge, pas meme dans ses jeux. */
.pendu-touche.juste{
  background:var(--saison);color:#fff;box-shadow:var(--ombre-s);
}
.pendu-touche.usee{
  background:transparent;color:var(--gris);opacity:.42;box-shadow:none;
}
.pendu-touche:disabled{cursor:default}
#pendu .jeu-voile-texte b{
  display:block;font-family:'Fredoka';font-size:1.25rem;font-weight:600;
  color:var(--encre);letter-spacing:.04em;margin-top:2px;
}

/* ============================================================
   Le saut (3.0.0)
   ------------------------------------------------------------
   L'ecran fait 160 x 144 unites mises a l'echelle par un facteur
   ENTIER, calcule en JS : c'est la seule facon d'obtenir des pixels
   carres et nets. Le CSS ne fait donc que poser le cadre et couper
   tout lissage - la taille, elle, vient de saut.js.

   `image-rendering:pixelated` est indispensable : sans lui, le
   navigateur interpole la toile a l'affichage et le jeu a l'air
   flou plutot que pixelise, ce qui est exactement l'inverse de
   l'effet recherche.
   ============================================================ */
.saut-ecran{
  position:relative;flex:none;
  border-radius:6px;overflow:hidden;
  box-shadow:var(--arete), var(--ombre-m);
  outline:3px solid var(--saison);outline-offset:0;
}
#saut canvas{display:block;image-rendering:pixelated}
/* Le saut reprend les lateraux de la coque (4.4.0). Son plateau est
   borne par la LARGEUR - 160 x 144 est plus large que haut, et la
   zone disponible est plus haute que large - donc chaque pixel rendu
   sur les cotes agrandit toute l'image. Mesure sur 390 x 844 : le jeu
   passe de 320 x 288 a 378 x 340, soit un cinquieme de plus en
   largeur et 40 % de surface. Les 6 px qui restent evitent que le
   cadre ne touche le bord de l'ecran. */
#saut{padding-left:6px;padding-right:6px}
#saut .jeu-voile{border-radius:6px}

/* ============================================================
   La course (3.0.0)
   ------------------------------------------------------------
   A l'inverse du saut, la scene prend TOUTE la zone de jeu : la
   perspective se creuse d'autant mieux que l'image est haute, et il
   n'y a ici aucune raison d'un cadre plus petit que l'ecran.
   La taille est posee en JS - la toile a des attributs a fixer.
   ============================================================ */
.course-ecran{
  position:relative;flex:none;
  border-radius:var(--r-l);overflow:hidden;
  box-shadow:var(--arete), var(--ombre-m);
  outline:3px solid var(--saison);outline-offset:0;
}
#course canvas{display:block}

@media (max-height:700px){
  .pendu-case, .pendu-liaison{height:30px;font-size:1.3rem}
  .pendu-case{min-width:22px}
  .pendu-mot--long .pendu-case{min-width:18px;height:27px;font-size:1.05rem}
  .pendu-mot--long .pendu-liaison{height:27px;font-size:1.05rem}
  /* La touche GARDE ses 44 px, meme sur un iPhone SE : c'est le
     plancher du projet, et la place existe - mesure a 375 x 667, la
     scene garde 69 px de marge une fois la potence plafonnee. C'est
     donc la potence qui cede, jamais la cible du doigt. */
  .pendu-touche{font-size:.95rem}
  .pendu-scene{gap:7px}
}
.mots-carre{
  width:min(100cqw, 100cqh * var(--rapport));
  aspect-ratio:var(--rapport);
  background:var(--papier);
  border-radius:var(--r-l);
  box-shadow:var(--arete), var(--ombre-m);
  /* le cadre prend la terre traversee, comme le serpent et le dos des
     cartes du memory : les jeux appartiennent au carnet */
  outline:3px solid var(--saison);
  overflow:hidden;
  /* conteneur de requete pour que la taille des lettres suive la
     grille et non la zone disponible autour d'elle */
  container-type:size;
  /* la trame : elle donne l'echelle de la case sans attirer l'oeil,
     comme le quadrillage du serpent. Le pas vient du JS. */
  background-image:
    repeating-linear-gradient(90deg, #EFEAE0 0 1px, transparent 1px var(--pas-c)),
    repeating-linear-gradient(180deg, #EFEAE0 0 1px, transparent 1px var(--pas-l));
  touch-action:none;
}
.mots-traits{position:absolute;inset:0;width:100%;height:100%;z-index:0}
.mots-trait{fill:none;stroke-width:.78;stroke-linecap:round}
/* Le trace en cours suit la saison ; un mot trouve prend l'or du
   carnet, la seule teinte qui n'appartienne a aucune des quatre
   terres. Meme partage que les paires du memory. */
.mots-trait--actif{
  stroke:var(--saison);opacity:0;transition:opacity .12s linear;
}
.mots-trait--actif.visible{opacity:.30}
.mots-trait--trouve{
  stroke:var(--ete);opacity:.36;
  transition:stroke-dashoffset .42s var(--doux);
}
.mots-grille{
  position:absolute;inset:0;z-index:1;
  display:grid;
  grid-template-columns:repeat(var(--cols), 1fr);
  grid-template-rows:repeat(var(--lignes), 1fr);
}
.mots-case{
  display:flex;align-items:center;justify-content:center;
  font-family:'Fredoka';font-weight:500;line-height:1;
  /* 4,9 % du cote de la grille : 17,9 px sur un iPhone ordinaire,
     17 px sur un SE. Le plafond en rem evite une lettre demesuree sur
     une tablette, ou la grille atteint 460 px. */
  font-size:min(4.9cqw, 1.35rem);
  color:var(--encre);
  /* sans quoi le glissement selectionne le texte au lieu de tracer */
  user-select:none;-webkit-user-select:none;
  -webkit-tap-highlight-color:transparent;
}
.mots-case.trouvee{color:var(--ete-encre);font-weight:600}
/* Le voile passe devant les trois couches : les lettres portent un
   z-index, donc l'ordre du DOM ne suffit plus a le mettre dessus. */
#mots .jeu-voile{z-index:3}

/* La liste des mots, sous la grille.
   ------------------------------------------------------------
   Elle est en `flex:none` : c'est la GRILLE qui cede de la place
   quand la liste prend une ligne de plus, jamais l'inverse. Un mot
   de la liste qui passerait sous le bord de l'ecran serait un mot
   qu'on ne sait pas qu'on cherche.

   La rature est un ::after qui s'etire de gauche a droite : un
   `text-decoration:line-through` apparait d'un bloc, et c'est
   justement le geste de rayer qu'on veut voir. */
.mots-bas{flex:none;display:flex;flex-direction:column;gap:5px}
.mots-theme{
  text-align:center;font-size:.66rem;font-weight:800;color:var(--gris);
  text-transform:none;letter-spacing:0;
}
.mots-liste{
  display:flex;flex-wrap:wrap;justify-content:center;gap:5px;list-style:none;
}
.mots-mot{
  position:relative;padding:5px 10px;border-radius:999px;
  background:var(--papier);box-shadow:var(--rebord), var(--arete);
  font-size:.75rem;font-weight:700;letter-spacing:.03em;color:var(--encre);
  transition:background .3s var(--doux), color .3s var(--doux);
}
.mots-mot::after{
  content:"";position:absolute;left:6px;right:6px;top:calc(50% - 1px);
  height:2px;border-radius:2px;background:var(--ete-encre);
  transform:scaleX(0);transform-origin:left center;
  transition:transform .42s var(--doux);
}
.mots-mot.trouve{
  background:var(--ete-clair);color:var(--ete-encre);box-shadow:var(--arete);
  animation:mots-trouve .45s var(--ressort);
}
.mots-mot.trouve::after{transform:scaleX(1)}

@media (max-height:700px){
  .mots-bas{gap:3px}
  .mots-theme{font-size:.62rem}
  .mots-mot{font-size:.7rem;padding:4px 8px}
}

.carte-piochee{
  background:#fff;color:var(--encre);border-radius:var(--r-m);
  padding:20px;text-align:left;box-shadow:var(--ombre-s);
}
.carte-piochee small{
  font-size:.75rem;font-weight:800;color:var(--coffre);
  text-transform:none;letter-spacing:0;
}
.carte-piochee b{
  display:block;font-family:'Fredoka';font-size:1.25rem;font-weight:600;
  line-height:1.2;margin:6px 0 4px;
}
.carte-piochee p{
  color:var(--encre-douce);font-size:.98rem;line-height:1.5;margin:6px 0 0;opacity:1;
}

.cat-bonus ul{margin:0;padding:0}
.cat-bonus li{list-style:none;padding:12px 2px;border-bottom:1px dotted var(--trait)}
.cat-bonus li:last-child{border-bottom:none;padding-bottom:0}
.cat-bonus li b{font-family:'Fredoka';font-size:.98rem;font-weight:500;display:block}
.cat-bonus li span{font-size:.87rem;color:var(--gris);line-height:1.45;display:block;margin-top:2px}

/* ============================================================
   Reglages
   ============================================================ */
.groupe{margin-bottom:26px}
.danger{color:var(--automne-encre);font-weight:800}

/* ============================================================
   Modale
   ============================================================ */
#modale{
  position:fixed;inset:0;z-index:60;display:flex;align-items:flex-end;justify-content:center;
  background:var(--voile);padding:16px;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
}
#modale .boite{
  width:100%;max-width:480px;background:var(--papier);
  border-radius:var(--r-xl);padding:26px 22px calc(22px + var(--bas));
  box-shadow:var(--ombre-l);
  max-height:88dvh;overflow-y:auto;
}
#modale h3{font-size:1.35rem;margin-bottom:8px}
#modale p{color:var(--encre-douce);font-size:.98rem;line-height:1.5}
/* LES BOUTONS COLLENT AU BAS DE LA BOITE (4.0.0).
   ------------------------------------------------------------
   .boite defile des que son contenu depasse 88dvh, et les actions
   sont dedans : sur une modale longue, le bouton principal passait
   sous le bord et il fallait defiler pour pouvoir fermer. C'etait
   deja vrai de l'historique des versions ; la fenetre des nouveautes,
   qui s'impose au lancement au lieu d'etre demandee, l'a rendu
   genant.

   `position:sticky` dans un conteneur qui defile deja : rien a
   deplacer, les boutons restent au meme endroit tant que tout tient,
   et se posent sur le bord des que ca deborde. Le fond est opaque et
   la marge negative annule le padding lateral de la boite, sans quoi
   le texte se verrait glisser dans les deux gouttieres. Le degrade
   du haut dit qu'il reste quelque chose a lire au-dessus. */
#modale .actions{
  display:flex;flex-direction:column;gap:10px;margin-top:22px;
  position:sticky;bottom:calc(-22px - var(--bas));
  margin-left:-22px;margin-right:-22px;
  padding:14px 22px calc(22px + var(--bas));
  background:var(--papier);
}
#modale .actions::before{
  content:"";position:absolute;left:0;right:0;top:-18px;height:18px;
  background:linear-gradient(to top,var(--papier),transparent);
  pointer-events:none;
}
#modale .emoji{font-size:2.6rem;display:block;margin-bottom:10px}

@media (min-width:620px){
  #modale{align-items:center}
  .grille-cases{grid-template-columns:repeat(5,1fr)}
  .soirs{max-width:420px}
}

/* canvas confettis */
/* au-dessus de #fete (80) et #celebration (85), sinon les confettis
   des moments forts sont peints derriere un voile opaque */
/* ------------------------------------------------------------
   width et height explicites, et ce n'est pas decoratif
   ------------------------------------------------------------
   Un <canvas> est un element remplace : en position absolue avec
   inset:0 mais sans dimension CSS, il ne s'etire pas - il prend sa
   taille INTRINSEQUE, c'est-a-dire ses attributs width/height, que
   anim.js fixe a innerWidth x devicePixelRatio.

   Sur un iPhone (densite 2 ou 3), la toile faisait donc deux ou trois
   fois l'ecran, ancree en haut a gauche : tout ce qui retombait etait
   dessine a deux ou trois fois ses coordonnees, donc hors champ. Les
   confettis ne se voyaient que le long du bord droit, et la poussiere
   du grattage - emise a la position du doigt - tombait toujours en
   dehors de l'ecran. D'ou « il n'y a pas de poussiere d'or ».
   ------------------------------------------------------------ */
#confettis{
  position:fixed;inset:0;width:100%;height:100%;
  z-index:95;pointer-events:none;
}

/* pas a pas de la semaine mise en avant, dans les reglages */
.pas-semaine{
  width:44px;height:44px;border-radius:50%;flex:none;
  background:var(--fond);box-shadow:inset 0 0 0 2px var(--trait);
  font-family:'Fredoka';font-size:1.3rem;color:var(--encre);
  display:flex;align-items:center;justify-content:center;
  transition:transform .18s var(--ressort);
}
.pas-semaine:active{transform:scale(.9)}

/* ============================================================
   Feuille A4 : l'apercu avant impression
   ============================================================ */
#feuille{
  position:fixed;inset:0;z-index:75;background:var(--fond);
  display:flex;flex-direction:column;
  overflow-y:auto;overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
}
.feuille-barre{
  position:sticky;top:0;z-index:2;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:calc(var(--haut) + 10px) 12px 10px;
  background:color-mix(in srgb, var(--fond) 92%, transparent);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid var(--trait);
}
.feuille-barre .bouton{min-height:44px;padding:8px 16px;font-size:.95rem}
.feuille-titre{font-family:'Fredoka';font-size:.9rem;color:var(--gris)}
.feuille-cadre{
  padding:12px 8px 40px;display:flex;justify-content:center;align-items:flex-start;
  overflow:hidden;
  /* sans min-width:0, la largeur min-content de la page A4 (1123px)
     forcerait le cadre a s'elargir et l'echelle resterait a 1 */
  width:100%;min-width:0;
}
.page-a4{
  width:297mm;min-height:210mm;flex:none;
  background:#fff;padding:10mm 11mm;
  box-shadow:0 6px 30px rgba(22,35,63,.22);
  transform-origin:top center;
  display:flex;flex-direction:column;
}
.page-a4 #plateau-impression{display:flex;flex:1}

/* ============================================================
   Ecran intro - la promesse du jeu, a lire avec l'enfant
   ============================================================ */
/* NB : classe prefixee. Un simple ".intro" entrait en collision avec le
   paragraphe .intro du contrat, qui heritait alors d'un min-height de
   100dvh et etirait tout le bloc vers le bas. */
.ecran-intro{
  min-height:100dvh;display:flex;flex-direction:column;text-align:center;
  padding:calc(var(--haut) + 8px) 10px calc(var(--bas) + 18px);
  max-width:480px;margin:0 auto;
}
.intro-haut{display:flex;justify-content:space-between;align-items:center;min-height:48px}
.intro-haut .bouton{min-height:44px;padding:8px 14px;font-size:.95rem}
.marque-mini{font-family:'Fredoka';font-weight:600;color:var(--gris);padding-left:12px}

.intro-scene{flex:1;display:flex;align-items:center;justify-content:center;min-height:210px;padding:14px 0}
.intro-texte{padding:0 14px}
.intro-texte h1{font-size:1.95rem;margin-bottom:12px}
.intro-texte p{color:var(--encre-douce);font-size:1.08rem;line-height:1.55;max-width:400px;margin:0 auto}
/* Le bouton d'installation d'Android : SECONDAIRE, et c'est voulu.
   Le bouton principal du panneau reste « C'est parti ! » — personne
   ne doit avoir l'impression qu'il faut installer pour continuer. */
.intro-installer{margin:16px auto 0;max-width:280px;width:100%}

.points{display:flex;gap:8px;justify-content:center;margin:26px 0 18px}
.points i{
  width:9px;height:9px;border-radius:50%;background:var(--trait);
  transition:width .32s var(--ressort), background .32s;
}
.points i.actif{width:28px;border-radius:6px;background:var(--saison-fonce)}

/* scene 1 : le plateau qui se remplit */
.sc-plateau{display:grid;grid-template-columns:repeat(4,52px);gap:11px}
.sc-plateau span{
  width:52px;height:52px;border-radius:14px;
  background:color-mix(in srgb, var(--t) 14%, #fff);
  border:2.5px solid var(--t);color:var(--t-encre);
  display:flex;align-items:center;justify-content:center;
  font-family:'Fredoka';font-size:1rem;
  animation:case-allume 3.6s ease-in-out infinite;
  animation-delay:calc(var(--i) * .16s);
}

/* ------------------------------------------------------------
   scène 2 : la semaine d'école, en toutes lettres
   ------------------------------------------------------------
   Elle montrait quatre initiales — L M J V — et le mercredi avait
   purement disparu du dessin. Un enfant qui compte ses jours d'école
   n'y retrouvait pas sa semaine, et « M » deux fois n'aide personne.

   Cinq tuiles sur UNE ligne, aux mêmes proportions et à la même
   petite graisse que le rituel du soir de l'écran de jeu
   (.soirs--cinq) : c'est le même objet, autant qu'il se reconnaisse.
   « mercredi » est le mot le plus long, c'est lui qui fixe la taille.
   ------------------------------------------------------------ */
.sc-soirs{display:flex;align-items:stretch;gap:7px;width:100%;max-width:330px}
.sc-soirs .sc-jour{
  flex:1;min-width:0;min-height:66px;padding:7px 2px;
  border-radius:var(--r-m);border:2.5px solid var(--trait);background:var(--papier);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  font-family:'Fredoka';color:var(--gris);
  animation:soir-anime 4.6s ease-in-out infinite;
  animation-delay:calc(var(--i) * .42s);
}
.sc-soirs b{
  font-size:.68rem;font-weight:600;line-height:1;letter-spacing:-.03em;
  max-width:100%;white-space:nowrap;overflow:hidden;
}
.sc-soirs i{
  font-style:normal;font-size:1rem;line-height:1;height:18px;
  display:flex;align-items:center;opacity:0;
  animation:coche-anime 4.6s ease-in-out infinite;
  animation-delay:calc(var(--i) * .42s);
}

/* ------------------------------------------------------------
   scène 1 : le coffre du carnet, qui s'ouvre en boucle
   ------------------------------------------------------------
   C'est le même dessin qu'à l'onglet Coffres et qu'à la fête d'un
   coffre gagné — il vit dans ui/icones.js. L'explication en avait un
   à elle, en CSS : deux rectangles et une étoile. Trois coffres pour
   un seul objet, c'était trois objets.

   L'ouverture, elle, est ici : une boucle, alors que celle du carnet
   est un événement qui se joue une fois. Voir .coffre-illu.boucle
   dans anim.css.
   ------------------------------------------------------------ */
.sc-tresor{width:190px;max-width:58vw}
.sc-tresor .coffre-illu{width:100%;height:auto;display:block;overflow:visible}

/* ------------------------------------------------------------
   scène 5 : le téléphone, et le geste qui pose le carnet dessus
   ------------------------------------------------------------
   Ce panneau n'existe que sur un téléphone, dans un navigateur, et
   jamais quand l'application tourne déjà en plein écran — la
   condition vit dans `besoinInstallation()`, dans ui/intro.js, et
   nulle part ailleurs.

   Le dessin est en HTML/CSS comme les trois autres scènes de
   l'intro, et pour une raison précise : « Sur l'écran d'accueil »
   doit rester du VRAI texte. Le même libellé en <text> SVG,
   remis à l'échelle du dessin, devenait flou à 10 px sur un SE —
   or c'est la ligne que l'utilisateur doit reconnaître dans son
   propre menu deux secondes plus tard.

   Les proportions sont celles d'un téléphone (186 × 268) et la
   largeur est plafonnée à 52vw : sur un SE la scène dispose de
   285 px de haut, mesuré, une fois l'entête, le texte, les points
   et le bouton retirés des 667.
   ------------------------------------------------------------ */
.sc-phone{width:186px;max-width:52vw}
.ph-corps{
  position:relative;width:100%;aspect-ratio:186/252;padding:6px;
  border-radius:26px;background:var(--papier);
  border:3px solid color-mix(in srgb, var(--encre) 13%, #fff);
  box-shadow:var(--arete), var(--ombre-l);
}
/* l'encoche, par-dessus l'écran */
.ph-corps::before{
  content:"";position:absolute;z-index:5;
  top:10px;left:50%;transform:translateX(-50%);
  width:42px;height:5px;border-radius:3px;
  background:color-mix(in srgb, var(--encre) 20%, transparent);
}
.ph-ecran{
  position:relative;width:100%;height:100%;overflow:hidden;
  border-radius:20px;background:var(--fond);
  display:flex;flex-direction:column;
}

/* le carnet en miniature : on doit reconnaître l'écran qu'on regarde */
.ph-mini{flex:1;min-height:0;display:flex;flex-direction:column;gap:9px;padding:14px 11px 10px}
.ph-mini--ios{padding-top:22px}
.ph-carte{
  display:block;padding:9px 8px;border-radius:11px;
  background:var(--papier);
  box-shadow:var(--ombre-s);
}
.ph-carte i{display:block;border-radius:4px}
.ph-pastille{width:44px;height:7px;background:color-mix(in srgb, var(--saison) 42%, #fff);margin-bottom:8px}
.ph-titre{width:74%;height:8px;background:color-mix(in srgb, var(--encre) 42%, #fff);margin-bottom:8px}
.ph-l1,.ph-l2{height:5px;background:color-mix(in srgb, var(--encre) 16%, #fff);margin-bottom:5px}
.ph-l1{width:100%}
.ph-l2{width:64%;margin-bottom:0}
.ph-soirs{display:flex;gap:5px}
.ph-soirs i{flex:1;height:21px;border-radius:6px;background:var(--papier);border:1.5px solid var(--trait)}
/* la frise de l'année, tout en bas : sans elle le téléphone avait un
   grand vide sous la carte, et un écran vide ne ressemble à rien */
.ph-annee{display:flex;align-items:center;gap:5px}
.ph-annee b{flex:1;height:7px;border-radius:4px;background:color-mix(in srgb, var(--encre) 10%, transparent)}
.ph-annee i{width:9px;height:9px;border-radius:3px;background:color-mix(in srgb, var(--saison) 55%, #fff)}

/* la barre du navigateur : en bas sur iOS, en haut sur Android */
.ph-barre{
  flex:none;height:34px;padding:0 9px;
  display:flex;align-items:center;justify-content:space-between;
  background:var(--papier);border-top:1px solid var(--trait);
}
.ph-ico{width:12px;height:12px;border-radius:3px;background:color-mix(in srgb, var(--encre) 14%, transparent)}
.ph-adresse{
  flex:none;height:28px;margin:6px 7px 0;padding:0 4px 0 9px;
  display:flex;align-items:center;gap:6px;
  background:var(--papier);border-radius:999px;box-shadow:var(--ombre-s);
}
.ph-url{flex:1;height:6px;border-radius:3px;background:color-mix(in srgb, var(--encre) 14%, transparent)}

/* la cible : le bouton sur lequel il faut appuyer */
.ph-cible{
  position:relative;flex:none;
  display:flex;align-items:center;justify-content:center;
  color:var(--saison-fonce);
}
.ph-halo{
  position:absolute;left:50%;top:50%;width:34px;height:34px;margin:-17px 0 0 -17px;
  border-radius:50%;border:2px solid var(--saison-fonce);opacity:0;
  animation:ph-halo 5s ease-in-out infinite;
}

/* le menu qui s'ouvre, et la ligne qu'il faut y trouver */
.ph-menu{
  position:absolute;left:6px;right:6px;bottom:6px;z-index:2;
  padding:8px 8px 10px;border-radius:15px;background:var(--papier);
  box-shadow:0 -6px 22px rgba(74,48,24,.18);
  display:flex;flex-direction:column;gap:6px;
  animation:ph-menu-bas 5s ease-in-out infinite;
}
/* 88 %, et c'est une mesure : a 76 %, « Installer l'application »
   sortait du telephone par la droite. C'est le libelle le plus long
   des deux, et c'est lui qui fixe la largeur du menu. */
.ph-menu--haut{
  top:38px;bottom:auto;left:auto;right:8px;width:88%;
  transform-origin:top right;
  box-shadow:0 8px 22px rgba(74,48,24,.20);
  animation-name:ph-menu-haut;
}
.ph-poignee{align-self:center;width:30px;height:4px;border-radius:2px;background:var(--trait);margin-bottom:1px}
.ph-ligne{height:23px;border-radius:8px;background:color-mix(in srgb, var(--encre) 6%, transparent)}
.ph-ligne--cible{
  display:flex;align-items:center;gap:6px;padding:0 8px;
  background:var(--saison-clair);color:var(--saison-encre);
  font-family:'Fredoka';font-weight:600;font-size:.56rem;
  letter-spacing:-.02em;white-space:nowrap;
  animation:ph-surligne 5s ease-in-out infinite;
}
.ph-ligne--cible svg{flex:none}

/* ---------- troisième temps : l'écran d'accueil, et ce qu'on obtient ----------
   La scène s'arrêtait sur « Sur l'écran d'accueil » surligné, donc sur
   le dernier GESTE : elle montrait quoi faire, jamais ce que ça donne.
   Ce bureau recouvre tout l'écran du téléphone à la fin du cycle, et
   l'icône du carnet s'y pose en dernier.

   L'icône est le VRAI fichier PNG, celui du manifeste et de l'écran
   d'accueil — pas un dessin refait ici. Un carnet qui montrerait une
   autre icône que celle qui va s'installer promettrait une autre
   application. Le fichier est dans la liste `COQUE` de `sw.js`, donc
   il est là hors ligne comme le reste. */
.ph-bureau{
  position:absolute;inset:0;z-index:3;
  display:grid;grid-template-columns:repeat(3,1fr);
  align-content:start;gap:13px 8px;padding:26px 12px 12px;
  background:
    radial-gradient(120% 80% at 80% 0%, #FFE3BE 0%, transparent 60%),
    linear-gradient(170deg, #FBF2E2 0%, #EFE6DA 52%, #E3E7EC 100%);
  animation:ph-bureau 5s ease-in-out infinite;
}
/* les applications qui étaient déjà là : des formes, pas des marques */
.ph-appli{
  justify-self:center;width:40px;height:40px;border-radius:11px;
  background:color-mix(in srgb, var(--encre) 11%, transparent);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5);
}
/* la nôtre : elle se pose en dernier, et elle porte son nom */
.ph-appli--nous{
  position:relative;background:none;box-shadow:none;
  animation:ph-pose 5s var(--ressort) infinite;
}
.ph-appli--nous img{
  display:block;width:40px;height:40px;border-radius:11px;
  box-shadow:0 3px 8px rgba(74,48,24,.28);
}
/* Le nom déborde volontairement de sa case, comme il déborderait d'une
   case de 40 px sur un vrai téléphone. `nowrap` plutôt qu'une troncature :
   « Un pas de… » ne se reconnaît pas, et c'est le nom qu'on cherchera
   du doigt le lendemain soir. */
.ph-appli--nous b{
  position:absolute;top:44px;left:50%;transform:translateX(-50%);
  font-family:'Fredoka';font-weight:500;font-size:.4rem;
  letter-spacing:-.01em;white-space:nowrap;color:var(--encre);
}
/* le dock, hors de la grille : il est ancré en bas, pas rangé avec
   les applications */
.ph-dock{
  position:absolute;left:11px;right:11px;bottom:9px;
  display:flex;justify-content:space-around;align-items:center;
  padding:6px 8px;border-radius:15px;
  background:rgba(255,255,255,.5);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.55);
  backdrop-filter:blur(4px);
}
.ph-dock i{
  width:26px;height:26px;border-radius:8px;
  background:color-mix(in srgb, var(--encre) 13%, transparent);
}

/* Le cran des écrans courts. Mesuré sur 375 × 667 : les quatre
   panneaux d'origine y débordent tous de 32 px — l'explication
   défile, contrairement à l'accueil, et c'est assumé depuis le
   début. Le cinquième en faisait 78 : le téléphone est le seul
   dessin de l'intro qui soit plus haut que large, et le texte y
   prend cinq lignes.
   C'est la HAUTEUR du dessin qui cède, pas sa largeur : rétrécir le
   téléphone aurait fait sortir « Sur l'écran d'accueil » de son
   menu, et c'est le mot que tout ce panneau existe pour montrer. */
@media (max-height:720px){
  .ph-corps{aspect-ratio:186/206}
  .ph-mini{padding:10px 10px 8px;gap:7px}
  .ph-mini--ios{padding-top:17px}
  .ph-soirs i{height:17px}
  .ph-bureau{gap:11px 8px;padding:20px 12px 10px}
  .ph-dock{padding:5px 8px}
  .ph-dock i{width:22px;height:22px}
}

/* ============================================================
   Célébration de fin de semaine : plateau, pion, ticket
   ============================================================ */
#celebration{
  position:fixed;inset:0;z-index:85;overflow-y:auto;
  background:color-mix(in srgb, var(--fond) 96%, transparent);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  display:flex;align-items:center;justify-content:center;
  padding:calc(var(--haut) + 16px) 14px calc(var(--bas) + 20px);
  animation:monte .32s var(--doux);
}
.cel-boite{width:100%;max-width:460px;text-align:center}
.cel-titre{font-family:'Fredoka';font-size:1.75rem;font-weight:600;line-height:1.1}
.cel-phrase{color:var(--gris);font-size:.95rem;margin:6px 0 18px}

/* ---- plateau miniature ---- */
.mini-plateau{
  position:relative;display:grid;grid-template-columns:repeat(9,1fr);gap:5px;
  background:var(--papier);border-radius:var(--r-l);padding:12px;
  box-shadow:var(--rebord), var(--arete), var(--ombre-m);
}
.mini-plateau .mc{
  aspect-ratio:1;border-radius:6px;
  border:2px solid color-mix(in srgb, var(--t) 45%, #fff);
  background:color-mix(in srgb, var(--t) 8%, #fff);
  transition:background .3s, transform .3s var(--ressort);
}
.mini-plateau .mc.faite{background:var(--t);border-color:var(--t)}
.mini-plateau .mc.cible{border-color:var(--t);border-width:2.5px}
.mini-plateau .mc.atteinte{animation:case-atteinte .7s var(--ressort)}

.mini-plateau .pion{
  /* boite de taille nulle : son contenu se centre sur le point vise,
     ce qui rend le calcul de position independant de la taille du dessin */
  position:absolute;top:0;left:0;width:0;height:0;
  display:flex;align-items:center;justify-content:center;
  pointer-events:none;z-index:2;
  filter:drop-shadow(0 3px 5px rgba(22,35,63,.35));
}
.mini-plateau .pion > svg{flex:none;margin-bottom:5px}
.mini-plateau .pion.saute > svg{animation:pion-saute .85s cubic-bezier(.34,1.4,.5,1)}

/* ---- ticket a gratter ---- */
.ticket-zone{margin-top:24px}

/* le ticket lui-meme : papier creme, liseres dores, encoches laterales */
.ticket{
  position:relative;width:100%;
  border-radius:18px;
  background:
    repeating-linear-gradient(135deg,
      rgba(224,190,116,.10) 0 6px, rgba(255,255,255,0) 6px 13px),
    linear-gradient(165deg,#FFFAF0,#FFF2D8 55%,#FFEBC6);
  box-shadow:0 10px 30px rgba(22,35,63,.18), 0 1px 0 rgba(255,255,255,.9) inset;
  border:2px solid #E9C97F;
  padding:10px;
  animation:pop .5s var(--ressort) both;
  overflow:hidden;
}
/* encoches, comme sur un vrai ticket detachable */
.ticket::before,.ticket::after{
  content:"";position:absolute;top:50%;width:22px;height:22px;
  border-radius:50%;background:var(--fond);
  box-shadow:0 0 0 2px #E9C97F inset;
  transform:translateY(-50%);
}
.ticket::before{left:-12px}
.ticket::after{right:-12px}

.ticket-haut,.ticket-bas{
  display:flex;align-items:center;justify-content:space-between;
  padding:2px 8px 8px;
  font-family:'Fredoka';font-size:.72rem;letter-spacing:0;
  text-transform:none;color:#B08636;
}
.ticket-bas{padding:8px 8px 2px;border-top:1.5px dashed #E4C78C;margin-top:8px}
.ticket-marque{font-weight:600;color:#8A6212}
.ticket-num{font-variant-numeric:tabular-nums}

/* la fenetre a gratter */
.ticket-fenetre{
  position:relative;min-height:132px;border-radius:12px;overflow:hidden;
  background:#FFFDF6;
  box-shadow:inset 0 0 0 1.5px #EBD6A6, inset 0 3px 10px rgba(140,100,20,.12);
}
.ticket-fond{
  position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:10px;padding:16px 18px;
}
.ticket-q{font-family:'Fredoka';font-size:1rem;line-height:1.3;color:var(--encre)}
.ticket-r{
  font-family:'Fredoka';font-size:1.2rem;font-weight:600;line-height:1.25;
  color:var(--coffre-fonce);
}
/* la chute du gag arrive un souffle apres la question */
.ticket-fenetre .ticket-grattage.efface ~ .ticket-fond .ticket-r,
.ticket-fond .ticket-r{animation:pop .42s .15s var(--ressort) both}
.ticket-grattage{
  position:absolute;inset:0;width:100%;height:100%;
  touch-action:none;cursor:crosshair;
  transition:opacity .5s var(--doux);
}
.ticket-grattage.efface{
  opacity:0;
  transform:scale(1.05) rotate(.7deg);
  transform-origin:50% 100%;
  transition:opacity .42s var(--doux), transform .42s var(--doux);
}
/* reflet qui balaie la couche doree, pour donner envie d'y toucher */
.ticket-brillance{
  position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,
    rgba(255,255,255,0) 38%, rgba(255,255,255,.55) 48%,
    rgba(255,255,255,0) 58%);
  background-size:280% 100%;
  animation:reflet 2.8s ease-in-out infinite;
}

.ticket-consigne{
  font-family:'Fredoka';color:var(--gris);font-size:1rem;margin:16px 0 16px;
  display:flex;align-items:center;justify-content:center;gap:8px;
}
.ticket-consigne .doigt{font-size:1.3rem;animation:tapote 1.5s ease-in-out infinite}
.ticket-consigne.trouvee{color:var(--printemps-encre);font-weight:600}


/* ============================================================
   Parcours initiatique de l'aventurier
   ============================================================ */
.parcours{
  min-height:100dvh;display:flex;flex-direction:column;text-align:center;
  padding:calc(var(--haut) + 8px) 12px calc(var(--bas) + 18px);
  max-width:480px;margin:0 auto;
}
.pas-haut{display:flex;justify-content:space-between;align-items:center;min-height:48px}
.pas-haut .bouton{min-height:44px;padding:8px 14px;font-size:.95rem}
.pas-compte{font-family:'Fredoka';font-size:.85rem;color:var(--gris);padding-right:10px}

.pas-corps{flex:1;display:flex;flex-direction:column;justify-content:center;gap:6px;padding:10px 4px}
.pas-corps h1{font-size:1.85rem;line-height:1.15}
.pas-aide{color:var(--gris);font-size:.95rem;line-height:1.45;max-width:380px;margin:0 auto}
.pas-corps .pastille{align-self:center;margin-bottom:10px}
.pas-champ{margin-top:22px}

.grande-saisie{
  width:100%;min-height:64px;padding:14px 18px;text-align:center;
  font-family:'Fredoka';font-size:1.35rem;
  background:var(--papier);border:2.5px solid var(--trait);border-radius:var(--r-l);
  transition:border-color .2s, box-shadow .2s;
}
textarea.grande-saisie{font-size:1.05rem;line-height:1.4;text-align:left;resize:vertical}
.grande-saisie:focus{
  outline:none;border-color:var(--saison);
  box-shadow:0 0 0 5px color-mix(in srgb, var(--saison) 16%, transparent);
}

.grille-choix{display:flex;flex-direction:column;gap:12px}
.choix-carte{
  display:flex;align-items:center;gap:14px;text-align:left;
  min-height:76px;padding:14px 18px;
  background:var(--papier);border:2.5px solid var(--trait);border-radius:var(--r-l);
  box-shadow:var(--ombre-s);
  transition:transform .18s var(--ressort), border-color .2s, background .2s;
}
.choix-carte .emo{font-size:1.8rem;flex:none}
.choix-carte b{font-family:'Fredoka';font-size:1.2rem;font-weight:600;display:block}
.choix-carte small{color:var(--gris);font-size:.85rem}
.choix-carte:active{transform:scale(.97)}
.choix-carte.pris{
  border-color:var(--saison);background:var(--saison-clair);
  transform:scale(1.02);
}

/* Les deux cartes de l'ecran de depart du parcours - creer, ou
   rejoindre avec un code.
   ------------------------------------------------------------
   `.choix-carte` met son titre et son sous-titre COTE A COTE, ce qui
   va pour « Une fille » / « partie seule » et pas du tout pour
   « J'ai un code d'invitation » / « Rejoindre le carnet ouvert par
   l'autre parent ». Les deux passent donc en colonne, et l'icone du
   carnet remplace l'emoji : ces deux cartes-la parlent au parent. */
.choix-texte{display:flex;flex-direction:column;gap:2px;min-width:0}
.grille-choix--depart .choix-carte{align-items:flex-start;padding:16px 16px}
.grille-choix--depart .emo{display:flex;align-items:center;margin-top:2px}
.grille-choix--depart b{line-height:1.2}
.grille-choix--depart small{line-height:1.35}

/* Les cinq niveaux, sur un ecran court (5.0.0)
   ------------------------------------------------------------
   Mesure sur 375 x 667, l'ecran le plus court du parc : cinq cartes
   de 76 px et quatre ecarts de 12 font 440 px, et l'ecran debordait
   de 52 px - « CM2 » restait sous le pli, sur la question ou l'on
   choisit precisement entre cinq classes. A 60 px de carte et 8
   d'ecart on tombe a 332, soit 108 px gagnes : plus de debordement,
   et la cible tactile reste a 60 px, bien au-dessus du plancher de
   44 du projet. La largeur, elle, ne bouge pas : c'est elle qui fait
   la cible d'un doigt sur une carte pleine largeur.

   Seule la grille des NIVEAUX porte ce cran. Les autres questions du
   parcours ont deux cartes, et les six figurines tiennent deja sur
   trois colonnes. */
@media (max-height:700px){
  .grille-choix--niveaux{gap:8px}
  .grille-choix--niveaux .choix-carte{min-height:60px;padding:10px 16px}
  .grille-choix--niveaux .choix-carte b{font-size:1.1rem}
}

.grille-figurines{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.choix-figurine{
  display:flex;flex-direction:column;align-items:center;gap:2px;
  padding:10px 4px 12px;
  background:var(--papier);border:2.5px solid var(--trait);border-radius:var(--r-l);
  box-shadow:var(--ombre-s);
  transition:transform .2s var(--ressort), border-color .2s, box-shadow .2s;
}
.choix-figurine span{font-family:'Fredoka';font-size:.82rem;color:var(--gris)}
.choix-figurine:active{transform:scale(.95)}
.choix-figurine.pris{
  border-color:var(--t);box-shadow:0 0 0 4px color-mix(in srgb, var(--t) 22%, transparent);
  transform:translateY(-3px) scale(1.04);
}
.choix-figurine.pris span{color:var(--encre);font-weight:700}
.choix-figurine .figurine{transition:transform .3s var(--ressort)}
.choix-figurine.pris .figurine{animation:pop .45s var(--ressort)}

.recap-figurine{display:flex;justify-content:center;margin-bottom:6px}
.recap-figurine .figurine{animation:tampon .7s var(--ressort) both}
.recap-liste{list-style:none;margin-top:20px;text-align:left}
.recap-liste li{
  display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  padding:12px 4px;border-bottom:1px dotted var(--trait);
}
.recap-liste span{color:var(--gris);font-size:.9rem;flex:none}
.recap-liste b{font-family:'Fredoka';font-weight:500;text-align:right}

/* la figurine, dans l'entete et dans la liste des enfants */
.avatar-figurine{
  flex:none;width:46px;height:46px;border-radius:50%;
  display:flex;align-items:flex-end;justify-content:center;overflow:hidden;
  background:var(--saison-clair);box-shadow:var(--ombre-s);
}

/* ---------- blocs de réglage ---------- */
.reglage-bloc{margin-bottom:12px;text-align:left}
.reglage-bloc > b{font-family:'Fredoka';font-size:1.05rem;font-weight:600;display:block}
.reglage-bloc .aide{font-size:.85rem;color:var(--gris);line-height:1.45;margin-top:4px}
.reglage-bloc .jetons{justify-content:flex-start;flex-wrap:wrap;margin-top:14px}
.compteur{display:flex;align-items:center;gap:14px;margin-top:14px}
.compteur-valeur{flex:1;text-align:center}
.compteur-valeur b{display:block;font-family:'Fredoka';font-size:1.6rem;line-height:1}
.compteur-valeur small{display:block;font-size:.76rem;color:var(--gris);font-weight:700;margin-top:2px}

.reglage-bloc .grille-figurines .choix-figurine{padding:8px 2px 10px}
.reglage-bloc .grille-figurines .choix-figurine span{font-size:.74rem}

/* ---------- édition des coffres dans les réglages ---------- */
.coffre-reglage .semaine{
  font-size:.74rem;font-weight:800;color:var(--gris);
  text-transform:none;letter-spacing:0;margin-bottom:12px;
}
.coffre-reglage .champ{margin-bottom:12px}
.coffre-reglage .champ input,.coffre-reglage .champ textarea{min-height:48px}
#modale .coffre-reglage{text-align:left}

/* Un coffre, ou le tresor, = une ligne qui s'ouvre en fenetre (7.3.0).
   Le nom en clair, la semaine au-dessus en petit, un chevron. */
.ligne-reglage{
  display:flex;align-items:center;gap:10px;width:100%;min-height:56px;
  padding:8px 4px;border:0;background:none;text-align:left;cursor:pointer;
  border-bottom:1px solid var(--trait);color:var(--encre);font:inherit;
}
.ligne-reglage:last-child{border-bottom:0}
.ligne-reglage span{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.ligne-reglage small{font-size:.76rem;color:var(--gris);font-weight:700}
.ligne-reglage b{font-family:'Fredoka';font-weight:500;font-size:1rem;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ligne-reglage i{font-style:normal;font-size:1.4rem;color:var(--gris);line-height:1}

/* ---------- écran d'explication : surtitre et scène des jetons ---------- */
.intro-sur{
  display:block;font-family:'Fredoka';font-size:.76rem;font-weight:500;
  text-transform:none;letter-spacing:0;color:var(--saison-fonce);
  margin-bottom:8px;
}
.sc-filet{
  display:flex;flex-direction:column;align-items:center;gap:16px;
  position:relative;
}
.sc-filet .jeton{
  position:absolute;left:50%;top:8px;margin-left:-26px;
  width:52px;height:52px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--coffre);color:#FFD166;font-size:1.3rem;
  box-shadow:0 6px 16px color-mix(in srgb, var(--coffre) 40%, transparent);
  animation:jeton-arrive 4s ease-in-out infinite;
  animation-delay:calc(var(--i) * .45s);
}
.sc-filet .jeton:nth-child(1){transform:translate(-99px,-10px)}
.sc-filet .jeton:nth-child(2){transform:translate(-33px,-30px)}
.sc-filet .jeton:nth-child(3){transform:translate(33px,-30px)}
.sc-filet .jeton:nth-child(4){transform:translate(99px,-10px)}
.sc-filet .filet-mot{
  margin-top:64px;font-family:'Fredoka';font-size:1rem;color:var(--coffre-fonce);
  background:var(--coffre-clair);padding:8px 18px;border-radius:999px;
}

/* ---------- écran d'explication : scène des jeux et du quiz ----------
   Mêmes proportions et même animation que .sc-plateau (case qui
   s'allume l'une après l'autre) : c'est le même vocabulaire visuel,
   pas une nouvelle scène à apprendre. Le quiz est à part et prend la
   couleur du coffre, pour se distinguer des trois jeux sans un mot de
   plus - exactement la séparation que fait déjà l'écran Bonus entre
   son bloc « Les jeux » et son bloc « Teste tes connaissances ». */
.sc-jeux{display:flex;flex-direction:column;align-items:center;gap:16px}
.sc-jeux-ligne{display:flex;gap:12px}
.sc-jeux-case,.sc-jeux-quiz{
  width:56px;height:56px;border-radius:16px;
  display:flex;align-items:center;justify-content:center;
  animation:case-allume 3.6s ease-in-out infinite;
  animation-delay:calc(var(--i) * .16s);
}
.sc-jeux-case{
  background:color-mix(in srgb, var(--saison) 14%, #fff);
  border:2.5px solid var(--saison);
}
.sc-jeux-quiz{
  background:color-mix(in srgb, var(--coffre) 14%, #fff);
  border:2.5px solid var(--coffre);
}

/* ---------- code d'invitation ---------- */
.code-invitation{
  margin-top:14px;padding:16px;border-radius:var(--r-m);text-align:center;
  background:var(--coffre-clair);
}
.code-invitation b{
  display:block;font-family:'Fredoka';font-size:2rem;font-weight:700;
  letter-spacing:.22em;color:var(--coffre-fonce);
}
.code-invitation span{
  display:block;font-size:.8rem;color:var(--gris);margin-top:6px;
}
/* Un bouton qui porte SES precisions, sur deux lignes dans sa propre
   boite. Le bouton de fratrie annoncait « les 3 aventuriers » et la
   liste des prenoms vivait dans un <p> juste dessous, hors du cadre :
   la question et sa reponse se lisaient comme deux choses sans
   rapport. Les deux lignes sont centrees par .bouton, qui porte deja
   text-align:center. */
.bouton-lignes{display:flex;flex-direction:column;gap:2px;min-width:0}
.bouton-lignes b{font-weight:600;line-height:1.2}
.bouton-lignes small{
  font-size:.82rem;font-weight:400;color:var(--gris);line-height:1.3;
}

/* Fermer le partage est un RETRAIT, et il se pose juste sous les deux
   actions qui DONNENT l'acces. Empile nu, il avait exactement le poids
   du « Un code pour Ambre seulement » du dessus : deux boutons
   fantomes de suite, l'un qui ouvre et l'autre qui ferme. Un filet et
   l'encre d'automne suffisent a les separer. Pas de teinte d'alerte
   pleine : rien n'est efface ici, et on repartage d'un tap - les
   reglages n'ont plus de section qui annonce du danger depuis la
   4.0.0, et ce n'est pas le moment d'en reouvrir une. */
.bouton-retrait{color:var(--automne-encre)}
/* Le filet est a PART, parce qu'il ne se justifie que quand un bouton
   qui DONNE l'acces est juste au-dessus : cote proprietaire, « fermer
   le partage » suit deux boutons d'invitation et deux fantomes
   empiles ne se distinguaient pas. Cote parent invite il n'y a rien
   a separer, et un filet qui ne separe rien se lit comme une erreur
   de mise en page. */
.bouton-retrait--filet{
  margin-top:14px;padding-top:15px;border-top:1px solid var(--trait);
}

/* dans la modale, le code est fait pour etre dicte a voix haute */
.code-invitation--grand{margin-top:4px}
.code-invitation--grand b{font-size:2.6rem;letter-spacing:.26em}

/* ============================================================
   Tablette et ordinateur
   ------------------------------------------------------------
   Même application, plus d'air. La barre d'onglets devient une
   pastille flottante, les grilles s'élargissent, et l'écran
   d'accueil se met côte à côte.
   ============================================================ */
@media (min-width:700px){
  #vue{padding:14px 24px 40px;max-width:820px}
  #entete{padding-top:calc(var(--haut) + 16px);max-width:820px;margin:0 auto;width:100%}
  #entete .qui b{font-size:1.3rem}

  #onglets{
    position:fixed;left:50%;bottom:calc(var(--bas) + 16px);transform:translateX(-50%);
    flex:none;
    width:auto;max-width:520px;gap:4px;padding:6px;
    border:1px solid var(--trait);border-radius:999px;
    box-shadow:var(--ombre-m);background:color-mix(in srgb, var(--papier) 96%, transparent);
  }
  #onglets a{padding:8px 22px;border-radius:999px;flex-direction:row;gap:8px;font-size:.9rem}
  #onglets a .ico{font-size:1.15rem}
  #onglets a.actif{background:var(--saison-clair)}
  #onglets a.actif .ico{transform:scale(1.1)}
  #vue{padding-bottom:104px}

  .grille-cases{grid-template-columns:repeat(9,1fr);gap:8px}
  .case-plateau{min-height:96px;padding:8px}
  .case-plateau .nom{font-size:.76rem}

  /* La carte est deja en ligne sur telephone : ici, le coffre respire */
  .coffre-carte{align-items:center;gap:22px;padding:20px 24px}
  .coffre-visuel{width:140px}
  .coffre-carte h3{font-size:1.25rem}
  .coffre-carte p{font-size:.95rem}
  .tresor-coffre{width:200px}

  .soirs{max-width:460px}
  .chiffres{max-width:560px}

  .cat-bonus{break-inside:avoid}

  /* ------------------------------------------------------------
     Sur un écran large, le dessin tient EN ENTIER
     ------------------------------------------------------------
     La scène devient une colonne pleine hauteur, et elle est bien
     plus large que le dessin n'est haut. Étiré à cette largeur, le
     dessin débordait par le haut — 360 px hors champ sur un écran de
     1900 — et ce qui sortait en premier était son sommet : le soleil,
     les étincelles, et le coffre. C'est-à-dire le seul objet que
     cette illustration existe pour montrer.

     Sur le bandeau d'un téléphone, rogner le ciel reste le bon choix
     et ne change pas. Ici, le dessin tient en entier, posé au bas de
     la colonne, et la teinte haute du ciel comble les côtés — c'est
     la même que celle de .hero-scene, donc le raccord ne se voit que
     là où les collines touchent le bord.
     ------------------------------------------------------------ */
  .porte{flex-direction:row;align-items:stretch}
  .hero-scene{flex:1;min-height:100dvh;container-type:size}
  .hero-fond{height:100%;min-height:0}

  /* Les deux ailes de terrain
     ------------------------------------------------------------
     Le dessin tient en entier, donc il ne touche plus les bords : il
     reste une bande de ciel de chaque côté, et en bas cette bande
     coupe les collines net. Les deux ailes les prolongent jusqu'au
     bord, à la hauteur EXACTE où chaque colline touche son bord dans
     le dessin — 29,3 % de la hauteur à gauche, 41,4 % à droite, la
     colline de devant s'arrêtant respectivement à 15 % et 22,1 %.

     La largeur d'une aile se calcule : le dessin fait 360/280 de son
     côté, donc sa largeur rendue vaut 1,2857 fois la hauteur de la
     scène — d'où les unités de conteneur (cqh) et le container-type
     ci-dessus. Le pixel en plus évite un cheveu clair au raccord. */
  .hero-scene::before,
  .hero-scene::after{
    content:"";position:absolute;bottom:0;pointer-events:none;
    width:calc((100% - 100cqh * 1.2857) / 2 + 1px);
  }
  /* Les teintes ne sont pas choisies a l'oeil : ce sont les valeurs
     exactes des deux degrades du dessin, relevees a la hauteur ou
     chaque colline touche son bord. C'est ce qui rend le raccord
     invisible - a un demi-ton pres, on verrait deux rectangles. */
  .hero-scene::before{
    left:0;height:29.3cqh;
    background:linear-gradient(to top,
      #5BAD84 0,            /* colline de devant, au ras du bas */
      #76C49B 51.2%,        /* son bord gauche, a y=238 */
      #89CE9B 51.2%,        /* la colline du fond reprend */
      #9ADBA7 100%);        /* son bord gauche, a y=198 */
  }
  .hero-scene::after{
    right:0;height:41.4cqh;
    background:linear-gradient(to top,
      #5BAD84 0,
      #83CFA6 53.4%,        /* bord droit de la colline de devant, y=218 */
      #91D2A0 53.4%,
      #A7DEB1 100%);        /* bord droit de la colline du fond, y=164 */
  }
  .porte-carte{
    flex:none;width:min(460px, 44vw);margin:0;border-radius:0;
    display:flex;flex-direction:column;justify-content:center;
    padding:40px 36px;box-shadow:-8px 0 30px rgba(22,35,63,.12);
  }

  .ecran-intro,.parcours{max-width:560px;padding-left:24px;padding-right:24px}
  .intro-scene{min-height:260px}
  .grille-figurines{grid-template-columns:repeat(3,1fr);gap:14px}
  #modale .boite{max-width:520px}
  .cel-boite{max-width:540px}
}

@media (min-width:1100px){
  #vue{max-width:980px}
  #entete{max-width:980px}
}

/* le pointeur fin n'a pas besoin de cibles de 44 px partout,
   mais on garde les zones confortables : on ajoute juste le survol */
@media (hover:hover){
  .bouton:hover{filter:brightness(1.06)}
  .case-plateau:hover{box-shadow:var(--ombre-m)}
  .tuile-enfant:hover{box-shadow:var(--ombre-m)}
  .choix-carte:hover,.choix-figurine:hover{border-color:var(--saison)}
  #onglets a:hover{color:var(--saison-fonce)}
}

/* ---------- panneau de diagnostic de connexion ---------- */
.diagnostic{
  margin-top:6px;border-radius:var(--r-m);
  background:color-mix(in srgb, var(--papier) 70%, transparent);
  border:1px solid var(--trait);
  font-size:.82rem;
}
.diagnostic summary{
  cursor:pointer;padding:11px 14px;min-height:44px;
  display:flex;align-items:center;
  font-family:'Fredoka';color:var(--gris);
}
.diagnostic[open] summary{border-bottom:1px solid var(--trait)}
.diagnostic dl{
  display:grid;grid-template-columns:auto 1fr;gap:4px 12px;
  padding:12px 14px;margin:0;
}
.diagnostic dt{color:var(--gris);font-weight:700}
.diagnostic dd{margin:0;color:var(--encre);word-break:break-word}
.bouton-google.attente{opacity:.6;pointer-events:none}

/* ============================================================
   Écran de jeu : tout tient dans la hauteur disponible
   ------------------------------------------------------------
   La carte du défi absorbe l'espace restant ; seule une
   description très longue défile, à l'intérieur de sa carte.
   ============================================================ */
/* height, et non plus min-height.
   ------------------------------------------------------------
   Avec min-height, la colonne avait le droit de depasser : elle le
   faisait d'environ 70 px sur un telephone ordinaire et de 190 sur un
   iPhone SE, et l'accueil - l'ecran du soir, celui qu'on ouvre tous
   les jours - se terminait par un defilement pour atteindre trois
   chiffres et une ligne de contexte.
   Bornee, la colonne distribue sa hauteur : la carte du defi rend ce
   qu'il faut, son corps defile en dedans si la description est
   longue, et l'action reste entiere. Rien n'est retire, et plus rien
   ne depasse. */
.ecran-jeu{
  display:flex;flex-direction:column;gap:12px;
  height:100%;min-height:0;
}
/* min-height:auto, et c'est la règle qui compte ici.
   ------------------------------------------------------------
   La carte rogne son contenu (overflow:hidden, pour le halo d'angle).
   Avec min-height:0 elle acceptait de se réduire en dessous de ce que
   son action occupe — et l'action se retrouvait coupée : sur une
   semaine couverte par un jeton et feuilletée, le ruban violet était
   tranché en deux et « Reprendre le jeton » devenait inatteignable.

   Bornée à son contenu minimum, la carte cesse de céder au bon
   moment. Le corps du défi reste le seul élément compressible, et si
   même lui ne suffit plus, c'est #vue qui défile : un écran qui
   défile est un désagrément, un bouton invisible est un bug. */
/* min-height:auto, et cette fois c'est mesure DANS LES DEUX SENS.
   ------------------------------------------------------------
   Passe a 0 le 14 septembre 2026 pour que la colonne tienne par
   construction : la carte cedait et son corps defilait. Resultat a
   l'ecran, verifie tout de suite : le texte du defi tronque au milieu
   d'une phrase, avec une barre de defilement dans la carte. C'est
   precisement ce que la 1.4.0 avait deja paye, sous une autre forme.

   La carte reste donc bornee a « tout le texte + l'action entiere »,
   et les pixels qui manquaient ont ete pris ailleurs : le « ? » sort
   du flux (44 px), et le cran des ecrans de moins de 900 px resserre
   ce qui pouvait l'etre. Mesure sur les 144 defis du projet : plus
   rien ne depasse a 393x852 ni a 390x844. */
.ecran-jeu .carte-defi{
  flex:1 1 auto;min-height:auto;
  display:flex;flex-direction:column;
  padding:18px;
}
/* Seul le corps du defi defile. L'action, elle, ne defile jamais :
   c'est la seule garantie qu'un bouton principal reste atteignable
   quelle que soit la hauteur de l'ecran. */
/* Le texte du défi n'est JAMAIS tronqué, et c'est la règle qui prime.
   ------------------------------------------------------------
   Il a été, pendant une version, posé en couche absolue avec un
   défilement interne, pour que la carte puisse se comprimer et que
   l'accueil ne défile jamais. C'était le mauvais arbitrage : sur un
   téléphone de taille moyenne, la dernière ligne de la consigne
   passait sous le bouton. Or c'est le texte du défi qui est la raison
   d'être de cet écran — l'enfant doit pouvoir le lire en entier, sans
   savoir qu'il y a quelque chose à faire défiler.

   Le corps reprend donc sa hauteur naturelle. La carte, en
   `min-height:auto`, se borne à « tout le texte + l'action » et
   n'entame plus rien. Si l'ensemble ne tient pas dans l'écran, c'est
   la page qui défile — un désagrément, contre un défi illisible.
   L'espace en trop, lui, revient au corps : le texte se centre au
   lieu de coller au bouton. */
.ecran-jeu .defi-corps{
  flex:1 1 auto;min-height:0;
  display:flex;flex-direction:column;
  /* "safe" : si le contenu deborde malgre tout, il s'aligne en haut au
     lieu d'etre rogne des deux cotes */
  justify-content:safe center;
  /* PAS d'overflow ici : essaye, et le texte du defi s'est retrouve
     tronque au milieu d'une phrase. Le corps rend sa hauteur entiere,
     la carte s'y borne, et si vraiment rien ne tient - une police
     systeme tres agrandie - c'est #vue qui defile. Un ecran qui
     defile est un desagrement, un texte coupe est un defi illisible. */
  /* le « ? » est pose dans son angle bas droit, hors du flux */
  position:relative;
}

/* Le « ? » ne prend plus de hauteur a lui seul.
   ------------------------------------------------------------
   Il occupait une bande de 44 px SOUS le texte, et c'est cette bande
   qui faisait passer la rangee des trois chiffres sous les onglets sur
   un iPhone 15. Hors du flux, il ne coute plus rien.

   EN HAUT a droite, et pas en bas - mesure, pas gout. En bas de la
   carte il y a l'action, qu'il ne doit pas concurrencer du doigt. Et
   en bas du TEXTE il n'y a pas de place : la carte est bornee a la
   hauteur de son contenu, donc le corps n'a aucun vide sous la
   derniere ligne. Verifie sur les 144 defis du projet : le disque
   recouvrait du texte dans 80 cas, jusqu'a 28 px.

   La droite des deux lignes d'entete, elle, est libre partout : 124 px
   au minimum sur les 144 (le pire est « ★ Grand defi · coffre » +
   « Defi 27 »). Le padding-right sur .haut reserve la place, pour que
   ce soit vrai aussi le jour ou une pastille s'allonge. */
.ecran-jeu .indice-bouton{
  position:absolute;top:-7px;right:-6px;bottom:auto;margin:0;
}
.ecran-jeu .carte-defi .haut{padding-right:46px}
.ecran-jeu .defi-action{flex:none;margin-top:14px}

/* ------------------------------------------------------------
   Feuilleter au doigt (7.0.0, sur tout l'ecran depuis la 7.0.1)
   ------------------------------------------------------------
   Le geste vit dans brancherGlissement(), js/ui/accueil.js. La ZONE
   est la section entiere de l'accueil ; ce qui GLISSE est la semaine
   - la carte et le rituel du soir -, pas l'annee.

   pan-y, et rien d'autre : le navigateur garde la verticale - sur
   375 px de large l'accueil defile encore un peu - et laisse
   l'horizontale au geste. Le `manipulation` pose sur tout le document
   ne suffit pas, il laisse le navigateur prendre aussi les glissements
   horizontaux. Les boutons de l'ecran - les soirs compris - heritent
   de la restriction : la valeur effective est l'intersection avec
   celle de leurs parents.

   Des noms PREFIXES, et ce n'est pas du style : ces classes se posent
   desormais sur tout ce que contient la section, et un « .part » ou un
   « .revient » generiques finiraient par attraper un element qui n'a
   rien a voir (voir « Les classes CSS generiques entrent en
   collision » dans CLAUDE.md). */
.ecran-jeu.glissable{touch-action:pan-y}
/* pendant le geste : rien ne se selectionne, ni le texte du defi ni
   celui du rituel, et la semaine colle au doigt sans retard */
.ecran-jeu.glisse-en-cours{
  cursor:grabbing;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;
}
.ecran-jeu .glisse-suit{transition:none;will-change:transform}
/* relachee trop tot, ou au bout du carnet : elle revient en souplesse */
.ecran-jeu .glisse-revient{transition:transform .26s var(--ressort)}
/* relachee assez loin : elle s'en va, la semaine suivante arrive */
.ecran-jeu .glisse-part{transition:transform .17s ease-in, opacity .17s ease-in;pointer-events:none}

/* ------------------------------------------------------------
   La vie de la saison, en fond de la carte du défi
   ------------------------------------------------------------
   Quelques feuilles, flocons, pétales ou éclats de lumière, très
   discrets, derrière le texte du défi. Le contenu et les règles de
   ton sont dans js/ui/accueil.js ; ici, trois choses de mise en
   page qui ne se devinent pas :

   1. LA COUCHE TIENT DANS LE COIN HAUT DROIT, et pas sur toute la
      carte. C'est un arbitrage, pris après l'avoir vu tourner : sur
      la carte entière, des feuilles traversaient le texte du défi
      sur toute sa hauteur et prenaient l'attention que cet écran
      doit à la consigne du soir. Cantonnées à 46 % de large sur
      54 % de haut, autour du « ? » du coup de pouce, elles se
      suggèrent au lieu de se raconter.

      Elle déborde de 16 px en haut et de 12 px à droite : les
      particules mordent sur le bandeau de la semaine et sur la
      marge, ce qui les détache de la carte au lieu de les y
      enfermer. Jamais vers le BAS, en revanche : #vue défile, et un
      absolu qui dépasse par le bas allongerait sa hauteur de
      défilement — sur le seul écran du produit qui ne doit JAMAIS
      défiler.

   2. `container-type:size` est ce qui permet d'écrire `100cqh`
      dans les keyframes, c'est-à-dire « tombe sur toute la hauteur
      de la carte », quelle que soit la longueur du défi. Un
      translateY en `%` aurait porté sur la taille de la feuille,
      pas sur celle de la carte : les feuilles seraient tombées de
      dix-sept pixels. C'est le même mécanisme que `.hero-scene`.

   3. Le texte passe DEVANT (z-index 1 contre 0). `.defi-corps`
      était déjà `position:relative` ; `.defi-action` ne l'était
      pas, et sans ces deux lignes une feuille passait sur le
      bouton principal.
   ------------------------------------------------------------ */
.saison-vie{
  position:absolute;top:-16px;right:-12px;
  /* En % pour que le coin reste un coin sur un téléphone, mais borné
     en px : sur un grand écran la carte fait plus de 1000 px de haut,
     et 54 % de ça faisait tomber les feuilles sur 560 px, c'est-à-dire
     en plein milieu du texte du défi. Les deux plafonds ne changent
     rien en dessous de 410 px de large — donc rien sur un téléphone. */
  width:46%;height:54%;
  max-width:190px;max-height:220px;
  z-index:0;pointer-events:none;
  container-type:size;
}
.ecran-jeu .defi-corps{z-index:1}
.ecran-jeu .defi-action{position:relative;z-index:1}

.saison-vie .sv{
  position:absolute;left:var(--x);top:0;
  display:block;line-height:0;opacity:0;
  animation:sv-chute var(--d) linear infinite;
  animation-delay:var(--delai);
}
/* L'Été monte au lieu de tomber : de la lumière, pas de la matière.
   Rien ne tombe au soleil, et des « rayons » qui descendraient se
   liraient comme des feuilles décolorées. */
.saison-vie--ete .sv{animation-name:sv-montee}
/* Le scintillement est porté par le SVG, pas par le span : les deux
   opacités se multiplient, donc l'éclat continue d'apparaître et de
   disparaître avec sa trajectoire. Sur le même élément, la seconde
   animation aurait simplement écrasé la première. */
.saison-vie--ete .sv svg{
  animation:sv-scintille 2.1s ease-in-out infinite;
  animation-delay:inherit;
}
.ecran-jeu .defi-action .ruban-fait{margin-top:0}
.defi-action .defaire{margin-top:2px}
.ecran-jeu .carte-defi .haut{margin-bottom:8px}
.ecran-jeu .carte-defi h2{margin-bottom:5px}
.ecran-jeu .carte-defi .domaine{margin-bottom:10px}
.ecran-jeu .carte-defi .quoi{line-height:1.45}
.ecran-jeu .bandeau-semaine{margin:0 0 2px}
.ecran-jeu .titre-section{margin-bottom:6px}
.ecran-jeu .carte-defi h2{font-size:1.6rem}
.jeu-cote{flex:none;display:flex;flex-direction:column;gap:14px}
.ecran-jeu .bloc-soirs{margin-top:0}
.ecran-jeu .bloc-soirs .consigne{font-size:.8rem;line-height:1.35;margin-bottom:10px}
/* hauteur fixe plutot qu'un rapport : les cases du soir ne doivent pas
   grandir avec la largeur de l'ecran, sinon la carte du defi se retrouve
   ecrasee sur les grands telephones */
.ecran-jeu .soir{aspect-ratio:auto;height:66px;min-height:0}
.ecran-jeu .soir .lettre{font-size:.8rem}
.ecran-jeu .soirs--cinq .soir .lettre{font-size:.66rem}
.ecran-jeu .annee-ligne{margin-top:12px}
.ecran-jeu .prochain-coffre{
  margin-top:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.ecran-jeu .carte-defi .bouton{min-height:50px}
.ecran-jeu .carte-defi .bouton--fantome{min-height:44px;font-size:.95rem}
/* Le retour a sa semaine, et la marche arriere : deux sorties qui
   doivent exister sans se disputer l'attention avec l'action du jour. */
.retour-semaine,
.ecran-jeu .carte-defi .retour-semaine{
  min-height:46px;font-size:.95rem;margin-top:10px;
}
.defi-attente{
  font-size:.95rem;color:var(--gris);text-align:center;margin-bottom:2px;
}

/* troisieme rang de la hierarchie, sous le jeton : meme famille que le
   texte courant, pas de couleur, pas d'emoji. On le trouve si on le
   cherche, il ne se propose jamais de lui-meme. */
.passer-semaine, .defaire,
.ecran-jeu .carte-defi .passer-semaine,
.ecran-jeu .carte-defi .defaire{
  min-height:44px;padding:8px 12px;
  font-family:'Nunito';font-size:.88rem;font-weight:600;
  color:var(--gris);text-decoration:underline;
  text-decoration-color:var(--trait);text-underline-offset:3px;
}
.ecran-jeu .jeu-cote{gap:12px}

/* écrans moyens : le premier cran de resserrement.
   ------------------------------------------------------------
   Le seuil etait a 800 px, et laissait sans rien faire toute la
   famille des telephones de 820 a 900 px de haut - c'est-a-dire la
   plupart des iPhone recents une fois la barre d'etat retiree. C'est
   exactement la que la derniere ligne du defi passait sous le bouton.
   ------------------------------------------------------------ */
@media (max-height:900px){
  .ecran-jeu{gap:7px}
  .ecran-jeu .carte-defi{padding:14px 16px}
  .ecran-jeu .bloc-soirs .consigne{
    font-size:.78rem;line-height:1.3;margin-bottom:7px;
  }
  .ecran-jeu .annee-ligne{margin-top:10px}
  .ecran-jeu .prochain-coffre{margin-top:6px}
  .ecran-jeu .jeu-cote{gap:7px}
  /* 48 px, et la cible tactile des 44 px tient toujours.
     Les huit derniers pixels manquants viennent d'ICI, en un seul
     endroit, et pas d'un grignotage de 1 px sur cinq reglages
     differents - c'est l'etat « jeton pose » qui les demandait, sa
     phrase de contexte prenant une ligne de plus que la consigne
     ordinaire. Une case de soir a 48 px reste une belle cible ; cinq
     reglages rabotes d'un pixel auraient rendu ce bloc illisible. */
  .ecran-jeu .soir{height:48px}
  .ecran-jeu .progression .titre-section{margin-bottom:24px}
  /* Le ruban « c'est fait » et le pas au-dessus de l'action : les
     8 px qui manquaient aux etats validee et jeton, ou l'action porte
     un ruban de 52 px en plus des deux liens. */
  .ecran-jeu .defi-action{margin-top:10px}
  .ecran-jeu .ruban-fait{padding:11px 16px}
  .ecran-jeu .bloc-soirs .consigne--note{margin-top:10px}
  /* Le bloc de l'annee, resserre en dedans : les huit derniers pixels
     de l'etat « jeton » sur un ecran de 844 px. La barre reste bien
     visible a 12 px, et les coffres qui y sont poses ne bougent pas
     (ils sont centres par transform, cf. .jalon-barre). */
  .ecran-jeu .barre{height:12px}
  .ecran-jeu .annee-ligne{margin-top:8px}
  .ecran-jeu .prochain-coffre{margin-top:4px}
}

/* Cran de LARGEUR, et il manquait : tous les autres crans du projet
   portent sur la hauteur, alors que le nombre de lignes d'un texte
   depend de sa LARGEUR. Sur un ecran de 375 px, chaque bloc de texte
   prend une ligne de plus que sur 393 - la description d'un defi passe
   de trois lignes a quatre - et aucune regle ne le voyait.
   Il retirait la redite « Terre d'Automne », que disait aussi la
   pastille de la carte.
   Le cran de largeur ne retire plus « Terre d'Automne » sous la semaine
   (7.2.0) : la pastille de la carte qui le redisait est partie, il est
   donc le seul a nommer la terre. Mesure : 375 x 812 tient toujours sans
   defiler avec lui. Seul le cran des ecrans courts le retire encore, et
   le signe dessine devant « Défi 7 » dit alors la saison. */

/* écrans courts : on resserre encore.
   Rien n'est retire, tout est rapproche. En dessous de cette taille,
   l'accueil finit par depasser et la page defile : c'est assume, le
   texte du defi et l'action passent avant. */
@media (max-height:700px){
  .ecran-jeu{gap:7px}
  .ecran-jeu .carte-defi{padding:12px 16px}
  /* La redite, et elle seule : « Terre d'Automne » est deja sur la
     pastille de la carte, juste en dessous. « on feuillette · retour
     semaine 13 » reste, toujours - c'est la seule chose qui dise ou
     l'on est quand on a quitte sa semaine. */
  .ecran-jeu .bandeau-semaine .saison-redite{display:none}
  .ecran-jeu .titre-section{font-size:.78rem}
  .ecran-jeu .barre{height:12px}
  .ecran-jeu .defi-action{margin-top:8px}
  .ecran-jeu .carte-defi h2{font-size:1.35rem}
  .ecran-jeu .carte-defi .quoi{font-size:.95rem}
  /* :not(--note) : la consigne generale s'efface, la phrase de contexte
     reste. Sans cette precision, un ecran court en etat jeton n'aurait
     plus AUCUN message - or c'est celui-la qui explique pourquoi la
     semaine est deja gagnee. */
  .ecran-jeu .bloc-soirs .consigne:not(.consigne--note){display:none}
  /* 48 px, et pas moins : la regle des 44 px de cible tactile tient
     ici comme ailleurs, y compris sur le plus petit des iPhone. */
  .ecran-jeu .soir{height:48px}
  .ecran-jeu .jeu-cote{gap:5px}
  .ecran-jeu .titre-section{margin-bottom:2px}
  .ecran-jeu .progression .titre-section{margin-bottom:22px}
  .ecran-jeu .carte-defi .bouton{min-height:48px}
  .annee-ligne{margin-top:7px;font-size:.9rem}
  .annee-ligne b{font-size:1.1rem}
  /* le compagnon de la barre se fait plus petit, et la place qu'on
     lui reserve au-dessus avec lui */
  .pion-barre{width:28px;height:28px}
  .carte-defi .saison-carte{display:inline}
  .ecran-jeu .annee-ligne .jetons svg{width:18px;height:18px}
  .prochain-coffre{margin-top:4px;font-size:.78rem}
  .ecran-jeu .progression .titre-section{margin-bottom:22px}
  .ecran-jeu .defi-action{margin-top:7px}
  /* :has est deja utilise ailleurs dans la feuille (.segment, .bascule) */
  #vue:has(.ecran-jeu){padding-bottom:8px}
}

@media (min-width:700px){
  .ecran-jeu{
    display:grid;grid-template-columns:1.05fr 1fr;gap:10px 22px;
    align-items:start;height:auto;min-height:0;
  }
  /* le bandeau traverse les deux colonnes, mais reste centre :
     colle aux bords de l'ecran il donnait une impression de vide */
  .ecran-jeu .bandeau-semaine{grid-column:1 / -1;max-width:440px;margin:0 auto;width:100%}
  .ecran-jeu .carte-defi{grid-column:1;min-height:0}   /* en grille, plus de partage de hauteur */
  .ecran-jeu .defi-corps{min-height:0}
  .jeu-cote{grid-column:2;gap:20px}
}

/* ============================================================
   Réglages : sections repliables
   ------------------------------------------------------------
   Six groupes déployés en même temps feraient une page
   interminable. Chaque section annonce son contenu dans son
   résumé, et ne s'ouvre que si on en a besoin.
   ============================================================ */
.titre-reglages{margin-bottom:2px}
.sous-reglages{color:var(--gris);margin:0 0 12px;font-size:.92rem}

.pliant{
  background:var(--papier);border-radius:var(--r-l);
  box-shadow:var(--rebord), var(--arete), var(--ombre-s);margin-bottom:8px;overflow:hidden;
}
.pliant > summary{
  list-style:none;cursor:pointer;
  min-height:58px;padding:10px 18px;
  display:flex;flex-direction:column;justify-content:center;gap:2px;
  position:relative;
  transition:background .18s;
}
.pliant > summary::-webkit-details-marker{display:none}
/* Le titre porte la teinte de sa section, et une pastille la rappelle :
   les sections ne sont plus des cartes blanches identiques. Le fond reste
   blanc - colorer les fonds aurait fait un arc-en-ciel. C'etait un filet
   sur le bord gauche jusqu'en 7.3.0, le motif retire partout ailleurs en
   7.1.1 (« trop IA ») et oublie ici. */
.pliant > summary span{
  font-family:'Fredoka';font-size:1.05rem;font-weight:600;
  color:var(--s-encre, var(--encre));
}
.pliant > summary span::before{
  content:"";display:inline-block;width:9px;height:9px;border-radius:50%;
  margin-right:9px;vertical-align:.1em;background:var(--s, var(--trait));
}
.pliant > summary small{color:var(--gris);font-size:.82rem;padding-left:18px}
.pliant[open] > summary{
  border-bottom-color:color-mix(in srgb, var(--s, var(--trait)) 38%, var(--trait));
}
.pliant > summary:active{
  background:color-mix(in srgb, var(--s, var(--saison)) 9%, #fff);
}
.pliant > summary::after{color:var(--s, var(--trait))}
.pliant > summary::after{
  content:"›";position:absolute;right:18px;top:50%;
  transform:translateY(-50%) rotate(90deg);
  font-family:'Fredoka';font-size:1.4rem;color:var(--trait);
  transition:transform .25s var(--ressort);
}
.pliant[open] > summary::after{transform:translateY(-50%) rotate(-90deg)}
.pliant[open] > summary{border-bottom:1px solid var(--trait)}
.pliant > summary:active{background:var(--saison-clair)}

.pliant-corps{padding:18px;animation:monte .28s var(--doux)}
.pliant-corps > .carte{box-shadow:none;background:var(--fond)}
.pliant-corps .champ:last-of-type{margin-bottom:18px}

/* ============================================================
   L'historique des versions (modale, ui/historique.js)
   ------------------------------------------------------------
   Une liste, pas un tableau : sur un téléphone, deux colonnes
   auraient coupé chaque ligne en deux. Le numéro de version fait
   office de titre, la date le suit en gris, et une pastille ouvre
   chaque entrée. Plus de filet à gauche (7.3.0) : aucune bande sur un
   seul bord, nulle part dans le carnet.
   ============================================================ */
.histo{list-style:none;text-align:left;margin-top:18px}
.histo > li{position:relative;padding:0 0 18px 18px}
.histo > li:last-child{padding-bottom:2px}
.histo > li::before{
  content:"";position:absolute;left:0;top:6px;
  width:10px;height:10px;border-radius:50%;
  background:var(--trait);
}
/* La version installée est la seule à porter la couleur : c'est la
   question qu'on se pose en ouvrant cette fenêtre — où en suis-je ? */
.histo > li.histo--ici::before{
  background:var(--saison);
  box-shadow:0 0 0 4px color-mix(in srgb, var(--saison) 20%, transparent);
}
.histo-titre{
  display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
  margin:0 0 6px;
}
.histo-titre b{
  font-family:'Fredoka';font-size:1.02rem;font-weight:600;color:var(--encre);
}
.histo--ici .histo-titre b{color:var(--saison-encre)}
.histo-titre span{font-size:.76rem;color:var(--gris)}
.histo > li > ul{list-style:none;margin:0}
.histo > li > ul > li{
  position:relative;padding-left:14px;margin-bottom:6px;
  font-size:.89rem;line-height:1.5;color:var(--encre-douce);
}
.histo > li > ul > li:last-child{margin-bottom:0}
.histo > li > ul > li::before{
  content:"";position:absolute;left:0;top:.6em;
  width:5px;height:5px;border-radius:50%;background:var(--trait);
}
.histo > li > ul > li b{color:var(--encre);font-weight:700}

/* Le lien qui l'ouvre, tout en bas des réglages. Troisième rang de la
   hiérarchie, comme « on passe à la semaine suivante » : même famille
   que le texte courant, pas de couleur, pas d'emoji. On le trouve si
   on le cherche, il ne se propose jamais de lui-même. La cible tient
   les 44 px malgré sa discrétion. */
.lien-versions{
  display:block;margin:18px auto 0;min-height:44px;padding:8px 12px;
  font-family:'Nunito';font-size:.86rem;font-weight:600;
  color:var(--gris);text-decoration:underline;
  text-decoration-color:var(--trait);text-underline-offset:3px;
}
.lien-versions--serre{margin-top:0}
.pied-version{
  text-align:center;color:var(--gris);font-size:.76rem;
  margin-top:2px;padding-bottom:4px;
}

/* ============================================================
   La relecture : une semaine par écran, au doigt
   ------------------------------------------------------------
   Plein écran, sans onglets. Une piste horizontale qui s'aimante
   sur chaque semaine, le plateau miniature en haut, le pion qui
   traverse l'année au fil de la lecture.

   Rien ici ne distingue une semaine validée d'une semaine restée
   à faire, hors la petite ligne verte quand il y a lieu de la
   mettre : toutes les pages ont la même forme, la même couleur de
   terre, le même poids. C'est la seule façon qu'une relecture
   reste un souvenir au lieu de devenir un bilan.
   ============================================================ */
.relecture{
  position:fixed;inset:0;z-index:40;
  display:flex;flex-direction:column;
  background:var(--fond);
}

.relec-haut{
  flex:none;padding:calc(var(--haut) + 10px) 14px 8px;
  display:grid;grid-template-columns:44px 1fr;gap:10px;align-items:center;
}
.relec-haut .relec-fermer{
  width:44px;height:44px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--papier);box-shadow:var(--ombre-s);font-size:1rem;color:var(--gris);
  transition:transform .18s var(--ressort);
}
.relec-haut .relec-fermer:active{transform:scale(.9)}
.relec-titre b{display:block;font-family:'Fredoka';font-size:1.15rem;line-height:1.1}
.relec-titre small{
  display:block;font-size:.76rem;color:var(--gris);font-weight:700;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.relec-plateau{grid-column:1 / -1;margin-top:8px;padding:8px}
.relec-plateau .mc{border-radius:4px}
.relec-plateau .pion > svg{width:26px;height:26px}

/* la piste : 36 pages qui s'aimantent */
.relec-piste{
  flex:1;min-height:0;
  display:flex;overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;
  scrollbar-width:none;outline:none;
}
.relec-piste::-webkit-scrollbar{display:none}

.relec-page{
  flex:none;width:100%;scroll-snap-align:start;scroll-snap-stop:always;
  overflow-y:auto;scrollbar-width:none;
  padding:6px 14px 14px;
  /* Chaque semaine porte sa propre saison, en fond (6.0.1). Retombe sur
     --fond si --t-clair n'est pas posee : un vieux relecture.js peut
     tourner avec un app.css neuf, l'inverse aussi - jamais de fond
     transparent qui laisserait voir la page precedente au travers. */
  background:var(--t-clair, var(--fond));
}
.relec-page::-webkit-scrollbar{display:none}
.relec-corps{
  min-height:100%;max-width:520px;margin:0 auto;
  display:flex;flex-direction:column;justify-content:safe center;gap:12px;
}

.relec-terre{
  text-align:center;font-family:'Fredoka';font-size:.78rem;font-weight:500;
  text-transform:none;letter-spacing:0;color:var(--gris);
}
.relec-carte{
  position:relative;overflow:hidden;
  background:var(--papier);border-radius:var(--r-xl);padding:20px;
  box-shadow:var(--ombre-m);
  text-align:center;
}
.relec-carte::before{
  content:"";position:absolute;top:-70px;right:-70px;width:180px;height:180px;
  border-radius:50%;background:color-mix(in srgb, var(--t) 10%, #fff);
}
.relec-carte > *{position:relative}
.relec-carte .pastille{background:color-mix(in srgb, var(--t) 13%, #fff);color:var(--t-encre)}
.relec-carte h2{font-size:1.5rem;margin:10px 0 4px}
.relec-domaine{font-family:'Fredoka';font-size:.88rem;color:var(--gris);margin-bottom:12px}
.relec-quoi{font-size:1rem;color:var(--encre-douce);line-height:1.5}
.relec-voile{color:var(--gris);font-style:italic}

.relec-etat{
  display:inline-flex;align-items:center;gap:6px;margin-top:14px;
  padding:7px 15px;border-radius:999px;
  font-size:.8rem;font-weight:800;
  background:var(--printemps-clair);color:var(--printemps-fonce);
}
.relec-etat--jeton{background:var(--coffre-clair);color:var(--coffre-fonce)}

.relec-bloc{
  background:var(--papier);border-radius:var(--r-l);padding:14px 16px;
  box-shadow:var(--rebord), var(--arete), var(--ombre-s);
}
.relec-bloc small{
  display:block;font-family:'Fredoka';font-size:.72rem;font-weight:500;
  text-transform:none;letter-spacing:0;color:var(--gris);margin-bottom:6px;
}
.relec-bloc p{font-size:.94rem;line-height:1.45;color:var(--encre-douce)}
.relec-note p{font-style:italic}
.relec-vecu{background:color-mix(in srgb, var(--t) 8%, #fff)}
.relec-blague{background:linear-gradient(165deg,#FFFAF0,#FFF2D8 60%,#FFEBC6);
  border:1.5px solid #E9C97F;box-shadow:var(--ombre-s)}
.relec-blague small{color:#B08636}
.relec-q{font-family:'Fredoka';color:var(--encre)}
.relec-r{
  font-family:'Fredoka';font-size:1.05rem;font-weight:600;
  color:var(--coffre-fonce);margin-top:6px;
}

.relec-bas{
  flex:none;display:flex;align-items:center;justify-content:center;gap:18px;
  padding:8px 14px calc(var(--bas) + 10px);
}
.relec-bas .relec-nav{
  width:48px;height:48px;border-radius:50%;background:var(--papier);
  display:flex;align-items:center;justify-content:center;
  color:var(--gris);box-shadow:var(--ombre-s);font-size:1.2rem;
  transition:transform .18s var(--ressort);
}
.relec-bas .relec-nav:active{transform:scale(.88)}
.relec-bas .relec-nav:disabled{opacity:.25}
.relec-compte{
  font-family:'Fredoka';font-size:.95rem;font-weight:600;color:var(--gris);
  min-width:76px;text-align:center;font-variant-numeric:tabular-nums;
}

@media (min-width:700px){
  .relec-haut{max-width:680px;margin:0 auto;width:100%;padding-top:calc(var(--haut) + 16px)}
  .relec-plateau{padding:12px}
  .relec-plateau .pion > svg{width:32px;height:32px}
  .relec-page{padding:10px 24px 18px}
}

/* ============================================================
   Le coup de pouce d'un défi
   ------------------------------------------------------------
   Un « ? » en bas à droite du texte du défi, et un rappel de la
   leçon quand on le tape. Il doit se remarquer quand on le cherche
   et s'effacer quand on ne le cherche pas : jamais en couleur de
   saison — ce serait concurrencer « Le défi est relevé », qui est
   la seule action principale de l'écran.
   ============================================================ */
.indice-bouton{
  display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;margin:6px -6px -6px auto;   /* collé au coin bas droit */
  font-family:'Fredoka';font-size:1.1rem;font-weight:600;
  color:var(--gris);
  transition:transform .18s var(--ressort), color .18s;
}
/* le disque visible fait 32 px ; les 44 px restent la cible tactile */
.indice-bouton::before{
  content:"";position:absolute;width:32px;height:32px;border-radius:50%;
  background:var(--papier);box-shadow:inset 0 0 0 2px var(--trait);
  transition:box-shadow .18s, background .18s;
}
/* Le « ? » passe AU-DESSUS de son disque : ::before est en absolu,
   donc il recouvrait le texte nu du bouton, qui n'est pas positionne.
   D'ou le <span>, qui l'est. */
.indice-bouton{position:relative}
.indice-bouton span{position:relative;line-height:1}
.indice-bouton:active{transform:scale(.9);color:var(--saison-encre)}
.indice-bouton:active::before{
  background:var(--saison-clair);
  box-shadow:inset 0 0 0 2px var(--saison);
}

/* ---- le contenu de la modale ---- */
.ind-defi{
  font-size:.76rem;font-weight:800;color:var(--gris);
  text-transform:none;letter-spacing:0;
  text-align:center;margin:-6px 0 14px;
}
/* L'exemple déjà résolu. C'est LUI qu'on vient voir : il a donc le
   fond, le cadre et la plus grosse typographie de la boîte. */
.ind-exemple{
  padding:16px 18px;border-radius:var(--r-m);
  background:var(--saison-clair);
  font-family:'Fredoka';font-size:1.08rem;font-weight:500;line-height:1.75;
  color:var(--encre);text-align:left;
}
.ind-exemple b{font-weight:700;color:var(--saison-encre)}
/* entouré au crayon, comme sur un cahier */
.ind-entoure{
  display:inline-block;padding:0 .34em;
  border:2px solid var(--saison-encre);border-radius:44% 56% 52% 48% / 58% 42% 56% 44%;
  color:var(--saison-encre);
}
.ind-souligne{
  border-bottom:2.5px solid var(--coffre);
  padding-bottom:1px;color:var(--coffre-encre);
}
.ind-legende{
  margin-top:8px;font-size:.76rem;color:var(--gris);
  text-align:left;line-height:1.5;
}
.ind-astuce{list-style:none;margin-top:16px;text-align:left}
.ind-astuce li{
  position:relative;padding:0 0 0 20px;margin-bottom:10px;
  font-size:.92rem;line-height:1.5;color:var(--encre-douce);
}
.ind-astuce li:last-child{margin-bottom:0}
.ind-astuce li::before{
  content:"";position:absolute;left:2px;top:.55em;
  width:7px;height:7px;border-radius:50%;background:var(--saison);
}
.ind-astuce b{color:var(--encre)}

/* Une precision de second plan dans une modale : plus petite et plus
   grise que le texte principal, pour qu'elle se lise apres lui et non
   avec lui. */
.note-modale{
  font-size:.85rem;color:var(--gris);line-height:1.45;margin-top:16px;text-align:left;
}

/* ============================================================
   Teste tes connaissances (4.0.0)
   ------------------------------------------------------------
   Le quiz reprend la coque des six jeux (.jeu-boite, .jeu-tete,
   .jeu-fermer) et pose le reste par-dessus : une carte de question,
   quatre facons d'y repondre, un pied a deux boutons. La coque est
   partagee pour la meme raison que pour les jeux - une copie, et
   toute retouche serait a faire sept fois.

   Deux choses qui ne se devinent pas :

   1. `touch-action:manipulation`, comme le pendu, et non le `none`
      des jeux a glissement. Il y a un CHAMP DE SAISIE ici : avec
      `none`, iOS ne laisse plus poser le curseur dans le texte, et
      la scene ne peut plus defiler quand un enonce long la fait
      deborder sur un petit ecran.
   2. C'est la SCENE qui defile, pas la boite. Le pied porte le
      bouton principal et ne doit jamais partir sous le bord -
      meme regle que l'action de la carte du defi sur l'accueil.
   ============================================================ */
#quiz{touch-action:manipulation}

/* Les dix pastilles : OU l'on en est, jamais comment on s'en sort.
   Pleine veut dire « repondu ». Elles ne verdissent ni ne rougissent :
   le quiz ne corrige rien en cours de route. */
.quiz-jauge{display:flex;gap:5px;flex:1;min-width:0;align-items:center}
.quiz-jauge i{
  flex:1;height:7px;max-width:26px;border-radius:4px;
  background:color-mix(in srgb, var(--gris) 28%, transparent);
  transition:background .2s ease, transform .2s var(--doux);
}
.quiz-jauge i.faite{background:var(--saison)}
.quiz-jauge i.ici{background:var(--saison);transform:scaleY(1.7)}

/* `safe center` et non `center` : la carte se centre tant qu'elle
   tient, et se recale EN HAUT des qu'elle deborde. Avec un `center`
   nu, un enonce long se ferait rogner des DEUX cotes et sa premiere
   ligne partirait hors du cadre - meme piege que sur la carte du
   defi de l'accueil, et meme parade. */
.quiz-scene{
  flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;
  display:flex;flex-direction:column;justify-content:safe center;
}
.quiz-carte{
  background:var(--papier);border-radius:var(--r-l);
  padding:20px 18px;box-shadow:var(--rebord), var(--arete), var(--ombre-m);
  animation:pop .28s var(--doux);
}
.quiz-matiere{
  display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  font-size:.68rem;font-weight:800;text-transform:none;letter-spacing:0;
  color:var(--saison-encre);margin-bottom:10px;
}
.quiz-rang{color:var(--gris);letter-spacing:.04em;flex:none}
.quiz-enonce{
  font-family:'Fredoka';font-size:1.18rem;font-weight:500;line-height:1.35;
  color:var(--encre);margin-bottom:16px;
}
.quiz-reponse{display:flex;flex-direction:column;gap:8px}

/* ---- QCM et mot a designer : la meme cible de 48 px ----
   48 et non 44 : on tape ici plusieurs fois de suite, souvent vite,
   et le plancher du projet est un minimum, pas une cible. */
.quiz-choix, .quiz-mot, .quiz-etiquette{
  min-height:48px;padding:10px 14px;border-radius:var(--r-m);
  background:var(--papier);color:var(--encre);
  font-size:1rem;line-height:1.3;text-align:left;
  box-shadow:var(--rebord), var(--arete), var(--ombre-s);
  transition:transform .12s var(--doux), box-shadow .18s ease;
}
.quiz-choix.pris, .quiz-mot.pris, .quiz-etiquette.pris{
  background:var(--saison);color:#fff;
  box-shadow:var(--ombre-m);transform:translateY(-1px);
}
.quiz-choix:active, .quiz-mot:active, .quiz-etiquette:active{transform:scale(.98)}

/* La phrase se lit en ligne, les mots s'enroulent. Le mot touche est
   un mot entier, ponctuation comprise : c'est ce que le module
   decoupe, et ce que le fichier de donnees designe par son index. */
.quiz-mots{flex-direction:row;flex-wrap:wrap;gap:7px;align-items:flex-start}
/* `min-width` autant que `min-height` : une etiquette porte la
   hauteur de 48 px depuis la 4.0.0, mais « le » ne faisait que 37 px
   de LARGE - sous le plancher de 44 du projet, dans la seule
   dimension qui manquait. Mesure faite en 5.0.0 sur « le chat dort »,
   la phrase du quiz de CP, ou tous les mots sont courts par
   construction. Les phrases des autres niveaux ne bougent pas : elles
   s'enroulent deja, et seuls leurs mots de deux lettres grandissent.
   Le texte reste CENTRE dans l'etiquette elargie, sinon un mot court
   se collerait a gauche d'une cible deux fois plus large que lui. */
.quiz-mot{flex:none;padding:10px 12px;min-width:48px;text-align:center}

/* L'ordre : on touche dans l'ordre voulu, un numero se pose. */
.quiz-etiquette{display:flex;align-items:center;gap:11px}
.quiz-numero{
  flex:none;width:26px;height:26px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-family:'Fredoka';font-size:.95rem;font-weight:600;
  background:color-mix(in srgb, var(--gris) 18%, transparent);color:var(--gris);
}
.quiz-etiquette.pris .quiz-numero{background:rgba(255,255,255,.28);color:#fff}

.quiz-saisie input{
  width:100%;min-height:54px;font-size:1.15rem;text-align:center;
  font-family:'Fredoka';font-weight:500;
}

/* ============================================================
   Les trois reponses tactiles du CP (5.0.0)
   ------------------------------------------------------------
   Une figure a toucher, une grande lettre, un grand nombre. Trois
   regles les gouvernent, et chacune vient d'une contrainte reelle :

   1. LA CIBLE EST UN CARRE, PAS UNE LIGNE. Les quatre reponses des
      autres niveaux sont des lignes empilees, parce qu'elles
      portent du texte. Ici la reponse tient en un signe : en
      colonne elle laisserait 90 % de la largeur vide, et le doigt
      d'un enfant de six ans vise mieux un carre qu'une bande.
   2. TROIS PAR RANGEE AU PLUS. A quatre, le pave tombe a 78 px sur
      un iPhone SE. Les questions du CP en portent trois ou quatre ;
      la quatrieme passe donc a la ligne, et c'est voulu.
   3. LE CHIFFRE EST ENORME, LE MOT L'EST MOINS. `min()` sur la
      largeur du conteneur : « 7 » s'affiche a 2,6 rem, « 50 cm »
      se reduit tout seul au lieu de deborder. Sans cela, les
      etiquettes de la question des longueurs sortaient du cadre.
   ============================================================ */
.quiz-formes, .quiz-lettres, .quiz-nombres{
  flex-direction:row;flex-wrap:wrap;justify-content:center;gap:10px;
}
.quiz-forme, .quiz-pave{
  flex:1 1 0;min-width:88px;max-width:150px;
  display:flex;align-items:center;justify-content:center;
  border-radius:var(--r-m);background:var(--papier);color:var(--encre);
  box-shadow:var(--rebord), var(--arete), var(--ombre-s);
  transition:transform .12s var(--doux), box-shadow .18s ease;
}
.quiz-forme{aspect-ratio:1;padding:10px}
.quiz-pave{
  min-height:88px;padding:8px 10px;
  font-family:'Fredoka';font-weight:600;line-height:1.1;text-align:center;
  font-size:clamp(1.3rem, 8cqw, 2.6rem);
}
.quiz-reponse{container-type:inline-size}
.quiz-forme.pris, .quiz-pave.pris{
  background:var(--saison);color:#fff;
  box-shadow:var(--ombre-m);transform:translateY(-1px);
}
.quiz-forme:active, .quiz-pave:active{transform:scale(.97)}
/* La figure prise passe en blanc sur la teinte de saison : sans
   cette surcharge, le dessin garderait ses couleurs de saison sur
   un fond de saison, et la selection ne se verrait pas. */
.quiz-forme.pris .quiz-figure g{
  fill:rgba(255,255,255,.3);stroke:#fff;
}
.quiz-figure{width:100%;height:100%;display:block}

/* La collection a compter. Elle vit dans la carte, au-dessus de la
   zone de reponse : un objet de 26 px, vingt au plus, sur deux
   rangees s'il le faut. Centree, parce qu'on compte mieux une
   collection rangee qu'un tas. */
.quiz-collection{
  display:flex;flex-wrap:wrap;justify-content:center;gap:7px;
  margin:0 0 16px;padding:12px 10px;border-radius:var(--r-m);
  background:color-mix(in srgb, var(--saison) 9%, transparent);
}
.quiz-objet{width:26px;height:26px;flex:none}

/* ---- le pied ----
   Deux boutons cote a cote, dont un rond de 48 px pour revenir. Le
   principal prend tout le reste : c'est lui qu'on cherche du doigt
   dix fois de suite. */
.quiz-pied{display:flex;align-items:center;gap:10px;flex:none}
.quiz-pied .bouton{flex:1;margin:0}
.quiz-retour{
  flex:none;width:48px;height:48px;border-radius:50%;
  font-size:1.6rem;line-height:1;color:var(--gris);
  background:var(--papier);box-shadow:var(--rebord), var(--arete), var(--ombre-s);
}
.quiz-retour[disabled]{opacity:.35}
.quiz-pied .bouton[disabled]{opacity:.45}
.quiz-pied--bilan{flex-direction:column;align-items:stretch;gap:8px}

/* ---- le bilan ----
   Un temps, un nombre de questions a revoir, et lesquelles. AUCUNE
   note, aucun « 8 sur 10 » : une note se compare, d'un enfant a
   l'autre comme d'une fois a l'autre, et c'est exactement ce que le
   carnet ne fait nulle part. « Deux questions a revoir » dit la meme
   chose et propose quelque chose a faire. */
.quiz-bilan{
  background:var(--papier);border-radius:var(--r-l);
  padding:22px 18px;box-shadow:var(--rebord), var(--arete), var(--ombre-m);
  text-align:center;animation:pop .3s var(--doux);
}
.quiz-bilan-titre{
  font-family:'Fredoka';font-size:1.6rem;font-weight:600;line-height:1.1;
  color:var(--saison-encre);
}
.quiz-bilan-temps{
  font-size:.78rem;font-weight:800;text-transform:none;letter-spacing:0;
  color:var(--gris);margin-top:6px;
}
.quiz-bilan-compte{font-size:1rem;color:var(--encre-douce);margin-top:12px}
.quiz-revoir{list-style:none;margin-top:18px;text-align:left}
.quiz-revoir li{
  margin-bottom:14px;
}
.quiz-revoir li:last-child{margin-bottom:0}
.quiz-revoir-matiere{
  display:block;font-size:.64rem;font-weight:800;text-transform:none;
  letter-spacing:0;color:var(--gris);margin-bottom:3px;
}
.quiz-revoir b{display:block;font-size:.95rem;line-height:1.35;color:var(--encre)}
/* Ce qui a ete repondu est gris et discret ; la bonne reponse est en
   teinte de saison. Aucune des deux n'est ROUGE - le carnet ne
   dessine jamais le manque, y compris quand il corrige. */
.quiz-revoir-tien{display:block;font-size:.85rem;color:var(--gris);margin-top:4px}
.quiz-revoir-vraie{
  display:block;font-size:.88rem;font-weight:700;color:var(--saison-encre);
  margin-top:2px;
}

/* Sur un iPhone court, l'enonce et les reponses passent avant le
   decor : meme seuil que partout ailleurs dans le projet. */
@media (max-height:700px){
  .quiz-carte{padding:15px 14px}
  .quiz-enonce{font-size:1.06rem;margin-bottom:12px}
  .quiz-choix, .quiz-mot, .quiz-etiquette{min-height:44px;padding:8px 12px}
  .quiz-saisie input{min-height:48px}
  /* Le carre du CP cede de la hauteur, jamais sa largeur : c'est la
     LARGEUR qui fait la cible du doigt sur ces trois zones, et une
     figure plus etroite serait plus dure a viser qu'une plus basse. */
  .quiz-forme{aspect-ratio:1.25}
  .quiz-pave{min-height:72px;font-size:clamp(1.2rem, 7.2cqw, 2.2rem)}
  .quiz-collection{padding:9px 8px;gap:6px;margin-bottom:12px}
  .quiz-objet{width:23px;height:23px}
  .quiz-bilan{padding:16px 14px}
  .quiz-bilan-titre{font-size:1.35rem}
}

/* ------------------------------------------------------------
   Le bloc des quiz, sur l'ecran Bonus (4.0.0)
   ------------------------------------------------------------
   La meme boite que « Les jeux », en bleu d'Hiver plutot qu'en vert :
   deux pavés de la même couleur l'un sous l'autre se liraient comme
   un seul bloc coupé en deux, et ce n'est pas la même chose qu'on y
   fait. Le violet est pris par la pioche, qui reste l'action de
   l'écran.

   Deux colonnes et non quatre : à quatre, chaque bouton fait 76 px
   de large sur un iPhone ordinaire, et « Printemps » n'y tient pas
   sans se couper en deux. À deux, les quatre saisons gardent leur
   nom entier sur une ligne.
   ------------------------------------------------------------ */
.quiz-bloc{
  background:linear-gradient(135deg,var(--hiver),#3E9BC4);
  color:#fff;border-radius:var(--r-l);padding:24px 20px;text-align:center;
  margin-bottom:22px;box-shadow:var(--ombre-m);
}
.quiz-bloc h3{font-size:1.3rem;margin-bottom:6px}
.quiz-bloc p{font-size:.92rem;opacity:.92;margin-bottom:16px;line-height:1.45}
.quiz-saisons{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
.quiz-saisons .bouton{
  background:#fff;color:var(--t-encre, var(--hiver-encre));
  flex-direction:column;gap:3px;min-height:68px;padding:9px 6px;
  font-size:.9rem;font-weight:600;line-height:1.15;white-space:normal;width:100%;
}
/* « déjà fait » ne dit pas « c'est gagné » : il dit qu'un autre jeu
   de questions sortira la prochaine fois. D'où le gris, et pas une
   coche ni une teinte de réussite. */
.quiz-deja{
  font-size:.64rem;font-weight:800;text-transform:none;letter-spacing:0;
  color:var(--gris);
}

/* ============================================================
   Ecran bonus : un resserrement CONTINU (4.2.0)
   ------------------------------------------------------------
   MESURE D'ABORD, parce que c'est elle qui a decide de tout. Le
   contenu de cet ecran fait 1317 px sur 390 x 844, pour 703 px de
   zone visible. Ce qu'on cherche a faire tenir n'est PAS tout cela -
   la liste des quatre familles ne rentre nulle part - mais le bas du
   bloc des quiz, qui n'apparaissait qu'aux quatre cinquiemes cache.

   UN CURSEUR, ET NON DES CRANS. La 4.1.0 avait deux paliers, la
   premiere version de la 4.2.0 en a eu trois, et les deux se
   heurtaient au meme mur : entre deux paliers il y a un CREUX.
   Mesure sur 390 x 844 : le palier 2 manquait la cible de 42 px, donc
   le palier 3 s'appliquait et laissait 49 px de vide sous les quiz.
   Sur 430 x 932, le vide etait de 168 px - « c'est trop condense, il
   reste de la place en dessous de Teste tes connaissances », signale
   par Xavier sur un iPhone 16 Pro Max.

   Tout est donc interpole sur UNE variable, `--c`, de 0 (la taille
   pleine, celle d'avant) a 1 (le resserrement maximal). ui/bonus.js
   la calcule par la mesure et pose la plus PETITE valeur qui fait
   tenir le bloc des quiz : sur un grand telephone elle vaut zero et
   rien ne change, sur un SE elle vaut un.

   Ce qui NE change a aucune valeur de `--c` :
   - la pioche reste la plus haute des trois et garde son bouton
     pleine largeur : c'est la seule action de l'ecran, la
     hierarchie ne se resserre pas ;
   - aucune cible tactile ne descend sous 48 px, meme a `--c: 1` -
     c'est ce qui fixe l'autre bout du curseur, et c'est pour cela
     qu'il ne va pas plus loin ;
   - aucun texte ne disparait. Un ecran qui tient en cachant ce
     qu'il doit dire n'a pas tenu.
   ============================================================ */
.bonus-ajuste{--c:0}

.bonus-ajuste .pioche,
.bonus-ajuste .jeu-bloc{
  padding:calc(30px - var(--c) * 16px) calc(22px - var(--c) * 8px);
  margin-bottom:calc(22px - var(--c) * 12px);
}
.bonus-ajuste .quiz-bloc{
  padding:calc(24px - var(--c) * 10px) calc(20px - var(--c) * 6px);
  margin-bottom:calc(22px - var(--c) * 12px);
}
.bonus-ajuste .pioche h3,
.bonus-ajuste .jeu-bloc h3{
  font-size:calc(1.35rem - var(--c) * .29rem);
  margin-bottom:calc(16px - var(--c) * 8px);
}
.bonus-ajuste .quiz-bloc h3{
  font-size:calc(1.3rem - var(--c) * .24rem);
  margin-bottom:calc(6px - var(--c) * 3px);
}
.bonus-ajuste .pioche p,
.bonus-ajuste .jeu-bloc p{
  font-size:calc(.95rem - var(--c) * .15rem);
  margin-bottom:calc(22px - var(--c) * 14px);
  line-height:calc(1.5 - var(--c) * .18);
}
.bonus-ajuste .quiz-bloc p{
  font-size:calc(.92rem - var(--c) * .12rem);
  margin-bottom:calc(16px - var(--c) * 8px);
  line-height:calc(1.45 - var(--c) * .13);
}
.bonus-ajuste .pioche .bouton{
  min-height:calc(58px - var(--c) * 10px);
  font-size:calc(1.1rem - var(--c) * .14rem);
}
.bonus-ajuste .jeu-boutons .bouton{
  min-height:calc(72px - var(--c) * 18px);
  font-size:calc(.82rem - var(--c) * .09rem);
  padding:calc(10px - var(--c) * 5px) 4px;
  gap:calc(4px - var(--c) * 2px);
}
.bonus-ajuste .quiz-saisons .bouton{
  min-height:calc(68px - var(--c) * 20px);
  font-size:calc(.9rem - var(--c) * .1rem);
  padding:calc(9px - var(--c) * 4px) calc(6px - var(--c) * 2px);
}
/* La marge de l'accroche etait un style INLINE dans bonus.js, donc
   hors d'atteinte d'une variable : meme piege que la phrase de
   contexte du rituel du soir, note dans « Mise en page ». Elle est
   passee ici. */
.bonus-ajuste .bonus-intro p{
  color:var(--gris);
  margin:calc(6px - var(--c) * 4px) 0 calc(20px - var(--c) * 12px);
}
/* Depuis la 7.2.0 l'intro n'a plus de phrase sous le titre : c'est le
   titre qui porte l'ecart avec la pioche, dans les deux modes. */
.bonus-intro h1{margin-bottom:16px}
.bonus-ajuste .bonus-intro h1{margin-bottom:calc(16px - var(--c) * 8px)}

/* La liste de la reserve passe sur DEUX colonnes quand le curseur
   est au bout : a ce moment-la l'ecran est un SE, et quatre volets
   fermes l'un sous l'autre y coutent 268 px pour quatre lignes de
   texte. Elle n'entre pas dans le calcul du curseur - c'est une
   liste, elle a le droit de defiler - mais autant qu'elle en montre
   deux fois plus. */
.bonus--reserve-serree .reserve-liste{
  display:grid;grid-template-columns:1fr 1fr;gap:8px;align-items:stretch;
}
.bonus--reserve-serree .reserve-liste > h3{grid-column:1/-1;margin:8px 0 2px 4px}
.bonus--reserve-serree .reserve-liste > details{margin-bottom:0}
/* Un volet ouvert reprend la pleine largeur : ses defis sont des
   phrases, et une phrase dans une colonne de 180 px se lit en
   colonne de journal. */
.bonus--reserve-serree .reserve-liste > details[open]{grid-column:1/-1}
/* Le chevron est en position absolue a droite du summary : en
   colonne etroite, un titre de deux lignes passait DESSOUS - mesure a
   l'ecran, « Confiance et tete bien faite » et « Francais et langue »
   etaient tous les deux mordus. Le padding droit lui reserve sa
   place, et `stretch` donne aux deux volets d'une meme rangee la
   meme hauteur : sans lui, une rangee d'un titre court et d'un titre
   long se lisait comme un defaut d'alignement. */
.bonus--reserve-serree .reserve-liste > details > summary{
  min-height:48px;padding:8px 34px 8px 22px;
}
.bonus--reserve-serree .reserve-liste > details > summary span{font-size:.95rem}
.bonus--reserve-serree .reserve-liste > details > summary small{font-size:.76rem}
.bonus--reserve-serree .reserve-liste > details > summary::after{right:12px}
