@import url('./cahier.css');

/* ==========================================================================
   App'Ianaro — socle visuel
   --------------------------------------------------------------------------
   Source unique du style pour le portail et l'espace Jeux. Les deux pages
   portaient jusqu'ici deux copies du même CSS, déjà divergentes de quelques
   pixels. Une seule feuille, servie avec `Cache-Control: no-cache` comme tout
   le reste du code (voir firebase.json) : une correction est visible au
   rechargement.

   PARTI PRIS — « shadcn, en couleurs ».
   La grammaire est celle de shadcn/ui : neutres zinc, surfaces blanches,
   traits d'un pixel, rayons généreux, anneau de focus visible, ombres presque
   absentes au repos. Ce qui s'y ajoute : SIX ACCENTS au lieu d'un seul, et un
   peu de mouvement. Chaque carte porte sa propre couleur dans `--a` ; tout ce
   qui doit s'y accorder — liseré, sceau, étiquette, bouton, halo — la lit.
   Une carte ne connaît donc jamais sa couleur, elle l'hérite.

   POURQUOI PAS DE POLICE WEB. Le public visé est à Madagascar, où la connexion
   se paie au mégaoctet (§ 2 du cadrage). Quatre-vingt-dix kilo-octets de
   fontes pour un portail qui tient en trente, c'est un tiers du chargement
   dépensé en dessin de lettres. Le dynamisme vient d'ailleurs : couleur,
   rythme, mouvement.

   POURQUOI SI PEU D'ANIMATIONS DE FOND. Un dégradé animé ou un flou en
   mouvement repeint l'écran soixante fois par seconde — sur les machines de
   cybercafé auxquelles ce site s'adresse, cela se voit. Le lavis coloré du
   haut de page est donc FIXE, et le budget d'animation est dépensé là où il
   se remarque : l'entrée des cartes, le survol, le clic. Toutes ces
   animations ne touchent que `transform` et `opacity`, les deux seules
   propriétés que le navigateur sait animer sans recalculer la page.

   ACCESSIBILITÉ. `prefers-reduced-motion` coupe tout mouvement en fin de
   fichier — ce n'est pas une option, c'est un réglage système que des gens
   activent parce que le mouvement leur donne la nausée. Les anneaux de focus
   ne sont jamais supprimés, seulement redessinés.

   COMPATIBILITÉ. `color-mix()` sert à teinter (fonds pâles, halos). Il est
   toujours écrit APRÈS une valeur neutre qui tient lieu de repli : un
   navigateur qui ne le connaît pas ignore la seconde déclaration et garde la
   première. La page perd ses teintes pâles, jamais sa lisibilité.
   ========================================================================== */

/* ---------- 1. Jetons ---------------------------------------------------- */

:root {
  /* Neutres — échelle zinc. Le fond n'est pas blanc : une carte blanche sur
     fond blanc n'existe pas, il faudrait la cerner d'un trait plus sombre. */
  --fond:      #FAFAFA;
  --carte:     #FFFFFF;
  --carte-2:   #F4F4F5;
  --encre:     #18181B;
  --encre-2:   #52525B;
  --encre-3:   #A1A1AA;
  --trait:     #E4E4E7;
  --trait-2:   #F1F1F3;
  --entete:    #FFFFFF;
  --surface-mix: #FFFFFF;
  --filtre-icone-theme: none;

  /* Les six accents. Un ordre, pas une hiérarchie : `teinte()` dans
     commun/presentation.js y puise par hachage du nom, si bien qu'un module
     ajouté demain reçoit sa couleur sans que personne ne la choisisse. */
  --c1: #6366F1;   /* indigo   */
  --c2: #06B6D4;   /* cyan     */
  --c3: #10B981;   /* émeraude */
  --c4: #F43F5E;   /* rose     */
  --c5: #F59E0B;   /* ambre    */
  --c6: #8B5CF6;   /* violet   */
  --ecole-texte: #7A5A00;

  /* Accent par défaut d'un élément qui n'en hérite d'aucun. */
  --a: var(--c1);

  --alerte:        #B91C1C;
  --alerte-fond:   #FEF2F2;
  --alerte-trait:  #FECACA;

  --r-xs:  6px;
  --r-sm:  8px;
  --r:     12px;
  --r-lg:  18px;
  --pilule: 999px;

  /* ---------- L'échelle des cartes ----------
     Réduites de 20 % le 11/08/2026 : la première version tenait trois cartes
     sur un écran de bureau là où elle en logeait quatre, et sur iPhone une
     seule fiche occupait la moitié de la hauteur d'écran.

     La GÉOMÉTRIE seule est divisée par cinq — largeur de colonne, marges
     intérieures, sceaux, gouttières. Les CORPS DE TEXTE ne suivent pas la même
     pente : la description passerait de 14 à 11,2 px, ce qui n'est plus un
     paragraphe mais une mention légale. Les titres et les libellés perdent
     donc une dizaine de pour cent, pas vingt. Le rapport hauteur/largeur des
     couvertures, lui, ne bouge pas — c'est du 16/9 avant comme après. */
  --col: 218px;      /* largeur minimale d'une colonne : 272 px × 0,8 */
  --gouttiere: .92rem;
  --pad-carte: .84rem;

  /* Trois niveaux, et le premier est presque invisible : au repos une carte
     est posée, pas soulevée. Le relief est réservé au survol, sinon il ne
     signifie plus rien. */
  --ombre-1: 0 1px 2px rgba(24,24,27,.05);
  --ombre-2: 0 1px 3px rgba(24,24,27,.07), 0 8px 24px -14px rgba(24,24,27,.20);
  --ombre-3: 0 2px 6px rgba(24,24,27,.06), 0 20px 42px -20px rgba(24,24,27,.30);

  /* Deux courbes. `--doux` pour ce qui se déplace, `--ressort` pour ce qu'on
     touche : un bouton qui dépasse légèrement sa cible avant de s'y poser se
     sent pressé, et c'est exactement l'impression recherchée. */
  --doux:    cubic-bezier(.22,.61,.36,1);
  --ressort: cubic-bezier(.34,1.36,.5,1);
  --t:  .22s;
  --t2: .42s;

  --largeur: 1080px;
}

/* Le choix explicite de l'utilisateur est posé par commun/theme.js avant le
   chargement de cette feuille. Les pages qui n'exécutent pas JavaScript
   gardent malgré tout un rendu lisible grâce au mode du système. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --fond:      #07111F;
  --carte:     #0D1A2A;
  --carte-2:   #122238;
  --encre:     #F8FAFC;
  --encre-2:   #C2CCDA;
  --encre-3:   #8291A6;
  --trait:     #26384D;
  --trait-2:   #192A3E;
  --entete:    #091525;
  --surface-mix: #0D1A2A;
  --filtre-icone-theme: invert(1);
  --ecole-texte: #F2C34B;

  --alerte:        #FCA5A5;
  --alerte-fond:   #35131A;
  --alerte-trait:  #7F1D2D;

  --ombre-1: 0 1px 2px rgba(0,0,0,.24);
  --ombre-2: 0 2px 5px rgba(0,0,0,.28), 0 12px 30px -18px rgba(0,0,0,.72);
  --ombre-3: 0 4px 10px rgba(0,0,0,.32), 0 24px 48px -22px rgba(0,0,0,.82);
}

/* ---------- 2. Base ------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  color: var(--encre);
  background: var(--fond);
  font: 16px/1.65 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Le lavis. Trois taches radiales très pâles, FIXES — voir l'en-tête du
   fichier. Elles n'existent que pour que le haut de page ne soit pas gris. */
body::before {
  content: '';
  position: fixed;
  inset: 0 0 auto;
  height: 460px;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(680px 300px at 12% -8%,  rgba(99,102,241,.16), transparent 62%),
    radial-gradient(600px 280px at 88%  0%,  rgba(6,182,212,.14),  transparent 60%),
    radial-gradient(520px 260px at 52% -14%, rgba(245,158,11,.12), transparent 64%);
}

:root[data-theme="dark"] body::before {
  background:
    radial-gradient(680px 300px at 12% -8%,  rgba(99,102,241,.18), transparent 62%),
    radial-gradient(600px 280px at 88%  0%,  rgba(6,182,212,.12),  transparent 60%),
    radial-gradient(520px 260px at 52% -14%, rgba(245,158,11,.08), transparent 64%);
}

:root[data-theme="dark"] .marque .logo {
  filter: brightness(0) invert(1);
  opacity: .96;
}

a { color: var(--a); text-decoration-thickness: 1px; text-underline-offset: 2px; }

h1, h2, h3 { letter-spacing: -.022em; }

/* Un seul anneau de focus pour tout le site, à l'accent de l'élément. Il
   n'est jamais retiré : c'est le seul repère de qui navigue au clavier. */
:focus-visible {
  outline: 2px solid var(--a);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* ---------- 3. Gabarit de page ------------------------------------------- */
/* Ces règles étaient écrites à l'identique dans le portail et dans l'espace
   Jeux. Deux copies se surveillent, trois divergent — et il fallait déjà les
   corriger toutes les deux pour un seul réglage de marge sur mobile. */

main { max-width: var(--largeur); margin: 0 auto; padding: 0 1.25rem 5rem; }

.accroche { padding: 3rem 0 1.9rem; max-width: 40rem; }

.oeil {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--encre-2); background: var(--carte);
  border: 1px solid var(--trait); border-radius: var(--pilule);
  padding: .26rem .68rem; box-shadow: var(--ombre-1);
  animation: entree .5s var(--doux) backwards;
}

/* `clamp` avec une borne basse en vw : sur les 390 px de l'iPhone 12 Pro le
   titre retombe à 28 px, ce qui tient sur deux lignes au lieu de trois. */
.accroche h1 {
  font-size: clamp(1.72rem, 7.2vw, 2.55rem);
  line-height: 1.12;
  margin: .8rem 0 .6rem;
  letter-spacing: -.035em;
  animation: entree .5s var(--doux) 70ms backwards;
}
/* Le mot en couleur. UNE COULEUR PLEINE, PAS UN DÉGRADÉ SUR TEXTE.
   `background-clip: text` a été retiré le 11/08/2026 : la technique repose sur
   `-webkit-text-fill-color: transparent`, et partout où le découpage ne prend
   pas — moteur ancien, rendu accéléré capricieux, capture d'écran, mode
   contraste élevé — il ne reste que le rectangle du dégradé, texte invisible
   par-dessus. Un titre illisible est un prix trop élevé pour un effet.
   Chaque page choisit sa couleur ; elle porte le mot, elle ne le remplace pas. */
.accroche h1 em { font-style: normal; color: var(--c1); }
.accroche p {
  color: var(--encre-2); margin: 0; font-size: .96rem; max-width: 34rem;
  animation: entree .5s var(--doux) 130ms backwards;
}

.vide {
  grid-column: 1 / -1; text-align: center; color: var(--encre-2);
  padding: 2.6rem 1rem; border: 1px dashed var(--trait); border-radius: var(--r);
}

/* ---------- 4. En-tête --------------------------------------------------- */

.entete {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--entete);
  border-bottom: 1px solid var(--trait);
  transition: box-shadow var(--t) var(--doux), border-color var(--t) linear;
}
/* Posée par le script au premier défilement : tant que la page est en haut,
   l'en-tête ne doit pas se distinguer du fond. */
.entete.detachee { box-shadow: var(--ombre-2); border-color: var(--trait-2); }

.bandeau {
  max-width: var(--largeur);
  margin: 0 auto;
  padding: .7rem 1.25rem;
  display: flex;
  align-items: center;
  gap: .9rem;
}

.marque {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  margin-right: auto;
  text-decoration: none;
  color: var(--encre);
  font-size: 1.06rem;
  font-weight: 700;
  letter-spacing: -.03em;
}
/* ⚠️ `.marque .sceau` A ÉTÉ RETIRÉ LE 18/08/2026 — AVEC SON HOVER ET SES DEUX
   VARIANTES RESPONSIVES. La marque était composée en CSS faute de logo : un
   carré dégradé portant une lettre. Le vrai logo est arrivé, et ces règles ne
   visaient plus rien. Les garder aurait coûté à la lecture — on cherche
   longtemps où sert une règle qui ne sert plus, c'est la même raison qui a
   fait retirer deux imports morts de portail/index.html.
   `.sceau-module`, plus bas, est une AUTRE classe et reste employée par le
   catalogue et l'espace Jeux : ne pas la confondre. */

/* ---------- Le vrai logo, à la place du sceau dessiné ----------
   AJOUTÉ LE 18/08/2026. La marque était composée en CSS — un carré dégradé
   portant une lettre, puis le nom en texte. C'était un substitut en attendant
   le logo ; il est arrivé.

   ⚠️ `width` ET `height` SONT ÉCRITS DANS LE HTML, PAS SEULEMENT ICI.
   Sans eux, le navigateur ne connaît pas les proportions avant d'avoir
   téléchargé l'image, réserve zéro pixel, et toute la page saute quand elle
   arrive. C'est ce décalage — plus que la lenteur — qui donne l'impression
   d'un site mal fait. Même raison que pour les emblèmes du catalogue.

   Le fichier fait 197 × 52 pour un affichage à 26 px de haut : le double, pour
   les écrans à forte densité. 3,3 Ko, contre 1,0 Mo pour l'original — voir
   outils/preparer-logo.py, qui le refabrique. */
.marque .logo {
  height: 26px; width: auto; display: block;
  transition: transform var(--t2) var(--ressort);
}
.marque:hover .logo { transform: scale(1.04); }
.marque .suite { color: var(--encre-3); font-weight: 600; }

/* Contrastes des pages secondaires uniquement. Le portail d'aiguillage
   conserve strictement ses jetons, couleurs et composants actuels. */
:root[data-theme="light"] body:not(.page-aiguillage) {
  --encre-3: #64748b;
  --c1: #4f46e5;
  --a: var(--c1);
}
:root[data-theme="light"] body:not(.page-aiguillage) .etiquette:not(.neutre) {
  color: color-mix(in srgb, var(--a) 60%, #000);
}
:root[data-theme="light"] body:not(.page-aiguillage) .bouton.inerte {
  opacity: 1; color: var(--encre-2); background: var(--carte-2);
}

/* ---------- Dans un module : la marque seule, carrée ----------
   AJOUTÉ LE 03/09/2026. Sur le portail, le logotype entier est seul en tête de
   barre et il y est à sa place. Dans un module, il partage la ligne avec le
   nom du cours, le retour au portail, la langue et le compte : à 197 pixels de
   large, il prenait à lui seul le tiers de la barre sur un portable, et le nom
   du cours passait à la ligne.

   La marque seule fait 57 pixels de large pour la même hauteur — un quart de
   la place. On peut donc la monter un peu : à 26 px un carré paraît petit là
   où un mot de 197 px paraissait juste. Les deux fichiers sortent de la même
   commande, outils/preparer-logo.py.

   ⚠️ CETTE CLASSE NE S'AJOUTE QU'AVEC logo-appianaro-mini.webp. Posée sur une
   page qui sert encore le logotype entier, elle l'étirerait à 32 px de haut,
   soit 121 px de large : l'inverse de ce qu'on cherche. */
.marque.mini .logo { height: 32px; }

.nav-liens { display: flex; gap: .15rem; }
.nav-liens a {
  --a: var(--c1);
  position: relative;
  padding: .38rem .7rem;
  border-radius: var(--r-sm);
  font-size: .88rem; font-weight: 600;
  color: var(--encre-2); text-decoration: none;
  transition: color var(--t) linear, background-color var(--t) linear;
}
.nav-liens a:hover { color: var(--encre); background: var(--carte-2); }
.nav-liens a[aria-current="page"] { color: var(--encre); }
.nav-liens a[aria-current="page"]::after {
  content: ''; position: absolute; left: .7rem; right: .7rem; bottom: .1rem;
  height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, var(--c1), var(--c4));
}

#session {
  font-size: .82rem; color: var(--encre-2);
  max-width: 15rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 560px) { #session { display: none; } }

/* ---------- 5. Boutons --------------------------------------------------- */

.bouton {
  --a: var(--c1);
  display: inline-flex; align-items: center; gap: .4rem;
  font: inherit; font-size: .8rem; font-weight: 600; line-height: 1.2;
  padding: .44rem .8rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--a);
  background: var(--a);
  color: #fff;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: transform .16s var(--ressort), box-shadow var(--t) var(--doux),
              filter var(--t) linear, background-color var(--t) linear;
}
.bouton:hover { transform: translateY(-1px); filter: saturate(1.12) brightness(1.06); }
/* Le halo reprend la couleur du bouton, très étalé et très bas : ce n'est pas
   une ombre, c'est la couleur qui déteint sur le fond. */
.bouton:hover { box-shadow: 0 10px 22px -10px var(--a); }
.bouton:active { transform: translateY(0) scale(.975); }

.bouton .fl { display: inline-block; transition: transform var(--t) var(--ressort); }
.bouton:hover .fl { transform: translateX(3px); }

.bouton.discret {
  background: var(--carte); color: var(--encre); border-color: var(--trait);
  box-shadow: var(--ombre-1);
}
.bouton.discret:hover {
  background: var(--carte);
  border-color: var(--encre-3);
  box-shadow: var(--ombre-2);
  filter: none;
}

/* Un seul bouton compact, placé par commun/theme.js juste avant le bouton de
   connexion. Les pictogrammes viennent de Feather Icons et restent de vrais
   fichiers image : pas de caractère lune/soleil dépendant de la police. */
.bouton-theme {
  width: 2.25rem;
  height: 2.25rem;
  flex: 0 0 2.25rem;
  justify-content: center;
  padding: 0;
}
.bouton-theme img {
  width: 1.1rem;
  height: 1.1rem;
  display: block;
  filter: var(--filtre-icone-theme);
}

.bouton.fantome {
  background: transparent; color: var(--a); border-color: transparent;
  box-shadow: none;
}
.bouton.fantome:hover {
  background: var(--carte-2);
  background: color-mix(in srgb, var(--a) 9%, transparent);
  box-shadow: none; filter: none;
}

/* ---------- Navigation maîtresse d'un module ----------------------------
   « Toutes les parties » et « Tous les chapitres » ne sont pas des retours
   accessoires : ils ramènent à la carte du cours. Cette classe commune donne
   la même hiérarchie aux modules actuels et sert de convention aux suivants. */
.bouton.navigation-maitresse {
  min-height: 48px;
  padding: .72rem 1.08rem;
  background: var(--a);
  color: #fff;
  border-color: var(--a);
  font-size: .94rem;
  font-weight: 750;
  letter-spacing: -.01em;
  box-shadow: 0 10px 24px -15px var(--a);
}
.bouton.navigation-maitresse:hover {
  background: color-mix(in srgb, var(--a) 88%, #000);
  border-color: color-mix(in srgb, var(--a) 88%, #000);
  color: #fff;
  box-shadow: 0 12px 28px -15px var(--a);
}

/* Un bouton mort fait douter du reste du site — d'où l'aspect franchement
   inerte : pas de curseur main, pas de relief, pas de survol. */
.bouton.inerte {
  background: var(--carte-2); color: var(--encre-3); border-color: var(--trait);
  cursor: default; box-shadow: none;
}
.bouton.inerte:hover { transform: none; box-shadow: none; filter: none; }

.bouton:disabled { opacity: .5; cursor: not-allowed; }
.bouton:disabled:hover { transform: none; box-shadow: none; filter: none; }

.bouton.petit { font-size: .75rem; padding: .32rem .6rem; }
.bouton.grand { font-size: .9rem; padding: .58rem 1.15rem; }

/* ---------- 6. Étiquettes ------------------------------------------------ */

.etiquette {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: .67rem; font-weight: 700; letter-spacing: .02em;
  padding: .16rem .5rem;
  border-radius: var(--pilule);
  white-space: nowrap;
  color: var(--a);
  background: var(--carte-2);
  background: color-mix(in srgb, var(--a) 12%, var(--surface-mix));
  border: 1px solid var(--trait);
  border-color: color-mix(in srgb, var(--a) 26%, var(--surface-mix));
}
.etiquette.neutre {
  color: var(--encre-2); background: var(--carte-2); border-color: var(--trait);
}

/* Le point qui bat. Deux secondes et demie de cycle, une opacité qui varie de
   moitié : assez pour attirer l'œil en périphérie, trop lent pour distraire
   quelqu'un qui lit à côté. */
.pastille {
  width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 0 currentColor;
}

/* ---------- 7. Cartes ---------------------------------------------------- */

.grille {
  display: grid;
  gap: var(--gouttiere);
  grid-template-columns: repeat(auto-fill, minmax(var(--col), 1fr));
  align-items: stretch;
}

/* Respect strict de l'attribut hidden contre les surcharges de spécificité (display: flex) */
[hidden],
.fiche[hidden] {
  display: none !important;
}

.fiche {
  --a: var(--c1);
  position: relative;
  display: flex; flex-direction: column;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--ombre-1);
  transition: transform var(--t) var(--doux), box-shadow var(--t) var(--doux),
              border-color var(--t) linear;
}

/* Le liseré du haut se déploie de la gauche au survol. Il est en `::before`
   plutôt qu'en `border-top` pour pouvoir se dessiner progressivement sans
   décaler d'un pixel ce qu'il y a dessous. */
.fiche::before {
  content: '';
  position: absolute; inset: 0 0 auto; height: 3px; z-index: 2;
  background: linear-gradient(90deg, var(--a), var(--a) 45%, transparent);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--t2) var(--doux);
}
.fiche:hover, .fiche:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--ombre-3);
  border-color: var(--trait);
  border-color: color-mix(in srgb, var(--a) 34%, var(--trait));
}
.fiche:hover::before, .fiche:focus-within::before { transform: scaleX(1); }

.couverture {
  position: relative;
  aspect-ratio: 16/9;
  background: var(--carte-2) center/cover no-repeat;
  border-bottom: 1px solid var(--trait);
  overflow: hidden;
  transition: transform var(--t2) var(--doux);
}
.fiche:hover .couverture { transform: scale(1.035); }

/* Pas d'image ? On en dessine une plutôt que de laisser un trou. Le sceau
   géant en filigrane, la teinte de la carte, une trame de points : la fiche
   reste une fiche, elle n'a pas l'air inachevée. */
.couverture.vide {
  display: grid; place-items: center;
  background:
    radial-gradient(circle at 1px 1px, rgba(24,24,27,.07) 1px, transparent 0) 0 0/13px 13px,
    linear-gradient(135deg, var(--carte-2), var(--carte));
}
.couverture.vide {
  background:
    radial-gradient(circle at 1px 1px, rgba(24,24,27,.07) 1px, transparent 0) 0 0/13px 13px,
    linear-gradient(135deg,
      color-mix(in srgb, var(--a) 17%, var(--surface-mix)),
      color-mix(in srgb, var(--a) 4%, var(--surface-mix)));
}
.couverture.vide span {
  font-size: 2.5rem; font-weight: 800; letter-spacing: -.05em;
  color: var(--encre-3);
  color: color-mix(in srgb, var(--a) 52%, var(--surface-mix));
  user-select: none;
}

.corps {
  display: flex; flex-direction: column; flex: 1;
  padding: var(--pad-carte) var(--pad-carte) calc(var(--pad-carte) + .08rem);
  gap: .36rem;
}
.tete { display: flex; align-items: flex-start; justify-content: space-between; gap: .45rem; }
.fiche h2 { font-size: .95rem; margin: 0; line-height: 1.32; }
.fiche h3 { font-size: .88rem; margin: 0; line-height: 1.32; }
.desc { color: var(--encre-2); font-size: .8rem; line-height: 1.55; margin: 0; flex: 1; }
.meta {
  font-size: .73rem; color: var(--encre-2); line-height: 1.45;
  display: flex; gap: .42rem; flex-wrap: wrap; align-items: center; margin: 0;
}
.meta b { color: var(--encre); font-weight: 600; }

/* `margin-top: auto` colle le pied au bas de la carte. Sans lui, une carte de
   jeu — plus courte qu'une fiche de formation — laisserait son bouton au
   milieu du vide dès qu'une rangée mélange les deux. */
.pied {
  display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; margin-top: auto; padding-top: .64rem;
  border-top: 1px solid var(--trait-2);
  flex-wrap: wrap;
}
.prix { font-weight: 700; font-size: .92rem; letter-spacing: -.02em; }
.prix small { font-weight: 400; color: var(--encre-2); font-size: .72rem; letter-spacing: 0; }

/* ---------- 8. Le sceau d'un module -------------------------------------- */
/* La lettre initiale du titre dans un carré coloré. Elle remplace l'icône que
   personne n'a dessinée, et surtout elle vaut pour un module qui n'existe pas
   encore : rien à choisir, rien à téléverser, rien à oublier. */

.sceau-module {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  border-radius: 10px;
  display: grid; place-items: center;
  font-size: .92rem; font-weight: 800; letter-spacing: -.03em;
  color: #fff;
  background: linear-gradient(140deg, var(--a), var(--a));
  background: linear-gradient(140deg,
    color-mix(in srgb, var(--a) 88%, var(--surface-mix)),
    color-mix(in srgb, var(--a) 78%, #000));
  box-shadow: 0 4px 12px -5px var(--a);
  transition: transform var(--t2) var(--ressort);
  user-select: none;
}
/* Un module qui apporte son emblème : pas de pastille colorée derrière, pas
   d'ombre teintée, pas de rayon — le logo a déjà sa forme et sa couleur, et
   l'enfermer dans un carré indigo reviendrait à le cadrer deux fois.
   `contain` : le visuel ne peut pas être rogné, quoi qu'il mesure. */
.sceau-module.propre {
  background: none;
  box-shadow: none;
  border-radius: 0;
  width: 40px; height: 40px;
}
.sceau-module.propre img { width: 100%; height: 100%; object-fit: contain; display: block; }
.fiche:hover .sceau-module { transform: rotate(-6deg) scale(1.06); }
/* Un logo ne pivote pas : incliner une marque de six degrés au survol, c'est
   amusant sur une lettre, négligé sur le travail d'un graphiste. */
.fiche:hover .sceau-module.propre { transform: scale(1.06); }

/* ---------- 9. Le rang de séparation ------------------------------------- */
/* Ce qui remplace l'ancien pavé vert pleine largeur. Une ligne de titre, pas
   un bloc : les jeux restent dans la grille du catalogue — c'est ce qui les
   fait paraître offerts plutôt qu'annexes — mais le rang dit à quel titre. */

.rang {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: .7rem;
  margin: 1.3rem 0 -.2rem;
  flex-wrap: wrap;
}
.rang h2 {
  font-size: .96rem; margin: 0; letter-spacing: -.01em;
  display: inline-flex; align-items: center; gap: .5rem;
}
.rang .filet {
  flex: 1; height: 1px; min-width: 1.5rem;
  background: linear-gradient(90deg, var(--trait), transparent);
}
.rang .lien-tout {
  --a: var(--c1);
  font-size: .83rem; font-weight: 600; text-decoration: none;
  color: var(--encre-2);
  display: inline-flex; align-items: center; gap: .3rem;
  transition: color var(--t) linear;
}
.rang .lien-tout:hover { color: var(--a); }
.rang .lien-tout .fl { transition: transform var(--t) var(--ressort); }
.rang .lien-tout:hover .fl { transform: translateX(3px); }

/* ---------- 10. Messages -------------------------------------------------- */

.msg {
  padding: .8rem 1rem;
  border-radius: var(--r-sm);
  font-size: .89rem;
  margin: 1.2rem 0;
  border: 1px solid var(--trait);
  background: var(--carte);
  animation: surgir .3s var(--doux) backwards;
}
.msg.err  { background: var(--alerte-fond); border-color: var(--alerte-trait); color: var(--alerte); }
.msg.info {
  --a: var(--c1);
  color: var(--encre);
  background: color-mix(in srgb, var(--a) 8%, var(--surface-mix));
  border-color: color-mix(in srgb, var(--a) 26%, var(--surface-mix));
}
.msg code {
  background: var(--carte-2); padding: .08em .35em; border-radius: 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .92em;
}

/* ---------- 11. Chargement ----------------------------------------------- */

.squelette {
  height: 214px;
  border-radius: var(--r);
  border: 1px solid var(--trait);
  background: linear-gradient(100deg,
    var(--carte-2) 28%, var(--carte) 48%, var(--carte-2) 68%);
  background-size: 220% 100%;
}

/* ---------- 12. Animations d'entrée -------------------------------------- */
/* `backwards` et non `both` : `both` fige la transformation finale sur
   l'élément après coup, et le `translateY` du survol ne s'appliquerait plus.
   Le décalage de chaque carte est posé en ligne par le script (--i). */

@keyframes entree {
  from { opacity: 0; transform: translateY(14px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
@keyframes surgir {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.anime {
  animation: entree .5s var(--doux) backwards;
  animation-delay: calc(var(--i, 0) * 55ms);
}

/* ---------- 12 bis. Le mouvement qui répond ------------------------------ */
/* AJOUTÉ LE 27/09/2026, avec commun/vivant.js qui porte le reste (onde,
   cartes au défilement, réponses, confettis). Ne sont ici que les règles qui
   doivent exister AVANT le premier affichage. */

/* Passer d'une page à l'autre en fondu plutôt que par un écran blanc. Les
   navigateurs qui ne connaissent pas la règle l'ignorent : le changement de
   page reste instantané, comme avant. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .25s; }

/* Sur écran tactile, la carte s'enfonce sous le doigt — l'équivalent du
   survol, qui n'existe pas au téléphone. Réservé à `hover: none` : à la
   souris, le soulèvement du survol ne doit pas se battre avec l'appui. */
@media (hover: none) {
  .fiche:active, .carte-vitrine:active, .carte-choix:active {
    transform: scale(.975); box-shadow: var(--ombre-1); transition-duration: .12s;
  }
}

/* Le reflet qui balaie un squelette de chargement. Il glisse par
   `transform` sur un calque, sans repeindre le dégradé de fond : même
   règle que le reste du fichier. */
.squelette { position: relative; overflow: hidden; }
.squelette::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.35) 50%, transparent 70%);
  transform: translateX(-100%);
  animation: balaye 1.3s linear infinite;
}
:root[data-theme="dark"] .squelette::after {
  background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.06) 50%, transparent 70%);
}
@keyframes balaye { to { transform: translateX(100%); } }

/* ---------- 13. Pied ----------------------------------------------------- */

.pied-page {
  border-top: 1px solid var(--trait);
  color: var(--encre-2);
  font-size: .82rem;
  background: var(--carte);
}
.pied-page > div {
  max-width: var(--largeur);
  margin: 0 auto;
  padding: 1.4rem 1.25rem 3rem;
  display: flex; gap: .8rem; align-items: center; flex-wrap: wrap;
}
.pied-page .filet-couleur {
  flex: 1; min-width: 2rem; height: 3px; border-radius: 3px;
  background: linear-gradient(90deg, var(--c1), var(--c2), var(--c3), var(--c5), var(--c4), var(--c6));
  opacity: .55;
}
/* Numéro de contact d'App'Ianaro (20/10/2026). Le même numéro est écrit en dur
   dans chaque pied de page public et dans les messages « appelez-nous » :
   s'il change, chercher « 324278942 » dans tout le dossier. */
.pied-contact {
  color: inherit; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.pied-contact::before { content: "📞 "; }
.pied-contact:hover, .pied-contact:focus-visible { color: var(--encre); text-decoration: underline; }

/* ---------- 14. Écrans tactiles ------------------------------------------ */
/* `:hover` sur un écran tactile ne veut pas dire « le doigt passe dessus »,
   il veut dire « le doigt a touché ici en dernier ». La carte reste donc
   soulevée après le retour en arrière, le bouton reste allumé, et la page a
   l'air cassée. On rend l'état au repos et on le remplace par `:active`, qui
   dure exactement le temps de l'appui — le seul retour tactile qui ait du
   sens. `:focus-within` n'est pas touché : il sert au clavier. */

@media (hover: none) {
  .fiche:hover { transform: none; box-shadow: var(--ombre-1); border-color: var(--trait); }
  .fiche:hover::before { transform: scaleX(0); }
  .fiche:hover .couverture,
  .fiche:hover .sceau-module,
  .fiche:active { transform: scale(.99); }

  .bouton:hover { transform: none; filter: none; }
  .bouton:hover:not(.discret) { box-shadow: none; }
  .bouton.discret:hover { box-shadow: var(--ombre-1); border-color: var(--trait); }
  .bouton:hover .fl, .rang .lien-tout:hover .fl { transform: none; }
  .nav-liens a:hover { background: transparent; color: var(--encre-2); }
  .nav-liens a[aria-current="page"] { color: var(--encre); }
}

/* ---------- 15. Petits écrans -------------------------------------------- */
/* Référence de mise au point : iPhone 12 Pro, 390 × 844 points. C'est le
   format le plus étroit qu'on rencontre encore couramment, et celui sur lequel
   la première version se tenait le plus mal : l'en-tête débordait — marque,
   deux onglets et le bouton de compte sur une seule ligne demandent 470 px —
   et une fiche unique remplissait la moitié de la hauteur.

   Le point de bascule est à 640 px et non à 390 : entre les deux se trouvent
   les téléphones en paysage, les petites tablettes et les fenêtres réduites,
   qui souffrent du même défaut. */

@media (max-width: 640px) {
  main { padding: 0 1rem 3.5rem; }

  /* L'en-tête passe sur deux lignes : marque et compte en haut, navigation en
     dessous, en interrupteur segmenté pleine largeur. C'est plus haut de
     34 px, mais rien n'est tronqué et les deux onglets deviennent des cibles
     tactiles franches au lieu de deux mots collés. */
  .bandeau { flex-wrap: wrap; padding: .6rem 1rem; row-gap: .5rem; column-gap: .55rem; }
  .marque { font-size: 1rem; }
  .marque .logo { height: 24px; }
  .marque.mini .logo { height: 28px; }

  /* Les modules ont davantage de commandes que le portail. Les laisser se
     répartir avec un simple flex-wrap rendait leur position dépendante de la
     longueur du nom du cours et du compte : sur certains téléphones, le thème
     partait à gauche, l'administration à droite et la déconnexion sur une
     troisième ligne. Cette grille donne un emplacement stable à chaque rôle.
     Les pages du portail ne portent pas `.bandeau-module` et conservent donc
     leur propre en-tête, déjà validé. */
  .bandeau-module {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    grid-template-areas:
      "marque marque modules"
      "statut theme compte";
    gap: .5rem .45rem;
    align-items: center;
  }
  .bandeau-module .marque {
    grid-area: marque; min-width: 0; margin-right: 0; overflow: hidden;
  }
  .bandeau-module .marque .suite {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .bandeau-module .retour-modules { grid-area: modules; justify-self: end; }
  .bandeau-module .bouton-theme { grid-area: theme; }
  .bandeau-module #session { display: none; }
  .bandeau-module #statutAdhesion { grid-area: statut; justify-self: start; }
  .bandeau-module #btnCompte {
    grid-area: compte; justify-self: end; min-height: 44px;
  }

  .nav-liens {
    order: 3; width: 100%; gap: 2px;
    background: var(--carte); border: 1px solid var(--trait);
    border-radius: var(--r-sm); padding: 2px;
  }
  .nav-liens a { flex: 1; text-align: center; padding: .36rem .5rem; }
  .nav-liens a[aria-current="page"] { background: var(--carte-2); }
  .nav-liens a[aria-current="page"]::after { left: 32%; right: 32%; bottom: .18rem; }

  .accroche { padding: 2.1rem 0 1.5rem; }
  .accroche p { font-size: .92rem; }

  /* Une seule colonne, mais des cartes plus PLATES : sur 358 px utiles, une
     couverture 16/9 fait déjà 201 px de haut. Trois fiches et l'écran est
     plein. La couverture passe donc en 21/9 — le format reste franc, la
     hauteur tombe d'un tiers, et l'on voit quatre fiches au lieu de deux. */
  .grille { gap: .8rem; }
  .couverture { aspect-ratio: 21/9; }
  .couverture.vide span { font-size: 2.1rem; }

  /* Les gros écrans laissent le prix et le bouton sur la même ligne. Ici, un
     titre long les sépare de toute façon ; autant que ce soit décidé. */
  .pied { row-gap: .5rem; }

  .rang { margin: 1rem 0 -.3rem; }
  .rang .filet { display: none; }
  .rang .lien-tout { margin-left: auto; }

  .squelette { height: 178px; }

  .pied-page > div { padding: 1.2rem 1rem 2.5rem; }
}

/* Sous 380 px — iPhone SE, Android d'entrée de gamme — la mention accessoire
   du rang saute plutôt que de pousser « Tout voir » à la ligne. */
@media (max-width: 380px) {
  .rang .etiquette { display: none; }
  .bouton { padding: .42rem .7rem; }
}

/* ---------- 16. Mouvement réduit ----------------------------------------- */
/* Un réglage du système d'exploitation, activé par des gens que le mouvement
   rend malades. On ne le contourne pas. Tout est neutralisé sauf les états de
   survol qui restent des changements de couleur — c'est-à-dire l'information,
   pas l'effet. */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .fiche:hover, .fiche:focus-within { transform: none; }
  .fiche:hover .couverture, .fiche:hover .sceau-module,
  .bouton:hover { transform: none; }
  .fiche::before { transform: scaleX(1); }
  .fiche:active, .carte-vitrine:active, .carte-choix:active { transform: none; }
  @view-transition { navigation: none; }
}

/* ---------- 17. Recherche intelligente & Flou d'arrière-plan -------------- */
.recherche-rideau {
  /* ⚠️ PAS DE FLOU TANT QUE LE VOILE EST FERMÉ (21/10/2026). Ce voile couvre
     tout l'écran en permanence. Avec un backdrop-filter actif même à
     opacité 0, Chrome recalculait le flou de tout l'écran à chaque image du
     défilement ; quand il prenait du retard, la barre, des cartes et les
     cœurs disparaissaient le temps d'une image (scintillement, vidéo du
     21/10/2026 à 11 s). Fermé, il est donc masqué (visibility) et sans flou ;
     le flou ne s'applique qu'à l'ouverture. */
  position: fixed;
  inset: 0;
  z-index: 30;
  background: color-mix(in srgb, var(--fond) 50%, rgba(0, 0, 0, 0.35));
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}

body.recherche-active .recherche-rideau {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: opacity 0.25s ease, visibility 0s;
  backdrop-filter: blur(12px) saturate(130%);
  -webkit-backdrop-filter: blur(12px) saturate(130%);
}

:root[data-theme="dark"] .recherche-rideau {
  background: color-mix(in srgb, var(--fond) 50%, rgba(0, 0, 0, 0.65));
}

/* Flou direct sur tout l'arrière-plan dès que l'utilisateur tape */
body.recherche-active .entete,
body.recherche-active .accroche-choix > :not(.recherche-accueil-conteneur),
body.recherche-active .choix,
body.recherche-active .titre-catalogue,
body.recherche-active .grille,
body.recherche-active .pied-page,
body.recherche-active #msg {
  filter: blur(8px);
  opacity: 0.35;
  pointer-events: none;
  user-select: none;
}

.entete,
.marque,
.nav-liens,
main,
.accroche-choix > *,
.choix,
.titre-catalogue,
.grille,
.pied-page,
#msg {
  transition: filter 0.25s ease, opacity 0.25s ease;
}

.recherche-accueil-conteneur,
.recherche-catalogue-conteneur {
  position: relative;
  z-index: 40;
}

.recherche-boite {
  position: relative;
  width: 100%;
  max-width: 680px;
  margin: 1.75rem 0 1rem;
  font-family: inherit;
  z-index: 40;
}

.recherche-ligne {
  display: flex;
  align-items: center;
  gap: .65rem;
  width: 100%;
}

.recherche-champ-enveloppe {
  flex: 1;
  min-width: 0;
  position: relative;
  display: flex;
  align-items: center;
  background: var(--carte);
  border: 1.5px solid var(--trait);
  border-radius: var(--pilule);
  padding: .4rem .75rem .4rem 1.1rem;
  box-shadow: 0 4px 18px -6px rgba(0,0,0,.08);
  transition: border-color var(--t), box-shadow var(--t), background-color var(--t);
}

.recherche-champ-enveloppe:focus-within {
  border-color: var(--c1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--c1) 20%, transparent), 0 8px 24px -8px rgba(0,0,0,.12);
}

body.recherche-active .recherche-champ-enveloppe {
  border-color: var(--c1);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--c1) 30%, transparent), 0 16px 36px -10px rgba(0,0,0,.22);
}

.recherche-icone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--encre-3);
  margin-right: .65rem;
  flex-shrink: 0;
}

.recherche-champ {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--encre);
  font: inherit;
  font-size: 1.02rem;
  line-height: 1.4;
  outline: none;
  padding: .4rem 0;
}

.recherche-champ::placeholder {
  color: var(--encre-3);
  opacity: .95;
}

.recherche-champ::-webkit-search-cancel-button {
  display: none;
}

.recherche-effacer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: var(--carte-2);
  color: var(--encre-2);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  margin-left: .5rem;
  flex-shrink: 0;
  transition: background var(--t), color var(--t);
}

.recherche-effacer:hover {
  background: var(--trait);
  color: var(--encre);
}

/* Bouton Favoris rond placé à droite de la barre de recherche */
.recherche-btn-favoris {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1.5px solid var(--trait);
  background: var(--carte);
  color: var(--encre-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  cursor: pointer;
  padding: 0;
  box-shadow: 0 4px 18px -6px rgba(0,0,0,.08);
  transition: all var(--t) var(--ressort);
}

.recherche-btn-favoris:hover {
  border-color: #e11d48;
  color: #e11d48;
  transform: scale(1.06);
  box-shadow: 0 4px 16px -4px rgba(225, 29, 72, .3);
}

.recherche-btn-favoris:active {
  transform: scale(.94);
}

.recherche-btn-favoris .coeur-filtre-icone {
  width: 21px;
  height: 21px;
  color: #e11d48;
  transition: transform var(--t) var(--ressort), fill var(--t);
}

.recherche-btn-favoris:hover .coeur-filtre-icone {
  transform: scale(1.12);
}

.recherche-btn-favoris.actif {
  background: color-mix(in srgb, #e11d48 12%, var(--carte));
  border-color: #e11d48;
  color: #e11d48;
  box-shadow: 0 0 0 3px color-mix(in srgb, #e11d48 22%, transparent), 0 4px 16px -4px rgba(225, 29, 72, .35);
}

.recherche-btn-favoris.actif .coeur-filtre-icone {
  fill: #e11d48;
  transform: scale(1.08);
}

.recherche-btn-favoris .compteur-favoris {
  position: absolute;
  top: -3px;
  right: -3px;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border-radius: 10px;
  background: #e11d48;
  color: #fff;
  font-size: .68rem;
  font-weight: 800;
  line-height: 19px;
  text-align: center;
  box-shadow: 0 2px 6px rgba(225, 29, 72, .45);
  pointer-events: none;
}

:root[data-theme="dark"] .recherche-btn-favoris.actif,
:root[data-theme="sombre"] .recherche-btn-favoris.actif,
:root.dark .recherche-btn-favoris.actif {
  background: color-mix(in srgb, #fb7185 16%, var(--carte));
  border-color: #fb7185;
  color: #fb7185;
  box-shadow: 0 0 0 3px color-mix(in srgb, #fb7185 24%, transparent), 0 4px 16px -4px rgba(251, 113, 133, .4);
}

:root[data-theme="dark"] .recherche-btn-favoris.actif .coeur-filtre-icone,
:root[data-theme="sombre"] .recherche-btn-favoris.actif .coeur-filtre-icone,
:root.dark .recherche-btn-favoris.actif .coeur-filtre-icone {
  fill: #fb7185;
}

.recherche-resultats {
  position: absolute;
  top: calc(100% + .5rem);
  left: 0;
  right: 0;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--r);
  box-shadow: 0 16px 36px -10px rgba(0,0,0,.16);
  max-height: 440px;
  overflow-y: auto;
  z-index: 50;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.recherche-compte-barre {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: .65rem 1rem;
  font-size: .76rem;
  font-weight: 600;
  color: var(--encre-3);
  border-bottom: 1px solid var(--trait-2);
  background: var(--carte-2);
}

.recherche-lien-catalogue {
  color: var(--c1);
  text-decoration: none;
  font-weight: 650;
}

.recherche-lien-catalogue:hover {
  text-decoration: underline;
}

.recherche-liste {
  display: flex;
  flex-direction: column;
}

.recherche-item {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  padding: .75rem 1rem;
  border-bottom: 1px solid var(--trait-2);
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: background-color var(--t);
}

.recherche-item:last-child {
  border-bottom: none;
}

.recherche-item:hover,
.recherche-item.selectionne {
  background: color-mix(in srgb, var(--item-couleur, var(--c1)) 9%, var(--carte));
}

.recherche-item-tete {
  display: flex;
  align-items: center;
  gap: .55rem;
}

.recherche-item-badge {
  font-size: .68rem;
  font-weight: 750;
  padding: .15rem .45rem;
  border-radius: var(--pilule);
  text-transform: uppercase;
  letter-spacing: .02em;
  flex-shrink: 0;
}

.recherche-badge-module {
  background: color-mix(in srgb, var(--item-couleur, var(--c1)) 14%, var(--carte));
  color: var(--item-couleur, var(--c1));
  border: 1px solid color-mix(in srgb, var(--item-couleur, var(--c1)) 30%, transparent);
}

.recherche-badge-jeu {
  background: color-mix(in srgb, #f59e0b 16%, var(--carte));
  color: #b45309;
  border: 1px solid rgba(245, 158, 11, .35);
}

:root[data-theme="dark"] .recherche-badge-jeu {
  color: #fcd34d;
}

.recherche-item-titre {
  font-size: .95rem;
  font-weight: 700;
  color: var(--encre);
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.recherche-item-prix {
  font-size: .74rem;
  font-weight: 600;
  color: var(--encre-2);
  flex-shrink: 0;
}

.recherche-item-desc {
  margin: 0;
  font-size: .82rem;
  line-height: 1.42;
  color: var(--encre-2);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.recherche-item-pied {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: .15rem;
  font-size: .74rem;
}

.recherche-item-cat {
  color: var(--encre-3);
  font-weight: 550;
}

.recherche-item-aller {
  color: var(--item-couleur, var(--c1));
  font-weight: 700;
}

.recherche-surligne {
  background: color-mix(in srgb, var(--c5) 30%, transparent);
  color: inherit;
  padding: .05rem .2rem;
  border-radius: 3px;
}

:root[data-theme="dark"] .recherche-surligne {
  background: color-mix(in srgb, var(--c5) 45%, transparent);
  color: #fff;
}

.recherche-vide {
  padding: 1.5rem 1rem;
  text-align: center;
  color: var(--encre-2);
  font-size: .88rem;
}

.recherche-vide strong {
  color: var(--encre);
}

.recherche-conseil {
  font-size: .78rem;
  color: var(--encre-3);
  margin-top: .4rem;
}

@media (max-width: 600px) {
  .recherche-ligne { gap: .45rem; }
  .recherche-champ { font-size: .92rem; }
  .recherche-btn-favoris { width: 44px; height: 44px; }
  .recherche-btn-favoris .coeur-filtre-icone { width: 19px; height: 19px; }
  .recherche-item-prix { display: none; }
}

/* ---------- 18. Système de Favoris sur les cartes & Accès Rapide ---------- */

/* Bouton cœur favori direct sur les cartes */
.btn-favori {
  position: absolute;
  top: .62rem;
  left: .62rem;
  z-index: 5;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Sans backdrop-filter (21/10/2026) : un flou sur un élément qui défile au-dessus des images faisait scintiller la page dans Chrome. Fond presque opaque à la place. */
  background: color-mix(in srgb, var(--carte) 94%, transparent);
  border: 1px solid color-mix(in srgb, var(--trait) 80%, transparent);
  color: var(--encre-2);
  cursor: pointer;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.12);
  transition: transform var(--t) var(--ressort),
              background-color var(--t) ease,
              border-color var(--t) ease,
              color var(--t) ease,
              box-shadow var(--t) ease;
  padding: 0;
  line-height: 1;
}

.btn-favori:hover {
  transform: scale(1.12);
  background: var(--carte);
  border-color: #f43f5e;
  color: #f43f5e;
  box-shadow: 0 4px 14px rgba(244, 63, 94, 0.25);
}

.btn-favori:focus-visible {
  outline: 2px solid #e11d48;
  outline-offset: 2px;
}

.btn-favori.actif {
  background: #fff1f2;
  border-color: #f43f5e;
  color: #e11d48;
  box-shadow: 0 4px 14px rgba(225, 29, 72, 0.35);
}

:root[data-theme="dark"] .btn-favori.actif {
  background: rgba(225, 29, 72, 0.22);
  border-color: #fb7185;
  color: #fb7185;
  box-shadow: 0 4px 14px rgba(244, 63, 94, 0.3);
}

@keyframes popFavori {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.32); }
  70%  { transform: scale(0.92); }
  100% { transform: scale(1); }
}

.btn-favori.anime-pop {
  animation: popFavori 0.32s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}


/* Badge favori dans les résultats de recherche déroulants */
.recherche-item-badge-favori {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .68rem;
  font-weight: 750;
  color: #e11d48;
  background: #ffe4e6;
  border: 1px solid #fecdd3;
  border-radius: var(--pilule);
  padding: .15rem .45rem;
  line-height: 1;
}

:root[data-theme="dark"] .recherche-item-badge-favori {
  background: rgba(225, 29, 72, 0.2);
  border-color: rgba(251, 113, 133, 0.3);
  color: #fb7185;
}

/* Bandeau d'accès rapide aux favoris en haut du catalogue */
.bandeau-favoris {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem 1.2rem;
  background: color-mix(in srgb, var(--carte) 92%, transparent);
  border: 1px solid color-mix(in srgb, var(--trait) 85%, transparent);
  border-radius: var(--r);
  padding: .85rem 1.2rem;
  margin: 0 0 1.8rem;
  box-shadow: 0 4px 18px -6px rgba(0,0,0,.06);
  animation: apparaitre var(--t) ease;
}

.bandeau-favoris-titre {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  font-size: .86rem;
  font-weight: 700;
  color: var(--encre);
}

.bandeau-favoris-titre svg {
  color: #e11d48;
  fill: #e11d48;
  flex-shrink: 0;
}

.bandeau-favoris-puces {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-items: center;
}

.puce-favori {
  display: inline-flex;
  align-items: center;
  background: var(--carte);
  border: 1px solid var(--trait);
  border-radius: var(--pilule);
  padding: .15rem .25rem .15rem .75rem;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
  transition: transform var(--t) var(--ressort),
              border-color var(--t) ease,
              box-shadow var(--t) ease;
}

.puce-favori:hover {
  border-color: color-mix(in srgb, #f43f5e 40%, var(--trait));
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
}

.puce-favori-lien {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .78rem;
  font-weight: 650;
  color: var(--encre);
  background: transparent;
  border: none;
  padding: .2rem .35rem .2rem 0;
  cursor: pointer;
  text-decoration: none;
  font-family: inherit;
  transition: color var(--t) ease;
}

.puce-favori-lien:hover {
  color: #e11d48;
}

.puce-favori .point-couleur {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--p-couleur, var(--c1));
  flex-shrink: 0;
}

.puce-favori-retirer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: color-mix(in srgb, var(--encre) 6%, transparent);
  color: var(--encre-2);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  margin-left: .25rem;
  transition: all var(--t) ease;
}

.puce-favori-retirer:hover {
  background: #ffe4e6;
  color: #e11d48;
  transform: scale(1.15);
}

:root[data-theme="dark"] .puce-favori-retirer:hover {
  background: rgba(225, 29, 72, 0.3);
  color: #fb7185;
}

.puce-favori-retirer:focus-visible {
  outline: 2px solid #e11d48;
  outline-offset: 1px;
}


.btn-favoris-vue-filtre {
  margin-left: auto;
  font-size: .78rem;
  font-weight: 700;
  color: var(--a, var(--c1));
  background: transparent;
  border: none;
  cursor: pointer;
  padding: .2rem .4rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.btn-favoris-vue-filtre:hover {
  color: #e11d48;
}

/* Surlignage délicat pour carte favori ciblée */
@keyframes flashFavori {
  0%   { box-shadow: 0 0 0 0 rgba(225, 29, 72, 0.6); }
  40%  { box-shadow: 0 0 0 6px rgba(225, 29, 72, 0.35); }
  100% { box-shadow: 0 0 0 0 rgba(225, 29, 72, 0); }
}

.fiche.cible-flash {
  animation: flashFavori 1.4s ease;
}

.msg-vide-favoris {
  grid-column: 1 / -1;
  padding: 3rem 1.5rem;
  text-align: center;
  background: var(--carte);
  border: 1.5px dashed var(--trait);
  border-radius: var(--r);
  color: var(--encre);
  margin: 1.5rem 0;
}

.msg-vide-favoris p {
  margin: 0;
  font-size: 1.05rem;
}

.msg-vide-favoris .desc {
  margin-top: .5rem;
  font-size: .9rem;
  color: var(--encre-2);
}

/* Le menu hamburger commun (styles) vit dans commun/menu-entete.css depuis
   le 21/10/2026 : menu-entete.js le charge lui-même, pour qu'il soit présent
   aussi dans les modules qui ne chargent pas ce fichier (Kids, Mahay). */
