/* ============================================================
   style.css - Feuille de style globale (Design, Layout, Animations)
   RÔLE : C'est la "Peau" et les "Muscles" de l'application.
   Gère la mise en page, les couleurs dynamiques et les animations fluides.
   ============================================================ */

/* ─── RÉINITIALISATION GLOBALE box-sizing (F-15) ─────────────────── */
/* RÔLE : Tous les éléments calculent largeur/hauteur padding+border inclus. */
/* POURQUOI : Avant ce reset, box-sizing était posé ponctuellement (~10×) sur
   les blocs avec padding+border. Un nouveau bloc oublié → débord ou mauvaise
   largeur silencieuse. Une déclaration globale en tête supprime ce piège. */
*, *::before, *::after { box-sizing: border-box; }

/* ─── SYSTÈME 5 : PERSONNALISATION & DESIGN SYSTEM ───────────────── */

:root {
  /* Palette par défaut (écrasée dynamiquement par config.js / ui.js) */
  --bg: #ddd6e8;
  --card: rgba(255, 255, 255, 0.88);
  --solid: #fff;
  --bubble-bg: #fff; /* RÔLE : fond de la bulle de pensée - surchargeable par les palettes */
  
  --pink: #e8a0bf;
  --lilac: #b090d0;
  --mint: #80d0a8;
  --peach: #e8c4a0;
  --sky: #88bee8;
  --coral: #e09090;
  --gold: #e8d088;
  --tama: #c8d8c0;
  
  --text: #5a5070; /* était #38304a - adouci, même teinte prune, moins contrasté */
  --text2: #6e5e8c; /* était #887ea0 - foncé pour passer WCAG AA (ratio > 5:1 sur --card) */
  --border: #ccc4d8;
  --shadow: rgba(56, 48, 74, 0.08);

  /* ─── COULEURS GRAPHIQUE HUMEUR ─────────────────────────────────────── */
  /* RÔLE : Couleurs fixes pour le graphique énergie/bonheur dans l'onglet Progrès.  */
  /* POURQUOI : Indépendantes des palettes de thème - ne changent jamais avec --lilac/--gold. */
  --mood-energy:      #e8d088;  /* jaune doré pastel - énergie (sliders, graphique) */
  --mood-happy:       #b090d0;  /* violet pastel - bonheur (sliders, graphique) - intentionnellement fixe : couleur sémantique humeur, lisibilité indépendante du thème */
  --mood-energy-text: #9a7c00;  /* gold foncé - texte énergie lisible sur fond clair */
  --mood-happy-text:  #7a50b0;  /* violet foncé - texte bonheur lisible sur fond clair */

  /* ─── COULEURS SÉMANTIQUES ────────────────────────────────────────── */
  /* RÔLE : Couche de sens au-dessus des couleurs déco - succès, erreur, warning, info, focus */
  /* POURQUOI : Actuellement tout passe par les couleurs décoratives (--mint, --coral…) sans intention claire */
  --success:    var(--mint);    /* Validation, habitude cochée, connexion OK */
  --danger:     var(--coral);   /* Reset, suppression, erreur */
  --warning:    #e8c068;        /* Attention, limite de quota */
  --info:       var(--sky);     /* Information neutre */
  --focus-ring: var(--lilac);   /* Anneau de focus clavier (cf. :focus-visible) */

  /* ─── RGB POUR rgba() ───────────────────────────────────────────── */
  /* RÔLE : Composantes RGB de --lilac, nécessaires pour rgba(var(--lilac-rgb), opacité) */
  /* POURQUOI : CSS ne peut pas extraire automatiquement les canaux d'une couleur hex -
               on doit les déclarer séparément. Utilisé notamment dans ui-agenda.js */
  --lilac-rgb: 176, 144, 208;
  --lilac-light:  #ede6f7;  /* fond actif filtre - lilas très pâle - recalculé dynamiquement par applyUIPalette() dans ui-settings.js */
  --lilac-xlight: color-mix(in srgb, var(--lilac) 12%, #ffffff);  /* fond console-top - suit la palette automatiquement */
  --lilac-dark:   #6b3fa8;  /* texte actif filtre - lilas profond - recalculé dynamiquement par applyUIPalette() dans ui-settings.js */

  /* Variables d'environnement PWA (Encoches iPhone / Android) */
  --sat: env(safe-area-inset-top, 0px); /* rétabli - protège l'encoche/Dynamic Island en haut */
  --sab: 0px; /* pas de home indicator sur cet appareil - valeur fixe intentionnelle */
  --sal: env(safe-area-inset-left, 0px);  /* absorbe le bord gauche en paysage */
  --sar: env(safe-area-inset-right, 0px); /* absorbe le bord droit en paysage */

  /* ─── FAMILLES TYPOGRAPHIQUES ─────────────────────────────────────── */
  /* RÔLE : 4 rôles distincts pour 4 registres visuels de l'app */
  /* POURQUOI : Chaque police joue un rôle narratif précis - le terminal reste rétro,
                les titres sont chaleureux, la voix du gotchi est reconnaissable,
                le reste est lisible et doux */
  --font-terminal: 'Courier New', monospace; /* Terminal, pixel art, boutons boutique */
  --font-title:    'Caveat', cursive;        /* Stade du gotchi, titres importants, accents cocooning */
  --font-gotchi:   'Nunito', sans-serif;     /* Voix du gotchi - toujours utilisé en italic 300 */
  --font-body:     'Nunito', sans-serif;     /* Tout le reste : labels, stats, modales, corps de texte */

  /* ─── ÉCHELLE TYPOGRAPHIQUE ───────────────────────────────────────── */
  /* RÔLE : Plancher de lisibilité - rien ne doit descendre sous --fs-xs */
  /* POURQUOI : Les tailles 8/9/10px épuisent la lecture, surtout sur iPhone avec TDAH */
  --fs-xs:  11px;  /* Réservé aux timestamps, numéros de version */
  --fs-sm:  13px;  /* Labels secondaires, badges, sous-titres */
  --fs-md:  15px;  /* Corps de texte standard */
  --fs-lg:  18px;  /* Titres de carte, titres de section */
  --fs-xl:  22px;  /* Titre de panneau principal */
  --fs-icon-lg: 40px; /* Emoji décoratif en grand (ex : 🔑 en tête de modale) - BD-17 */

  /* ─── ESPACEMENTS ────────────────────────────────────────────────── */
  /* RÔLE : Espacements cohérents qui évoluent avec la typographie */
  /* POURQUOI : Quand le texte grossit, les conteneurs calibrés en px fixes deviennent trop serrés */
  --sp-xs:  4px;   /* Séparateurs, gaps internes minimes */
  --sp-sm:  8px;   /* Padding interne des petits composants (badges, tags) */
  --sp-md:  12px;  /* Padding standard des cartes et boutons */
  --sp-lg:  16px;  /* Padding généreux, marges entre sections */
  --sp-xl:  24px;  /* Marges entre blocs majeurs */
  --app-gutter: 14px; /* RÔLE : marge latérale uniforme - console, dynamic-zone, tama, bulle, sliders */

  /* ─── BORDER RADIUS ──────────────────────────────────────────────── */
  /* RÔLE : Rayon de courbure cohérent sur tous les composants */
  --r-sm:   6px;   /* Tags, badges, petits boutons */
  --r-md:   10px;  /* Boutons standard, inputs */
  --r-lg:   14px;  /* Cartes, modales */
  --r-xl:   20px;  /* Éléments très arrondis (languette, pills) */

  /* Thème Papier */
  --paper-bg:        #e8e0d0;
  --paper-border:    #c8b8a0;
  --paper-text:      #6a5a40;
  --paper-entry:     rgba(255,255,255,.5);
  --paper-entry-ts:  #a09880;
  --paper-entry-btn: #f0e8d8;
  --paper-book-bg:     #f4edd8;
  --paper-book-border: #c8b898;
  --paper-book-shadow: #b8a888;
  --paper-book-line:   #d4c4a8;

  /* Thème Terminal */
  --terminal-box:          #1a1a1a;
  --terminal-border:       #444;
  --terminal-screen:       #0a0a0a;
  --terminal-screen-border:#333;
  --terminal-text:         #00ff41;
  --terminal-text-dim:     #007a1f;
  --terminal-line-div:     #0f2a0f;

  /* ── Jeux ──────────────────────────────────────────────────────────────
     RÔLE : Variables de design partagées par tous les mini-jeux (canvas p5 + HTML).
     POURQUOI un bloc dédié : les valeurs du canvas p5 ne peuvent pas lire var(--…)
       nativement - game-ui.js les lit via getComputedStyle() dans setup() et les
       passe au sketch. Centraliser ici permet de changer le thème des jeux en un seul
       endroit sans toucher à chaque fichier jeu.
     Convention : toutes les variables commencent par --game-* ou --cx-* (cristaux).
     ─────────────────────────────────────────────────────────────────────────────── */

  /* Fond du canvas - --bg légèrement assombri pour un effet "scène" */
  --game-bg:            #cdc5de;

  /* Fond de la barre HUD (timer, vague, score) - semi-transparent sur le canvas */
  --game-hud-bg:        rgba(56, 48, 74, 0.12);

  /* Polices des jeux - héritent directement des variables app */
  --game-hud-font:      var(--font-body);
  --game-title-font:    var(--font-title);

  /* Arrondis des zones de tri / zones de jeu */
  --game-zone-radius:   14px;

  /* Boutons fin de partie - héritent des couleurs app */
  --game-btn-primary:   var(--lilac);
  --game-btn-secondary: var(--pink);

  /* Ombre - identique à l'app */
  --game-shadow:        var(--shadow);

  /* Texte - identiques aux variables app */
  --game-text:          var(--text);
  --game-text2:         var(--text2);

  /* ── Cristaux (Tri de Cristaux) ────────────────────────────────────────
     RÔLE : Couleurs des 4 cristaux de base + cristal doré bonus.
     POURQUOI ici plutôt que dans ui-cristaux.js : p5 lit ces valeurs via
       getComputedStyle() dans setup() - elles doivent être des custom properties
       CSS accessibles au niveau :root pour que la lecture fonctionne.
     Les fichiers JS référencent ces variables par leur nom cssVar :
       { id:'violet', cssVar:'--cx-violet', couleur:'#b090d0' } etc.
     ──────────────────────────────────────────────────────────────────── */
  --cx-violet: #b090d0;   /* correspond à --lilac */
  --cx-rose:   #f0a0c0;   /* correspond à --pink adouci */
  --cx-bleu:   #90c0f0;   /* correspond à --sky adouci */
  --cx-vert:   #90d0b0;   /* correspond à --mint adouci */
  --cx-dore:   #f0d060;   /* correspond à --gold adouci - cristal bonus */

  /* ── Dégradés de fond par jeu ──────────────────────────────────────────
     RÔLE : Couple top/bottom utilisé par chaque sketch p5 pour son background
            (lu via readGameTheme dans game-ui.js).
     POURQUOI : auparavant les trois jeux partageaient --game-bg (#cdc5de violet
            générique), ce qui créait une rupture visuelle avec les cartes du hub
            qui ont chacune leur propre palette (cf. .game-card[data-jeu-id="…"]).
            Ces variables alignent le canvas de chaque jeu sur sa carte.
     CONVENTION : --<préfixe>-bg-top / --<préfixe>-bg-bot où préfixe = cx/bl/pt.
     ──────────────────────────────────────────────────────────────────── */
  /* Cristaux - violet lilas (cf. .game-card[data-jeu-id="cristaux"]) */
  --cx-bg-top: #e8dcf8;   /* lilas très clair - haut de canvas */
  --cx-bg-bot: #cdb8ef;   /* lilas médium - bas de canvas */
  /* Bulles - bleu ciel aqua (cf. .game-card[data-jeu-id="bulles"]) */
  --bl-bg-top: #d8f0fc;   /* bleu très pâle - évoque l'eau/le ciel */
  --bl-bg-bot: #9cc8e4;   /* aqua médium - fond bas */
  /* Potions - rose pêche (cf. .game-card[data-jeu-id="potions"]) */
  --pt-bg-top: #fce8f0;   /* rose très clair - pétale */
  --pt-bg-bot: #e8a8c4;   /* pêche rosé médium - fond bas */

  /* ─── COULEURS CYCLE MENSTRUEL ───────────────────────────────────
     RÔLE : Couleurs partagées par les modules cycle (ui-agenda.js,
            ui-journal.js, ui-settings.js, app.js).
     POURQUOI : Auparavant hardcodées dans plusieurs fichiers JS (BD-16) -
            centralisées ici pour cohérence et thématisation possible.
     Lecture côté JS : getCSSVar('--c-cycle-rose') (cf. ui-core.js)
     ──────────────────────────────────────────────────────────────── */
  --c-cycle-warm:       #e07060;  /* warm - alerte douce (journal : temps faible) */
  --c-cycle-rose:       #e07080;  /* phase menstruelle / point rose marqueur */
  --c-cycle-bleu:       #80b8e0;  /* phase folliculaire / point bleu marqueur */
  --c-cycle-vert:       #60c8a0;  /* phase ovulation */
  --c-cycle-violet:     #b090d0;  /* phase lutéale (= --lilac, dupliqué pour cohérence sémantique cycle) */
  --c-cycle-warm-alpha: #e0708066;/* contour pointillé semi-transparent (rose alpha) */
  --c-cycle-bleu-alpha: #80b8e066;/* contour semi-transparent (bleu ovulation) */
}

/* Reset CSS basique */
* {
  -webkit-tap-highlight-color: transparent;
  margin: 0;
  padding: 0;
}

/* RÔLE : Reset typographique - force l'héritage de font sur les éléments de formulaire */
/* POURQUOI : Par défaut, button/input/select/textarea ignorent font-family du body en CSS.
              Sans ce reset, ils affichent la police système du navigateur (souvent monospace).
              Les éléments qui doivent rester terminal ont font-family: var(--font-terminal) explicitement. */
button, input, select, textarea {
  font-family: inherit;
}

/* RÔLE : Force le rendu texte du caractère ✿ (U+273F) sur iOS/Android
   POURQUOI : Certains systèmes l'interprètent comme emoji et l'affichent en bleu.
              @font-face avec unicode-range intercepte ce seul caractère et le force
              en rendu texte (pas de variation selector FE0E nécessaire dans le HTML). */
@font-face {
  font-family: 'NunitoFleur';
  src: local('Nunito');
  unicode-range: U+273F; /* ✿ uniquement */
}

/* Application ciblée : boutons et éléments de l'app - pas les emojis vrais */
button, .btn, .btn-p, .btn-s, .btn-d, .thought-flowers, .bilan-flowers,
#bilan-flowers, #journal-flowers, #thought-count {
  font-family: 'NunitoFleur', var(--font-body);
}

body {
  background: var(--bg);
  color: var(--text);
  /* RÔLE : Police de base de toute l'app - Nunito remplace Courier New comme police par défaut */
  /* POURQUOI : Courier New était un héritage du style terminal appliqué partout par défaut.
                Nunito est plus lisible, plus douce, mieux adaptée au quotidien sur mobile.
                Les éléments "terminal" conservent --font-terminal explicitement. */
  font-family: var(--font-body);
  min-height: 100dvh;
  padding-top: var(--sat);
  padding-left: var(--sal);
  padding-right: var(--sar);
  display: flex;
  flex-direction: column;
}

/* Custom Scrollbar minimaliste */
::-webkit-scrollbar { width: 3px; }
::-webkit-scrollbar-thumb { background: transparent; border-radius: 2px; }
#dynamic-zone { scrollbar-width: none; } /* Firefox */


/* ─── SYSTÈME 7 : INGÉNIERIE & LAYOUT GLOBAL ─────────────────────── */

/* CONSOLE FIXE (En haut) */
/* RÔLE : Fond lilas très clair pour distinguer visuellement la zone Gotchi/canvas
   de la zone dynamique basse (navigation + panneaux).
   Le canvas p5.js dessine son propre fond - ce background est derrière le canvas, pas dedans.
   body.garden-fullscreen surcharge ces trois propriétés explicitement → pas de conflit. */
#console-top {
  flex-shrink: 0;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  background: var(--lilac-xlight);
  padding: calc(var(--sat) + 6px) var(--app-gutter) 0;
  border-bottom: none;
  box-shadow: 0 4px 16px rgba(var(--lilac-rgb), 0.22);
}

/* ZONE DYNAMIQUE (Contenu défilant en bas) */
#dynamic-zone{
  flex: 1;
  overflow-y: auto;
  padding: 8px var(--app-gutter);
  padding-top: 320px; /* fallback avant calcul JS - remplacé immédiatement par syncConsoleHeight() */
  padding-bottom: calc(64px + var(--sab));
  width: 100%;
  max-width: 460px;
  align-self: center;
}

/* RÔLE : masque les liens de don tant qu'aucune URL n'est configurée.
   POURQUOI : appliquerLienDon() retire cette classe seulement si
   USER_CONFIG.links.donateUrl existe - donc jamais sur le profil d'Alexia. */
.don-hidden { display: none !important; }

/* ─── CADRE TÉLÉPHONE - GRAND ÉCRAN (desktop / tablette large) ───────
   RÔLE : sur écran large, contenir l'app dans une colonne ~460px centrée,
          façon console portable, au lieu de s'étaler sur toute la largeur.
   POURQUOI min-width 600px : aucun téléphone en portrait n'atteint 600px,
          donc le rendu mobile n'est jamais affecté.
   À VÉRIFIER : modales plein écran, jardin fullscreen, clavier. */
@media (min-width: 600px) {
  html {
    /* le "bureau" autour du téléphone - centre la coque vert. + horiz. */
    background: color-mix(in srgb, var(--lilac) 30%, #ffffff);
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  body {
    position: relative;                 /* ancre les enfants absolute (console, languette, modales) */
    box-sizing: border-box;
    width: 460px;
    height: min(100dvh - 32px, 900px);  /* callé en hauteur (marges « bureau ») */
    min-height: 0;                      /* annule le min-height:100dvh de base */
    margin: 0;
    border: 12px solid #ffffff;         /* contour mobile flat blanc (bezel) */
    border-radius: 44px;                /* rayon ext. ; rayon int. ≈ 44 - 12 = 32 */
    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.22);
    overflow: hidden;                   /* coupe au rayon de la coque */
    background-clip: padding-box;       /* le fond app reste sous l'écran, pas sous le bezel */
  }
  /* RÔLE : le contour blanc redessiné PAR-DESSUS le contenu pour garantir le crop,
     coins arrondis inclus. POURQUOI : la bordure de <body> est peinte AVANT ses
     enfants → un enfant positionné (languette, modale) peut la recouvrir. Ce calque
     masque ce débordement et donne un vrai bezel net. pointer-events:none → n'intercepte
     aucun clic. z-index 9500 : au-dessus du contenu, sous #rotate-overlay (9999). */
  body::after {
    content: "";
    position: absolute;
    inset: -12px;                       /* atteint le bord extérieur (border box) */
    box-sizing: border-box;
    border: 12px solid #ffffff;
    border-radius: 44px;
    pointer-events: none;
    z-index: 9500;
  }
  /* La console est fixée au VIEWPORT en mobile. Dans le cadre desktop, on
     l'ancre DANS la coque (absolute), sinon elle se détache en haut de l'écran
     et le scroll de #dynamic-zone ne fonctionne plus. */
  #console-top {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    transform: none;
    width: auto;
    max-width: none;
    z-index: 60;                        /* garde-fou : le tama reste au-dessus de #dynamic-zone (clics) */
    border-radius: 32px 32px 0 0;       /* = rayon intérieur du bezel */
    overflow: hidden;                   /* arrondit le haut de la coque */
  }
  /* #dynamic-zone (flex:1 + overflow-y:auto) scrolle À L'INTÉRIEUR de la coque. */
  #dynamic-zone {
    max-width: none;
  }
  /* TAMA NET : le canvas a une résolution interne fixe (CS = 200) étirée en width:100%.
     Si la taille d'affichage n'est pas un multiple entier de 200, la mise à l'échelle
     est fractionnaire → pixel art flou. On fige donc l'affichage à 400px (= 2× CS) sur
     l'accueil desktop : mise à l'échelle entière → net (avec image-rendering:pixelated). */
  #console-top:not(.compact) #tama-shell-main {
    max-width: 400px;
    margin-left: auto;
    margin-right: auto;
  }
  /* Chrome normalement fixée au VIEWPORT → ancrée DANS la coque sur desktop, sinon
     elle déborde du faux mobile (languette, modales, terminal, toast, bannière, jardin).
     ⚠️ Préfixe `body ` indispensable : à spécificité égale, les règles position:fixed
     de base (plus bas dans le fichier) gagnaient sur la media query. `body #x`/`body .x`
     passe au-dessus (spécificité supérieure) et l'emporte quel que soit l'ordre.
     L'overflow:hidden de la coque recadre alors tout sous le bezel blanc. */
  body .menu-languette,
  body .app-overlay,
  body #modal,
  body #update-banner,
  body #toast,
  body .canvas-fullscreen-overlay,
  body .canvas-fs-close {
    position: absolute;
  }
  /* Overlays créés dynamiquement en JS (humeur #etats-overlay, RDV #rdv-overlay) avec
     position:fixed EN INLINE → une règle CSS normale ne suffit pas, il faut !important
     pour les ancrer dans la coque au lieu de couvrir tout le viewport. inset:0 inline
     les recadre alors sur la coque (body = bloc conteneur en position:relative). */
  body #etats-overlay,
  body #rdv-overlay,
  body #snack,
  body #garden-lost-banner,
  body #hg-zen-intro-overlay {
    position: absolute !important;
  }
}

/* ─── INVITE DESKTOP « OUVRIR SUR MOBILE » (QR) ──────────────────────
   RÔLE : QR dans l'espace « bureau » À GAUCHE, téléphone poussé À DROITE.
   POURQUOI ≥768px : couvre tablette (paysage + iPad récents) et PC. En dessous,
   pas assez de place à côté de la coque → on n'affiche que le cadre centré. */
#desktop-mobile-invite { display: none; }

@media (min-width: 768px) {
  /* Téléphone poussé à DROITE pour dégager le QR à GAUCHE. */
  html {
    justify-content: flex-end;
    padding-right: clamp(24px, 8vw, 140px);
  }
  #desktop-mobile-invite {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    position: fixed;
    top: 50%;
    /* Collé au flanc gauche de la coque : bord droit du QR = (marge droite du
       téléphone) + (largeur coque 460) + 24px d'écart. Suit le téléphone à toute largeur. */
    right: calc(clamp(24px, 8vw, 140px) + 460px + 24px);
    left: auto;
    transform: translateY(-50%);
    width: clamp(180px, 22vw, 240px);
    padding: 24px;
    background: rgba(255, 255, 255, 0.62);
    border-radius: 20px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.10);
    color: var(--text);
    text-align: center;
    z-index: 5;
  }
  #desktop-mobile-invite .dmi-title {
    font-family: var(--font-title, sans-serif);
    font-size: 1.1rem; margin: 0; color: var(--lilac-dark);
  }
  #desktop-mobile-invite .dmi-text { font-size: 0.9rem; margin: 0; line-height: 1.4; }
  #desktop-mobile-invite .dmi-hint { font-size: 0.8rem; margin: 0; color: var(--text2); }
  #desktop-mobile-invite #dmi-qr {
    width: 140px; height: 140px; background: #fff; padding: 8px;
    border-radius: 12px; display: flex; align-items: center; justify-content: center;
  }
  #desktop-mobile-invite #dmi-qr img,
  #desktop-mobile-invite #dmi-qr canvas { width: 124px !important; height: 124px !important; }
  #desktop-mobile-invite .dmi-don {
    display: inline-block;
    margin-top: 4px;
    padding: 6px 14px;
    font-size: 0.85rem;
    text-decoration: none;
    color: var(--lilac-dark);
    background: rgba(255, 255, 255, 0.7);
    border-radius: 999px;
    border: 1px solid rgba(var(--lilac-rgb), 0.35);
  }
}

/* Header (Date et Bouton Menu) */
.hdr {
  text-align: center;
  padding: 2px 0;
  display: flex;
  justify-content: space-between;
  align-items: flex-start; /* boutons et slot tama alignés en haut */
  position: relative; /* POURQUOI : nécessaire pour que z-index soit appliqué */
  z-index: 1; /* POURQUOI : en mode compact, #tama-bubble-wrap remonte de -48px et passe
                              par-dessus .hdr, bloquant les clics sur les boutons boutique/tablette.
                              Ce z-index garantit que .hdr reste au premier plan. */
}
/* RÔLE : Titre central du header (HabitGotchi + date) */
#hdr-title {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  align-self: stretch;
  border-radius: var(--r-sm);
  /* fondu + légère montée en sortant */
  transition: opacity 0.3s ease, transform 0.3s ease, max-height 0.35s ease, background 0.15s;
  opacity: 1;
  transform: translateY(0);
  max-height: 60px;
  overflow: hidden;
}
/* RÔLE : Feedback tap sur le titre → ouvre l'agenda */
/* POURQUOI var(--lilac-rgb) : suit la palette active - sans ça le fond restait violet même en thème Forêt */
#hdr-title:active { background: rgba(var(--lilac-rgb), 0.15); }
#console-top.compact #hdr-title {
  opacity: 0;
  transform: translateY(-8px);
  max-height: 0;
  pointer-events: none;
}
/* RÔLE : Label vertical de l'onglet courant - ancré à gauche du tama en mode compact */
/* POURQUOI : Le tama occupe la place du titre en mode compact.
              Ce label vertical comble le vide à gauche sans toucher au layout. */
#compact-tab-label {
  display: none;
}
#console-top.compact #compact-tab-label {
  display: block;
  position: absolute;
  left: 4px;
  top: 50%;
  transform: translateY(-50%) rotate(180deg);
  writing-mode: vertical-rl;
  font-size: var(--fs-lg);
  font-family: var(--font-title);
  color: var(--lilac);
  opacity: 0.7;
  letter-spacing: 1px;
  pointer-events: none;
  white-space: nowrap;
  transition: opacity 0.2s;
}
/* RÔLE : Titre "HabitGotchi" dans le header - --font-terminal conservé pour l'identité pixel */
.hdr h1 { font-size: 20px; color: var(--lilac); letter-spacing: 0.5px; line-height: 1.1; font-family: var(--font-title); font-weight: 700; }
.hdr sub { font-size: var(--fs-xs); color: var(--text2); }

/* RÔLE : Date du header - remplace l'ancien <sub> sémantiquement incorrect (BD-07).
   POURQUOI : <sub> portait une intention typographique (indice) - un <span> dédié
              clarifie le rôle et permet d'appliquer la taille sans cascade implicite. */
.header-date { font-size: 0.75em; vertical-align: baseline; }
.hdr .menu-btn {
  width: 44px; height: 44px; border-radius: 10px; border: 2px solid var(--border); /* était 36×36 - Apple HIG : 44pt minimum */
  background: var(--solid); font-size: 16px; cursor: pointer; display: flex;
  align-items: center; justify-content: center; transition: .15s; flex-shrink: 0;
}

/* RÔLE : Icône PNG header (boutique/tablette) - centrée dans le .menu-btn 44×44 */
/* POURQUOI : taille 28px laisse une marge de tap confortable dans le bouton 44px */
.nav-icon-img {
  width: 28px;
  height: 28px;
  image-rendering: pixelated;
  pointer-events: none;
}

/* RÔLE : Icône PNG dans les titres de modales et overlays (h2, span de titre) */
/* POURQUOI : vertical-align:middle aligne l'image avec le texte adjacent sur la ligne de base */
.title-icon-img {
  width: 24px;
  height: 24px;
  image-rendering: pixelated;
  vertical-align: middle;
  margin-right: 6px;
}
/* RÔLE : Icône .title-icon-img à l'intérieur d'un bouton - taille ramenée à 1em */
/* POURQUOI : 24px fixes dans un .btn (fs-sm ≈ 13px) double la hauteur du bouton.  */
/*            1em réserve l'espace layout, scale(1.4) agrandit visuellement         */
/*            sans affecter le flux - le bouton ne grossit pas. */
.btn .title-icon-img {
  width: 1em;
  height: 1em;
  transform: scale(1.4);
}

/* RÔLE : Icône PNG vitality (🌱/💜 dans le label jardin) - remplace les emojis de 11px */
.vitality-icon-img {
  width: 14px;
  height: 14px;
  image-rendering: pixelated;
  display: block;
}
.hdr .menu-btn:active { transform: scale(.9); background: var(--border); }


/* ─── SYSTÈME 1 : MÉTABOLISME (L'Écran du Gotchi) ────────────────── */

/* Le boîtier externe */
.tama-shell {
  background: none;
  border: none;
  padding: 2px;
  box-shadow: none;
  margin: 4px auto 0;
  max-width: 100%; /* POURQUOI : le padding de #console-top gère déjà les marges latérales */
  position: relative;
  z-index: 1;
  /* RÔLE : bloque le scroll natif sur la zone Gotchi pour que le frottement de nettoyage soit fiable.
     POURQUOI : sur Android Chrome, touchmove est passive par défaut → return false du touchMoved p5 ignoré →
     le navigateur intercepte le geste comme un scroll vertical au lieu de laisser passer le scrub.
     pinch-zoom permet le zoom d'accessibilité tout en bloquant scroll/pan. Ajouté 2026-05-18 (feedback testeuse Android). */
  touch-action: pinch-zoom;
  /* Réduction dynamique de la console (quand on change d'onglet) */
  transition: max-width 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
              padding 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
              margin 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  transform-origin: top center;
}

/* ─── BARRE DE PROGRESSION DES HABITUDES DU JOUR ─────────────────── */

/* RÔLE : Conteneur - fond lilas pâle visible à 0/6, contour lilas discret */
/* POURQUOI pas overflow:hidden : le box-shadow de contour serait coupé dedans */
#hab-progress-bar {
  width: 100%;
  height: 7px;
  background: rgba(var(--lilac-rgb), 0.15);
  border: 1px solid rgba(var(--lilac-rgb), 0.3);
  border-radius: 4px;
  margin-top: 6px;
  position: relative;
  transition: height 0.4s cubic-bezier(0.25, 1.15, 0.5, 1),
              opacity 0.4s cubic-bezier(0.25, 1.15, 0.5, 1),
              margin-top 0.4s cubic-bezier(0.25, 1.15, 0.5, 1);
}

/* RÔLE : Fill - gradient lilas→pervenche→mint, grandit depuis la gauche */
/* POURQUOI position:absolute : s'étend dans le conteneur sans pousser son layout,
   border-radius identique pour rester dans le contour. */
/* POURQUOI couleur intermédiaire #88aad4 : évite le gris sRGB au milieu du gradient */
#hab-progress-fill {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0%;
  background: linear-gradient(to right, var(--lilac) 0%, #88aad4 50%, var(--mint) 100%);
  background-size: var(--bar-w, 100%) 100%;
  border-radius: 4px;
  transition: width 0.4s cubic-bezier(0.25, 1.15, 0.5, 1);
}

/* RÔLE : Mode compact - barre masquée pour ne pas surcharger la console réduite */
/* POURQUOI height:0 + opacity:0 : height:0 retire l'espace, opacity:0 garantit l'invisibilité
   pendant la transition - même technique que max-height:0 sur #hdr-title */
#console-top.compact #hab-progress-bar {
  height: 0;
  opacity: 0;
  margin-top: 0;
}

/* RÔLE : Mode compact - bannières Mode Cocon + installation iOS masquées pour ne pas surcharger la console réduite. */
/* POURQUOI !important : les bannières ont un style inline display:flex/none piloté en JS */
/*   (updateCoconBanner / updateIosInstallBanner) - sans !important, le style inline gagnerait sur la règle CSS */
/*   et la bannière resterait visible. La sortie du cocon reste accessible via la section "Mode Cocon" dans Réglages ; */
/*   le tuto iOS reste accessible via Réglages › Notifications. */
#console-top.compact #cocon-banner,
#console-top.compact #ios-install-banner {
  display: none !important;
}

/* RÔLE : Pastille Mode Cocon - rappel visuel en mode compact, en miroir de #compact-tab-label. */
/* POURQUOI : La bannière est masquée en compact (règle ci-dessus). Sur un autre onglet, rien ne
   signalait le Cocon actif. La pastille ne s'affiche QUE si compact ET cocon-active (classe posée
   par updateCoconBanner) - pure logique CSS, le JS ne fait que basculer la classe d'état. */
#cocon-pastille {
  display: none;
}
#console-top.compact.cocon-active #cocon-pastille {
  display: flex;
  align-items: center;
  gap: 3px;
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  writing-mode: vertical-rl;
  padding: 6px 3px;
  border-radius: 11px;
  background: linear-gradient(180deg, #e8d5ff, #f5eaff);
  border: 1px solid #c8a8e0;
  color: var(--text);
  font-size: var(--fs-xs);
  letter-spacing: 0.5px;
  pointer-events: none;
  z-index: 2;
}
/* RÔLE : Masque la pastille pendant la transition jardin / le plein écran - comme #compact-tab-label. */
/* POURQUOI : Cohérence avec le label d'onglet, qui est masqué dans ces deux états (cf. règles plus bas). */
body.garden-preparing #cocon-pastille,
body.garden-fullscreen #cocon-pastille {
  display: none !important;
}

/* RÔLE : Wrapper tama + bulle - en mode normal, dans le flux */
/* position:relative nécessaire pour ancrer #compact-tab-label en absolute à l'intérieur */
#tama-bubble-wrap {
  position: relative;
  transition: margin-top 0.4s cubic-bezier(0.25, 1.15, 0.5, 1);
}

/* RÔLE : Mode compact - le wrapper remonte pour s'aligner avec les boutons du .hdr */
/* POURQUOI : Le .hdr fait ~48px (boutons 44px + padding). En mode compact, #hdr-title
              disparaît (max-height→0) mais .hdr garde sa hauteur pour les boutons.
              On remonte #tama-bubble-wrap de cette hauteur pour que le tama
              soit visuellement aligné avec les boutons. */
#console-top.compact #tama-bubble-wrap {
  margin-top: -48px; /* remonte de la hauteur du .hdr */
}

/* Tama réduit en mode compact */
#console-top.compact #tama-shell-main {
  max-width: 220px;  /* un peu plus grand, avec marge latérale pour ne pas coller aux boutons */
  padding-left: 8px;
  padding-right: 8px;
  margin-left: auto;
  margin-right: auto;
  transition: max-width 0.4s cubic-bezier(0.25, 1.15, 0.5, 1);
}
#console-top.compact .bubble { margin-bottom: 8px; }

/* RÔLE : Padding sous la bulle uniquement sur l'onglet accueil (mode non-compact) */
/* POURQUOI : En mode compact (autres onglets), la bulle est masquée - pas de padding nécessaire */
#console-top:not(.compact) {
  padding-bottom: 10px;
}

/* L'écran Canvas (Le jeu en lui-même) */
.tama-screen {
  touch-action: manipulation;
  background: var(--tama);
  border: 3px solid var(--lilac);
  border-radius: 8px;
  overflow: hidden;
  aspect-ratio: 1/1;
  width: 100%;
  margin: 0 auto;
  position: relative; /* RÔLE : contexte de positionnement pour .tama-env-flash */
}

/* RÔLE : Flash coloré par-dessus le canvas lors d'un changement d'env depuis l'inventaire.
   POURQUOI : Le flash p5 (_envFadeState) s'exécute dans le canvas lui-même - invisible
              si le canvas est trop petit (compact) ou si la couleur pastel se noie dans le fond.
              Cet overlay CSS est posé AU-DESSUS du canvas et garantit un flash visible
              quelle que soit la taille du tama. */
@keyframes tamaEnvFlash {
  0%   { opacity: 0; }
  30%  { opacity: 0.82; }
  100% { opacity: 0; }
}
.tama-env-flash {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 5;
  animation: tamaEnvFlash 0.75s ease-out forwards;
}
/* Empêche le lissage des pixels pour garder l'effet Rétro */
.tama-screen canvas {
  display: block;
  image-rendering: pixelated !important;
  image-rendering: crisp-edges !important;
  width: 100% !important;
  height: 100% !important;
}


/* ─── SYSTÈME 3 : COGNITION & IA (Dialogue) ──────────────────────── */

/* La Bulle de pensée */
.bubble {
  background: var(--bubble-bg);
  /* POURQUOI : --bubble-bg défini dans :root à #fff, surchargeable par les palettes */
  border: none;
  border-radius: 8px;
  padding: 10px 16px;
  white-space: pre-line; /* RÔLE : permet les sauts de ligne via \n dans flashBubble() */
  /* RÔLE : Police du gotchi - italic fin pour marquer que c'est SA voix */
  /* POURQUOI : On veut que le lecteur·ice sente immédiatement que c'est le gotchi qui s'exprime */
  font-family: var(--font-gotchi);
  font-style: italic;
  font-weight: 300;
  font-size: var(--fs-sm);
  line-height: 1.4;
  text-align: center;
  height: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 12px var(--shadow);
  position: relative;
  margin: 6px auto 0;
  max-width: 100%; /* POURQUOI : le padding de #console-top gère déjà les marges latérales */
  width: 100%;
  z-index: 10;
}
/* La petite flèche pointant vers le Gotchi */
/* POURQUOI : triangle blanc sans bordure - cohérent avec le fond blanc de la bulle */
.bubble::before {
  content: '';
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%);
  border-left: 7px solid transparent;
  border-right: 7px solid transparent;
  border-bottom: 8px solid var(--bubble-bg);
  display: block;
}
.bubble::after { display: none; }
   
/* CHAT IA (Soutien) */
.soutien-chat {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 50dvh; overflow-y: auto; padding: 8px 0;
}
.chat-bubble-user {
  align-self: flex-end; background: var(--lilac); color: #fff;
  border-radius: 12px 12px 2px 12px; padding: 8px 12px;
  font-size: var(--fs-sm); max-width: 85%; line-height: 1.5; /* était 11px */
  font-family: var(--font-gotchi);
  font-style: italic;
  font-weight: 300;
}
.chat-bubble-claude {
  align-self: flex-start; background: #f0e8ff; color: var(--text);
  border-radius: 12px 12px 12px 2px; padding: 8px 12px;
  font-size: var(--fs-sm); max-width: 90%; line-height: 1.5; /* était 11px */
  border: 1px solid var(--border);
  font-family: var(--font-gotchi); /* POURQUOI : voix du gotchi - même registre que la bulle principale */
  font-style: italic;
  font-weight: 300;
}
.chat-bubble-system {
  text-align: center; font-size: var(--fs-xs); color: var(--text2); /* était 9px - messages système = secondaires */
  padding: 2px 0; font-style: italic;
}


/* ─── SYSTÈME 2 : NAVIGATION (Menu & Tiroir) ─────────────────────── */

/* ─── RUBAN DIAGONAL - Bouton menu ───────────────────────────────── */
/* RÔLE : Remplace l'ancienne languette centrée en bas, trop proche visuellement
          des cartes de l'onglet Inventaire (mêmes bords, même largeur).
   POURQUOI ruban diagonal : forme distinctive, ancrée dans un coin,
          aucune ambiguïté avec les éléments de contenu. */
.menu-languette {
  position: fixed;
  bottom: 0;
  right: 0;
  /* RÔLE : crée le triangle de coin via clip-path - pointe vers le haut à droite */
  width: 92px;
  height: 92px;
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  background: var(--lilac);
  border: none;
  padding: 0;
  cursor: pointer;
  z-index: 150;
  /* RÔLE : ombre portée sous le triangle */
  /* POURQUOI var(--lilac-rgb) : l'ombre doit suivre la couleur de la languette qui utilise déjà var(--lilac) */
  filter: drop-shadow(2px -2px 6px rgba(var(--lilac-rgb), .40));
  /* RÔLE : on anime width + height pour l'effet "on tire sur une feuille de coin" */
  /* POURQUOI pas transform : le triangle est ancré en bas à droite via position fixed -
     agrandir width/height depuis ce coin donne l'illusion que la feuille se décolle */
  transition: width  0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
              height 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
              filter 0.2s ease;
}

/* RÔLE : Icône ☰ positionnée dans le coin inférieur droit du triangle */
.menu-languette::after {
  content: '☰';
  position: absolute;
  bottom: 20px;
  right: 20px;
  font-size: 18px;
  color: #fff;
  line-height: 1;
  pointer-events: none;
  transition: font-size 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
              opacity 0.2s ease;
}

/* RÔLE : Feedback tactile - légère expansion au tap */
.menu-languette:active {
  width: 102px;
  height: 102px;
}

/* RÔLE : État menu ouvert - le triangle s'agrandit comme une feuille qu'on tire */
/* POURQUOI 110px : assez grand pour être perçu clairement, pas au point de gêner le contenu */
.menu-languette.is-open {
  width: 110px;
  height: 110px;
  /* POURQUOI var(--lilac-rgb) : l'ombre ouverte amplifie la couleur de la languette - doit rester cohérente avec le thème */
  filter: drop-shadow(-2px -4px 12px rgba(var(--lilac-rgb), .55));
}
.menu-languette.is-open::after {
  content: '✕';
  font-size: 22px;
}

/* ─── CLASSE PARTAGÉE POUR TOUS LES OVERLAYS ────────────────────── */
/* RÔLE : Garantit que chaque overlay couvre bien tout le viewport ET capte les taps.
   POURQUOI : Sans pointer-events:auto explicite, certains navigateurs mobiles laissent
              les événements touch "passer à travers" l'overlay vers les éléments derrière.
              Quand display:none, pointer-events est automatiquement ignoré - pas de conflit.
   CONVENTION : Toute modale/overlay DOIT avoir cette classe OU utiliser openModal()/clModal(). */
.app-overlay {
  position: fixed; inset: 0; pointer-events: auto;
}

/* Modale du Menu Principal */
/* RÔLE : -webkit-backdrop-filter dupliqué - iOS Safari 15/16/17 ne reconnaît pas la version standard.
   POURQUOI : sans préfixe, le fond reste opaque sur ~5-15 % du parc iOS (audit cross-platform 2026-05-18 F-07). */
.menu-overlay {
  z-index: 200; display: none;
  align-items: center; justify-content: center;
  background: rgba(56, 48, 74, 0.45); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.menu-overlay.open { display: flex; }

/* ─── MENU CAHIER D'ADO ──────────────────────────────────────────── */

/* RÔLE : Conteneur principal - aspect cahier spirale avec lignes bleues */
.menu-book {
  background: var(--paper-book-bg);
  border: 4px solid var(--paper-book-border);
  border-radius: var(--r-sm);
  padding: var(--sp-md) var(--sp-md) var(--sp-sm) 28px; /* 28px à gauche = espace reliure */
  width: 300px;
  box-shadow: 4px 4px 0 var(--paper-book-shadow), inset 0 0 20px rgba(0,0,0,.05);
  font-family: var(--font-title);
  position: relative;
  /* POURQUOI repeating-linear-gradient : simule les lignes d'un cahier, sans image à charger */
  background-image: repeating-linear-gradient(
    to bottom,
    transparent,
    transparent 27px,
    #c8d8f0 27px,
    #c8d8f0 28px
  );
  background-position: 0 52px; /* décale les lignes sous le titre */
}

/* Reliure rouge à gauche */
.menu-book::before {
  content: '';
  position: absolute;
  left: 18px;
  top: 0; bottom: 0;
  width: 2px;
  background: #e09090;
}

/* Trous de reliure */
.menu-book::after {
  content: '';
  position: absolute;
  left: 14px;
  top: 0; bottom: 0;
  width: 10px;
  background-image: radial-gradient(circle, #d4c4a8 4px, transparent 4px);
  background-size: 10px 36px;
  background-repeat: repeat-y;
  background-position: 0 18px;
}

/* Titre du cahier */
.menu-book h2 {
  text-align: center;
  font-size: 18px;
  font-family: var(--font-title);
  font-weight: 700;
  letter-spacing: 0.5px;
  margin-bottom: 24px; /* POURQUOI : était 12px - plus d'air sous le nom du gotchi */
  color: var(--paper-text);
  position: relative; /* passe au-dessus des lignes */
  z-index: 1;
}

/* RÔLE : Rangée de stickers emoji collés dans le menu cahier */
/* POURQUOI : emojis grands, bien espacés, occupent toute la largeur utile du cahier */
.menu-stickers {
  display: flex;
  justify-content: space-around; /* POURQUOI space-around : répartit sur toute la largeur sans calc() */
  align-items: center;
  margin-bottom: 14px;
  position: relative;
  z-index: 1;
}

/* RÔLE : Un sticker emoji individuel - grand, nu, avec contour blanc épousant sa forme */
/* POURQUOI drop-shadow multicouche : empile des ombres blanches dans toutes les directions
   pour simuler un stroke qui suit le contour exact de l'emoji (impossible avec border/outline) */
.menu-sticker {
  position: relative; /* RÔLE : ancrage pour badges absolute (cf. #badge-atelier) - POURQUOI : sans ça, le badge se positionnerait sur le parent .menu-stickers */
  font-size: 52px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  transition: transform 0.1s ease;
  filter:
    drop-shadow(0px  3px 0 #fff)
    drop-shadow(0px -3px 0 #fff)
    drop-shadow( 3px 0px 0 #fff)
    drop-shadow(-3px 0px 0 #fff)
    drop-shadow( 2px  2px 0 #fff)
    drop-shadow(-2px  2px 0 #fff)
    drop-shadow( 2px -2px 0 #fff)
    drop-shadow(-2px -2px 0 #fff);
}

/* RÔLE : Inclinaisons alternées - effet stickers collés de travers */
.menu-sticker:nth-child(1) { transform: rotate(-6deg); }
.menu-sticker:nth-child(2) { transform: rotate(3deg); }
.menu-sticker:nth-child(3) { transform: rotate(-4deg); }

/* RÔLE : Feedback tactile au tap */
.menu-sticker:active { transform: scale(0.88) !important; }

/* RÔLE : État désactivé - estompé, non interactif */
.menu-sticker--disabled {
  opacity: 0.45;
  pointer-events: none;
  cursor: default;
}

/* Doodle pixel art coin haut droit */
.menu-doodle {
  position: absolute;
  top: 8px;
  right: 10px;
  opacity: 0.7;
}

/* RÔLE : Liste de navigation - lignes de cahier cliquables */
.menu-lines {
  display: flex;
  flex-direction: column;
  align-items: flex-start; /* ← nécessaire pour que --indent fonctionne */
  gap: 8px; /* POURQUOI : était 2px - plus d'air entre les lignes de nav */
  margin-bottom: 12px;
  position: relative;
  z-index: 1;
}

/* RÔLE : Une ligne de navigation - grande zone de tap, centrée */
.menu-line {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 44px; /* POURQUOI : réduit depuis 56px - moins de padding vertical, plus compact */
  padding: 0 8px; /* POURQUOI : réduit depuis 12px */
  cursor: pointer;
  border-radius: 6px;
  border: 2px solid rgba(200,184,160,0.4);
  transition: background .12s, border-color .12s;
  color: var(--paper-text);
  font-size: 22px;
  font-weight: bold;
  width: 70%;
}

/* RÔLE : Lignes paires décalées à droite - effet quinconce centré */
.menu-line--indent {
  align-self: flex-end;
  margin-right: 10%;
}

/* Rendre cliquable visuellement */
/* POURQUOI var(--lilac-rgb) : le fond tap doit correspondre à la couleur active du menu selon la palette */
.menu-line:active { background: rgba(var(--lilac-rgb), 0.2); border-color: var(--lilac); }

/* RÔLE : État actif - effet surligneur au lieu d'un simple encadré */
/* POURQUOI : border seule ressemble à un encadrement neutre - le surligneur évoque
   le cahier d'ado, plus cohérent avec l'ADN visuel, et plus lisible d'un coup d'œil */
/* POURQUOI var(--lilac-rgb) : l'effet surligneur est la couleur principale de navigation - doit suivre la palette */
.menu-line.active {
  background: linear-gradient(
    to bottom,
    transparent 20%,
    rgba(var(--lilac-rgb), 0.35) 20%,
    rgba(var(--lilac-rgb), 0.35) 80%,
    transparent 80%
  );
  border-color: transparent; /* POURQUOI : on supprime le cadre pour laisser le surligneur parler */
  color: var(--lilac);
  font-weight: 900;
}

.ml-icon  { font-size: 28px; line-height: 1; flex-shrink: 0; }
.ml-label { font-size: 26px; letter-spacing: 0.3px; font-family: var(--font-title); }

/* RÔLE : Icône PNG menu cahier - rendu pixel art net, contour blanc sticker */
/* POURQUOI drop-shadow multicouche : même effet que .menu-sticker - contour blanc qui suit
   le contour exact du PNG transparent, évite la confusion avec le fond beige du cahier */
.ml-icon-img {
  width: 28px;
  height: 28px;
  image-rendering: pixelated;
  flex-shrink: 0;
  filter:
    drop-shadow(0px  2px 0 #fff)
    drop-shadow(0px -2px 0 #fff)
    drop-shadow( 2px 0px 0 #fff)
    drop-shadow(-2px 0px 0 #fff)
    drop-shadow( 1px  1px 0 #fff)
    drop-shadow(-1px  1px 0 #fff)
    drop-shadow( 1px -1px 0 #fff)
    drop-shadow(-1px -1px 0 #fff);
}

/* RÔLE : Icône PNG sticker (jardin/atelier/jeux) - remplace l'emoji, hérite des rotations et drop-shadow du parent */
/* POURQUOI : le filter drop-shadow sur .menu-sticker suit le contour du PNG transparent - effet sticker préservé */
.sticker-icon-img {
  width: 72px;
  height: 72px;
  image-rendering: pixelated;
  display: block;
  pointer-events: none;
}

/* RÔLE : Icône PNG post-it (agenda/soutien) - affiché au-dessus du label */
/* POURQUOI : séparé du texte pour permettre un sizing indépendant de la fonte */
.postit-icon-img {
  width: 32px;
  height: 32px;
  image-rendering: pixelated;
  display: block;
  margin: 0 auto 2px;
}

/* RÔLE : Post-its empilés verticalement */
.menu-postits {
  display: flex;
  flex-direction: column;
  align-items: center; /* POURQUOI : centre les post-its réduits à 72% dans le cahier */
  gap: 6px;
  margin-top: 10px;
  position: relative;
  z-index: 1;
}

/* RÔLE : Post-it collé en bas du cahier */
/* POURQUOI rotate léger : effet post-it à la va-vite, comme dans un vrai cahier d'ado */
.menu-postit {
  width: 90%; /* POURQUOI : réduit depuis 100% - post-its moins larges, plus vraisemblables */
  padding: 10px 14px;
  font-size: var(--fs-md); /* POURQUOI : était fs-sm - plus lisible, plus présent */
  font-weight: bold;
  font-family: var(--font-body);
  cursor: pointer;
  border-radius: 2px;
  border: none;
  letter-spacing: 0.3px;
  box-shadow: 3px 3px 6px rgba(0,0,0,0.16); /* POURQUOI : ombre légèrement plus marquée */
  transition: transform .12s;
  text-align: center;
}
.menu-postit:active { transform: scale(.95); }

.menu-postit--rose {
  background: #f9c8dc; /* POURQUOI : était #fde8f0 trop pâle - fond plus soutenu */
  color: #7a2848;
  transform: rotate(-1deg);
}
.menu-postit--rose:active { transform: rotate(-1deg) scale(.95); }

.menu-postit--lilac {
  background: #d8bef5; /* POURQUOI : était #ede0f8 trop pâle - fond plus soutenu */
  color: #3d1f6e;
  transform: rotate(0.8deg);
  margin-bottom: 20px; /* POURQUOI : espace sous le post-it soutien avant le bas du cahier */
}
.menu-postit--lilac:active { transform: rotate(0.8deg) scale(.95); }

@keyframes bookSlideUp {
  0%   { transform: translateY(60px) scale(.95); opacity: 0; }
  70%  { transform: translateY(-6px) scale(1.01); }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}
.menu-overlay.open .menu-book {
  animation: bookSlideUp .35s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}


/* ─── COMPOSANTS UI GÉNÉRIQUES (Boutons, Inputs, Cartes) ─────────── */

/* RÔLE : -webkit-backdrop-filter dupliqué - iOS Safari 15/16/17 ne reconnaît pas la version standard.
   POURQUOI : audit cross-platform 2026-05-18 F-07 - sans préfixe, le fond reste opaque sur iOS 15-17. */
.card {
  background: var(--card); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); border: 2px solid var(--border);
  border-radius: var(--r-lg); padding: var(--sp-md); margin-bottom: var(--sp-lg); box-shadow: 0 2px 8px var(--shadow);
  /* POURQUOI : sp-lg (16px) uniformise l'espace entre tous les blocs de l'accueil */
}
/* RÔLE : Titre de section - cartes, panneaux et modales de l'app */
/* POURQUOI : Caveat est plus grande visuellement que Nunito à taille égale - 20px compense
              et donne un rendu cohérent avec les autres titres Caveat de l'app */
.card h2,
.j90 h2,
.modal-box h2 {
  font-family: var(--font-title);
  font-size: 20px;
  font-weight: 700;
  text-align: center;
  margin-bottom: var(--sp-sm);
  letter-spacing: 0.3px;
}

/* RÔLE : Carte action principale - visuellement dominante sur la page Gotchi */
/* POURQUOI : La carte habitudes est la cible principale de l'utilisatrice à l'ouverture -
              elle doit ressortir clairement par rapport à la card-gotchi (info secondaire).
              Fond plus saturé, bordure 2px pleine, ombre portée forte. */
.card-primary {
  border-color: var(--lilac);
  border-width: 2px;
  /* POURQUOI var(--lilac-rgb) : l'ombre colorée de la carte principale reflète la couleur d'accentuation du thème */
  box-shadow: 0 8px 28px rgba(var(--lilac-rgb), 0.38), 0 2px 8px rgba(0,0,0,0.07);
  padding: 0;
  overflow: hidden;
  /* POURQUOI : fond blanc pur pour faire ressortir les icônes sticker et le contenu */
  background: #ffffff;
}

/* RÔLE : Header coloré de la carte habitudes */
/* POURQUOI : space-between pousse le badge X/6 à droite, titre à gauche */
.card-primary-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* POURQUOI var(--lilac-rgb) : le header de carte suit la teinte principale - sinon reste violet en palette Océan */
  background: rgba(var(--lilac-rgb), 0.15);
  border-bottom: 1px solid rgba(var(--lilac-rgb), 0.45);
  padding: var(--sp-sm) var(--sp-md);
  margin-bottom: 0;
}

/* RÔLE : Titre "Tes habitudes du jour" - Caveat pour un accent chaleureux */
.card-primary-header h2 {
  font-family: var(--font-title);
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 0;
  margin-bottom: 0;
}

/* RÔLE : Badge compteur habitudes - pill X/6 dans le header de la carte habitudes */
/* POURQUOI : Signal de progression immédiatement lisible sans scanner la liste ;
              vire au vert quand toutes les habitudes sont cochées pour donner
              un feedback de complétion sans toast supplémentaire */
#hab-count {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-sm);
  background: var(--lilac);
  color: #fff;
  padding: 3px 10px;
  border-radius: 10px;
  font-weight: bold;
  transition: background 0.35s ease, transform 0.2s ease;
  letter-spacing: 0.3px;
}
#hab-count.all-done {
  /* POURQUOI : feedback vert doux - même teinte que .hab.done, cohérence palette */
  background: var(--mint);
  transform: scale(1.08);
}

/* RÔLE : Zone liste des habitudes - padding interne après le header */
#hab-home {
  padding: var(--sp-md) var(--sp-md) var(--sp-lg);
  /* POURQUOI : padding latéral var(--sp-md) - aligné sur le padding latéral standard des .card */
}

/* RÔLE : Icône PNG catégorie - rendu pixel art net à toutes les tailles */
/* POURQUOI : image-rendering:pixelated préserve les contours nets quand le PNG
              est affiché à une taille supérieure à sa taille native (24×24 → 28px) */
.cat-icon-img {
  /* RÔLE : Icône catégorie - centrée verticalement dans la ligne .hab, liseré blanc sticker */
  display: block;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  /* RÔLE : Liseré blanc net style sticker - 4 drop-shadow à 0px blur décalés 2px */
  /* POURQUOI : blur:0 = contour pixel-perfect, pas de halo flou */
  filter: drop-shadow(0  2px 0 #fff)
          drop-shadow(0 -2px 0 #fff)
          drop-shadow( 2px 0 0 #fff)
          drop-shadow(-2px 0 0 #fff)
          drop-shadow(0 1px 2px rgba(0,0,0,0.12));
  transition: filter 0.3s ease, transform 0.3s ease;
}

/* RÔLE : Quinconce - variable CSS de rotation définie sur .hab, lue par .cat-icon-img */
/* POURQUOI : passer par une variable permet à l'animation de combiner scale + rotate
              sans que le transform de keyframe écrase la rotation quinconce */
.hab:nth-child(odd)  { --icon-rot: -6deg; }
.hab:nth-child(even) { --icon-rot:  6deg; }
.cat-icon-img { transform: rotate(var(--icon-rot, 0deg)); }

/* RÔLE : Bounce au cochage - scale + rotation quinconce combinés via var(--icon-rot) */
/* POURQUOI : intégrer la rotation dans chaque keyframe évite que scale() l'écrase */
@keyframes iconDone {
  0%   { transform: scale(1)    rotate(var(--icon-rot, 0deg)); }
  35%  { transform: scale(1.28) rotate(var(--icon-rot, 0deg)); }
  60%  { transform: scale(0.88) rotate(var(--icon-rot, 0deg)); }
  80%  { transform: scale(1.1)  rotate(var(--icon-rot, 0deg)); }
  100% { transform: scale(1)    rotate(var(--icon-rot, 0deg)); }
}

/* RÔLE : Désaturation quand l'habitude est cochée - icône grisée, liseré blanc conservé */
/* POURQUOI : grayscale(1) + opacity légère signale visuellement "fait" sans teinte bizarre */
.hab.done .cat-icon-img {
  filter: drop-shadow(0  2px 0 #fff)
          drop-shadow(0 -2px 0 #fff)
          drop-shadow( 2px 0 0 #fff)
          drop-shadow(-2px 0 0 #fff)
          drop-shadow(0 1px 2px rgba(0,0,0,0.10))
          grayscale(1) opacity(0.55);
  animation: iconDone 0.45s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
}

/* RÔLE : Taille dans la mini-bar - conservée pour compat si jamais réactivée */
.hab-mini .cat-icon-img {
  width: 34px;
  height: 34px;
  filter: drop-shadow(0  2px 0 #fff)
          drop-shadow(0 -2px 0 #fff)
          drop-shadow( 2px 0 0 #fff)
          drop-shadow(-2px 0 0 #fff);
}

/* RÔLE : Fallback emoji si le PNG est absent (onerror dans getCatIcon) */
.cat-icon-fallback {
  font-size: 26px;
  line-height: 1;
  flex-shrink: 0;
}

/* RÔLE : Pastille colorée identifiant une catégorie d'habitude (sport, nutri…) */
/* POURQUOI : Utilisée dans la modale d'édition des habitudes (ouvrirEditionHabitudes
              dans ui-habs.js) - couplée à un libellé textuel ("Sport", "Hydratation")
              pour donner deux signaux redondants (couleur + texte) sans dépendre des
              PNG sticker, qui restent réservés à la vue d'accueil. */
/* POURQUOI 14px : taille calée sur la cap-height d'un texte var(--fs-sm) - la pastille
              tient à côté du label sans dominer visuellement. flex-shrink:0 garantit
              qu'elle ne s'écrase pas si le conteneur manque de place. */
.cat-badge {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  flex-shrink: 0;
  /* Liseré blanc fin façon sticker - cohérence visuelle avec .cat-icon-img */
  box-shadow: 0 0 0 1.5px #fff, 0 1px 2px rgba(0,0,0,0.12);
}

/* RÔLE : Poignée de drag affichée dans la modale d'édition des habitudes.
   POURQUOI : SortableJS écoute uniquement sur cette poignée (option `handle`)
              - touche le glyphe ⋮⋮ pour réordonner, tape ailleurs pour éditer
              le label sans déclencher de drag accidentel. */
.drag-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  color: var(--text2);
  opacity: 0.55;
  font-size: 16px;
  line-height: 1;
  flex-shrink: 0;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  /* POURQUOI : sans touch-action:none, iOS interprète le geste comme un scroll
                et SortableJS ne reçoit pas l'événement de drag. */
  touch-action: none;
  transition: opacity 0.15s ease, background 0.15s ease;
}
.drag-handle:hover { opacity: 0.9; background: rgba(var(--lilac-rgb), 0.10); }
.drag-handle:active { cursor: grabbing; opacity: 1; }

/* RÔLE : États visuels pendant le drag - appliqués par SortableJS via les options
   `ghostClass`, `chosenClass` et `dragClass`. */
/* POURQUOI : feedback discret pour confirmer que la ligne est saisie sans imiter
              un système d'OS étranger (pas de soulèvement spectaculaire). */
.hab-edit-row.sortable-ghost   { opacity: 0.25; }
.hab-edit-row.sortable-chosen  { background: rgba(var(--lilac-rgb), 0.08); border-radius: 8px; }
.hab-edit-row.sortable-drag    { opacity: 0.95; box-shadow: 0 6px 16px rgba(0,0,0,0.18); }


/* RÔLE : Carte principale Gotchi - stat + pensée IA réunies */
/* POURQUOI : Fond blanc mat (#fff) - le dégradé lilas/rose est retiré pour laisser
              toute la place à l'effet holographique ::after. La carte reste discrète
              au repos (opacity 0.13) et s'illumine au toucher/survol (opacity 0.32). */
.card-gotchi {
  background: #ffffff;
  /* POURQUOI var(--lilac-rgb) : bordure de la card-gotchi suit la palette - sans ça reste violet en thème Forêt */
  border: 1px solid rgba(var(--lilac-rgb), 0.35);
  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
  text-align: center;
  padding: var(--sp-lg);
  margin-bottom: var(--sp-lg); /* POURQUOI : espace généreux entre carte Gotchi et carte habitudes */
  /* RÔLE : Socle pour l'effet holographique - le ::after est positionné en absolu par-dessus */
  position: relative;
  overflow: hidden;
  will-change: transform;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

/* RÔLE : Couche irisée holographique - style carte Pokémon holographique */
/* POURQUOI : Pseudo-élément indépendant du contenu (pointer-events:none), couvrant toute la
              carte. Le dégradé multi-stops simule l'iridescence d'un film mince (nacre/hologramme).
              Les stops utilisent --pink / --lilac / --mint (variables de palette) pour que le
              reflet suive automatiquement le thème choisi dans la personnalisation.
              Les propriétés --holo-* sont pilotées par JS (mousemove / touchmove) en temps réel. */
.card-gotchi::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(
    calc(var(--holo-angle, 125deg)),
    var(--pink),
    var(--lilac),
    color-mix(in srgb, var(--lilac) 50%, var(--mint)),
    var(--mint),
    color-mix(in srgb, var(--pink) 60%, var(--mint)),
    var(--pink)
  );
  background-size: 250% 250%;
  background-position: var(--holo-x, 50%) var(--holo-y, 50%);
  /* POURQUOI 0.16 et non 0.13 : couleurs palette moins saturées que des HSL purs -
     l'opacity est légèrement remontée pour que l'effet reste visible au repos */
  opacity: var(--holo-opacity, 0.16);
  transition: opacity 0.35s ease;
  z-index: 0;
}

/* RÔLE : Garde le contenu de la carte au-dessus de la couche irisée */
/* POURQUOI : ::after est z-index:0 - sans ce reset, le texte/boutons passeraient sous le reflet */
.card-gotchi > * {
  position: relative;
  z-index: 1;
}

/* RÔLE : Nom du gotchi - police Caveat, chaleureuse et personnelle */
/* POURQUOI : Le nom est un élément d'attachement fort - Caveat lui donne un côté manuscrit/doux */
#g-name {
  font-family: var(--font-title);
  font-weight: 700;
  font-size: 24px;
}

/* RÔLE : Ligne nom + badge anniversaire - centrée, espacée */
.g-name-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-xs);
  margin-bottom: 2px;
}

/* RÔLE : Stade du gotchi - même ligne que le nom, taille proche */
#g-stage {
  font-family: var(--font-title);
  font-weight: 600;
  font-style: italic;
  font-size: 22px;
  color: var(--lilac);
}

/* RÔLE : Bouton info - cercle lilas discret mais lisible */
/* POURQUOI var(--lilac-rgb) : le fond du bouton info est une surface translucide de la couleur principale */
.btn-info-discret {
  background: rgba(var(--lilac-rgb), 0.15);
  border: 1.5px solid var(--lilac);
  border-radius: 50%;
  width: 22px; height: 22px;
  font-size: 12px;
  color: var(--lilac);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  font-family: serif;
  font-style: italic;
  font-weight: bold;
  padding: 0;
  transition: background .15s;
}
/* POURQUOI var(--lilac-rgb) : hover plus intense sur la même teinte que le repos */
.btn-info-discret:hover { background: rgba(var(--lilac-rgb), 0.3); }

/* RÔLE : Fleurs de quota - indique visuellement combien de pensées il reste */
.thought-flowers {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-top: 8px;
  font-size: 20px;
  letter-spacing: 3px;
}
.thought-flowers .flower-on  { opacity: 1;   color: var(--lilac); }
.thought-flowers .flower-off { opacity: 0.2; color: var(--text2); }

/* RÔLE : Fleurs de quota bilan - sous le bouton, sur fond blanc, centrées */
/* POURQUOI : Fleurs déplacées hors du bouton dans un div autonome - plus besoin d'override flex ni de blanc */
#bilan-flowers.thought-flowers { margin-top: 2px; justify-content: center; font-size: 16px; }
/* RÔLE : Couleur des fleurs bilan sur fond blanc */
/* POURQUOI : Même palette que thought-count et journal-flowers - lilac pour on, text2 estompé pour off */
#bilan-flowers .flower-on  { color: var(--lilac); opacity: 1;   }
#bilan-flowers .flower-off { color: var(--text2);  opacity: 0.2; }

/* RÔLE : Zone info agenda dans le post-it menu - RDV du jour + phase cycle */
/* POURQUOI : flex pour aligner cercle couleur + texte phase sur la même ligne */
.agenda-postit-info {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-size: var(--fs-xs);
  color: #7a2848;
  line-height: 1.3;
  flex-wrap: wrap;
}

/* RÔLE : Fleurs de quota soutien - dans le post-it menu, centrées sous le texte */
/* POURQUOI : Override margin-top et font-size pour s'intégrer dans le bouton post-it sans trop de place */
#soutien-flowers.thought-flowers { margin-top: 0; font-size: 14px; letter-spacing: 2px; }
/* POURQUOI : Sur le fond lilac foncé (#d8bef5), utiliser la couleur texte du post-it (#3d1f6e) */
#soutien-flowers .flower-on  { color: #3d1f6e; opacity: 0.9; }
#soutien-flowers .flower-off { color: #3d1f6e; opacity: 0.2; }

/* RÔLE : Zone pensée IA - séparée de la carte par un trait pointillé lilas */
/* POURQUOI : C2.2 - le trait est plus léger qu'un fond coloré et crée une relation visuelle
              directe avec l'esthétique "cahier" du reste de l'app */
#claude-card {
  background: transparent;
  border: none;
  border-top: 1.5px dashed rgba(var(--lilac-rgb), 0.35);
  border-radius: 0;
  padding: var(--sp-md) var(--sp-sm) var(--sp-xs);
  margin-top: var(--sp-md);
  text-align: center;
}

/* RÔLE : Message de pensée IA - italic, fade-in doux à chaque nouvelle pensée */
#claude-card #claude-msg {
  font-style: italic;
  text-align: center;
}

/* RÔLE : Animation d'entrée du message IA - glisse depuis le haut, s'estompe */
/* POURQUOI : rend l'apparition de la pensée vivante, pas brutale */
@keyframes claudeMsgIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
#claude-card #claude-msg.has-msg {
  animation: claudeMsgIn .35s ease both;
}

/* RÔLE : Placeholder quand aucune pensée n'a encore été demandée */
/* POURQUOI : évite une zone vide qui donne l'impression que l'appli est cassée */
#claude-card #claude-msg:empty::before {
  content: 'Demande une pensée à ton Gotchi…';
  font-style: italic;
  font-size: var(--fs-xs);
  color: rgba(var(--lilac-rgb), 0.45);
  display: block;
  margin-top: var(--sp-xs);
}

/* RÔLE : Centrage du message d'attente IA pendant le bilan et les props.
   POURQUOI : startThinkingAnim() pose text-align:center en JS, mais le reset
              CSS au stop peut l'effacer - on le fixe aussi en statique ici. */
#claude-summary,
#prop-loading {
  text-align: center;
  font-style: italic;
}

/* RÔLE : Indicateur "en train de penser" - 3 pastilles qui rebondissent en cascade.
   POURQUOI : remplace les points médians texte (· ·· ···) par un visuel plus grand
              et vivant pendant les attentes IA (startThinkingAnim, tous contextes). */
.think-dots {
  display: inline-flex;
  gap: 5px;
  margin-left: 9px;
  vertical-align: middle;
}
.think-dots i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--lilac);
  animation: thinkDot 1.3s ease-in-out infinite;
}
.think-dots i:nth-child(2) { animation-delay: .16s; }
.think-dots i:nth-child(3) { animation-delay: .32s; }
@keyframes thinkDot {
  0%, 75%, 100% { transform: translateY(0);    opacity: .3; }
  35%           { transform: translateY(-7px); opacity: 1;  }
}
@media (prefers-reduced-motion: reduce) {
  .think-dots i { animation: none; opacity: .55; }
}

/* RÔLE : Bilan IA de la semaine - encart papier doux, italique manuscrit.
   POURQUOI : styles précédemment en inline (BD-04) - déplacés ici pour
              éviter d'écraser la cascade et permettre les overrides thématiques. */
#claude-summary {
  background: rgba(176, 144, 208, .07);
  padding: 14px 16px;
  border-radius: 8px;
  font-size: var(--fs-sm);
  border: 1px solid var(--border);
  margin-bottom: 12px;
  white-space: normal;
  color: var(--text);
  font-family: var(--font-gotchi);
  font-style: italic;
  font-weight: 400;
}

/* RÔLE : Contour de la courbe énergie/bonheur - même carte douce que le bilan,
   pour qu'elle ne "flotte" plus (la légende énergie/bonheur est dans le SVG). */
#mood-chart-wrap {
  background: rgba(176, 144, 208, .07);
  padding: 12px 14px 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
}
#mood-chart-wrap:empty { display: none; } /* pas de boîte vide avant rendu */

/* RÔLE : Paragraphes du bilan IA - aération et lisibilité mobile
   POURQUOI : Le bilan est parsé en <p class="bilan-para"> côté JS (ui-ai.js) ;
              chaque paragraphe respire, la 1re phrase sert d'accroche visuelle */
.bilan-para {
  margin: 0 0 10px;
  line-height: 1.75;
  text-align: left;
}
.bilan-para:last-child { margin-bottom: 0; }


.inp {
  width: 100%; padding: var(--sp-sm) var(--sp-md); border: 2px solid var(--border); border-radius: var(--r-md);
  /* RÔLE : Champs de saisie - police body pour lisibilité */
  background: #fff; font-size: var(--fs-sm); font-family: var(--font-body); color: var(--text); outline: none; transition: .2s;
}
.inp:focus { border-color: var(--lilac); }

/* RÔLE : Neutralise le rendu natif iOS sur input[type="time"] et <select> du bloc Notifications.
   POURQUOI : Sur Safari iOS, ces deux contrôles ont une largeur intrinsèque (UI native du picker)
              qui ignore width:100% et déborde du conteneur sur petits écrans. -webkit-appearance:none
              redonne la main au CSS. min-width:0 empêche l'auto-min-width des flex items.
              Une petite flèche en background-image rend le select toujours identifiable. */
#notif-prefs input[type="time"],
#notif-prefs select {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  min-width: 0;
  max-width: 100%;
}
#notif-prefs select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath fill='%23999' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-md) center;
  background-size: 10px 6px;
  padding-right: calc(var(--sp-md) * 2 + 10px);
}

.btn {
  /* RÔLE : Boutons globaux - police body, lisible et douce */
  padding: var(--sp-sm) var(--sp-lg); border: none; border-radius: var(--r-md);
  font-size: var(--fs-sm); font-weight: bold; font-family: var(--font-body); line-height: 1;
  cursor: pointer; transition: .12s;
}
.btn:active { transform: scale(.94); }
/* RÔLE : Anneau de focus visible pour navigation clavier et assistive */
/* POURQUOI : Aucun :focus n'était défini - invisible sur tablette/desktop et inaccessible au clavier */
.btn:focus-visible,
.menu-btn:focus-visible,
.menu-circle:focus-visible,
.nav-a:focus-visible,
.pin-k:focus-visible,
.inp:focus-visible,
.mood-b:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}
.btn-p { background: var(--lilac); color: #fff; }
.btn-s { background: #fff; color: var(--text); border: 2px solid var(--border); }
.btn-d { background: var(--coral); color: #fff; }
.btn-m { background: var(--mint); color: var(--text); }

/* RÔLE : Variante discrète de .btn-s - pill plus petit, bordure fine, texte secondaire. */
/* POURQUOI : Phase 4 refonte boutons (2026-05-14) - résout la dette §8.2 de la charte    */
/*            (remplace .btn-export) et accueille les boutons d'action discrets de        */
/*            l'atelier (Vider, Motif). État actif via .is-active (texte + bold).         */
.btn-s.btn-s--discret {
  font-size: var(--fs-sm);
  font-weight: normal;
  padding: var(--sp-sm) var(--sp-md);
  border-width: 1px;
  color: var(--text2);
  background: none;
}
.btn-s.btn-s--discret.is-active {
  color: var(--text);
  font-weight: 700;
}

/* RÔLE : Bouton de choix de snack - emojis grands, fond carte, contour discret */
/* POURQUOI : Auparavant entièrement défini inline dans ui-settings.js (BD-09) -
              centralisé ici pour cohérence et réutilisabilité. */
.btn-snack {
  flex: 1;
  font-size: 32px;
  padding: var(--sp-md) 4px;
  background: var(--card);
  border: 2px solid var(--border);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: transform .15s;
}

/* RÔLE : Signaler visuellement qu'un bouton est désactivé (ex: quota IA atteint) */
/* POURQUOI : Sans ce style, un bouton disabled est visuellement identique à un actif → confusion TDAH */
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none !important; /* bloque l'animation :active */
}

.btn-boutique {
  background: linear-gradient(135deg, var(--lilac), var(--pink));
  color: #fff; font-size: 12px; padding: 10px 20px; border-radius: 12px;
  border-bottom: 3px solid rgba(0,0,0,.15); border-right: 2px solid rgba(0,0,0,.1);
  /* POURQUOI var(--lilac-rgb) : l'ombre du bouton boutique prolonge la couleur du dégradé lilac→pink */
  letter-spacing: .5px; box-shadow: 0 3px 10px rgba(var(--lilac-rgb), .4);
  transition: transform .12s, box-shadow .12s;
}
.btn-boutique:active {
  transform: translate(1px, 2px) scale(.96);
  border-bottom-width: 1px;
  /* POURQUOI var(--lilac-rgb) : cohérence avec l'état repos - ombre réduite mais même teinte */
  box-shadow: 0 1px 4px rgba(var(--lilac-rgb), .3);
}

/* ─── PICKERS & TOGGLES (rôle Navigation-Toggle, charte §3.5) ─────── */

/* RÔLE : Bouton d'un picker à choix unique (palette de couleurs, gomme, futurs pickers).  */
/* POURQUOI : Phase 4 refonte boutons (2026-05-14) - externalise les pastilles couleur et  */
/*            la gomme de l'atelier. La couleur de fond reste inline pour les couleurs     */
/*            (dynamique par essence). Taille pilotée par --btn-size posée sur le          */
/*            conteneur parent. État actif via .is-selected.                               */
/*            Cf. docs/CHARTE_BOUTONS.md §3.5 (Navigation-Toggle).                         */
.btn-pick {
  width: var(--btn-size, 32px);
  height: var(--btn-size, 32px);
  border-radius: 50%;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
  outline: 1px solid rgba(0, 0, 0, .18);
  outline-offset: 1px;
  transition: outline .12s, transform .12s;
}
.btn-pick.is-selected {
  outline: 3px solid var(--text);
  outline-offset: 3px;
}
.btn-pick:active { transform: scale(.94); }

/* RÔLE : .btn-add-slot supprimée le 2026-05-15 (cf. CHARTE_BOUTONS §8.3).                */
/* POURQUOI : orpheline depuis la refonte atelier mai 2026 - la carte « + Nouveau » de la */
/*            galerie est désormais .atelier-galerie-add (signature §4, plus bas).        */

/* ═════════════════════════════════════════════════════════════════ */
/* RÔLE : Étape 2 - habillage visuel de l'atelier (Phase Cowork mai 2026)  */
/* POURQUOI : ajoute une ambiance "atelier baigné de lumière" sans toucher */
/*            à la logique. Quatre classes : baseline, titres de section,  */
/*            cimaise de galerie, ombre sur vignettes.                    */
/* ═════════════════════════════════════════════════════════════════ */

/* RÔLE : baseline italique sous le titre "Atelier".                      */
/* POURQUOI : touche poétique discrète, ton chaleureux sans alourdir.     */
/*            display:flex + justify-content:space-between → les 3 mots   */
/*            s'étirent pile sur la largeur "emoji + titre Atelier".      */
.atelier-baseline {
  display: flex;
  justify-content: space-between;
  font-style: italic;
  font-size: 12px;
  color: var(--text2);
  margin-top: 1px;
  letter-spacing: .2px;
  opacity: .85;
}

/* RÔLE : titre de section discret (Palette / Tableaux).                  */
/* POURQUOI : small caps + letter-spacing → hiérarchie visuelle légère,  */
/*            sans surcharger la lecture.                                */
.atelier-section-title {
  text-transform: uppercase;
  font-size: 10px;
  letter-spacing: 1.4px;
  color: var(--text2);
  font-weight: 600;
  opacity: .75;
  margin-bottom: 6px;
  padding-left: 2px;
}

/* RÔLE : ombre portée discrète sous chaque vignette de la galerie.       */
/* POURQUOI : décollement visuel léger, lisibilité du contour amélioré.  */
.atelier-vignette {
  box-shadow: 0 2px 0 rgba(0, 0, 0, .08);
}

/* ═════════════════════════════════════════════════════════════════ */
/* RÔLE : Étape 3 - split Galerie / Studio (Pattern A)               */
/* POURQUOI : nouvelles classes structurelles pour les deux vues     */
/*            de l'atelier (Galerie comme hall, Studio plein écran). */
/* ═════════════════════════════════════════════════════════════════ */

/* RÔLE : header commun aux deux vues (Galerie + Studio).                 */
/* POURQUOI : alignement constant, bordure inférieure légère pour séparer */
/*            du contenu, padding identique au header de l'atelier v1.    */
.atelier-view-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px 8px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}

/* RÔLE : bouton "← Galerie" en haut à gauche du Studio.                  */
/* POURQUOI : symétrie visuelle avec le ✕ à droite (taille, style),       */
/*            tout en signalant clairement l'action retour.                */
.atelier-back {
  /* POURQUOI -webkit-appearance/text-fill-color : sur iOS Safari, le texte d'un <button>
     prend la teinte bleue système par défaut, qui prime sur `color`. On neutralise
     l'apparence native et on force la couleur du texte (fix bleu iOS 2026-05-30). */
  -webkit-appearance: none;
  appearance: none;
  background: none;
  border: none;
  color: var(--text);
  -webkit-text-fill-color: var(--text);
  font-size: 14px;
  font-family: var(--font-body);
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
  transition: background .12s;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
/* RÔLE : chevron « retour » dessiné en CSS (plus de caractère ←).
   POURQUOI : iOS rend la flèche U+2190 comme un emoji BLEU (même piège que le ✿,
   cf. @font-face plus haut), que `color`/`-webkit-text-fill-color` ne corrigent pas.
   Un chevron en bordures CSS est 100 % fiable et suit la couleur de texte du thème. */
.atelier-back::before {
  content: "";
  width: 7px;
  height: 7px;
  border-left: 2px solid var(--text);
  border-bottom: 2px solid var(--text);
  transform: rotate(45deg);
  flex: 0 0 auto;
}
.atelier-back:hover  { background: rgba(0, 0, 0, .05); }
.atelier-back:active { transform: scale(.96); }

/* RÔLE : grille de tuiles dans la vue Galerie (2 colonnes).              */
/* POURQUOI : grille responsive - 2 colonnes par défaut, vignettes        */
/*            carrées (aspect-ratio 1:1 hérité de l'élément interne).     */
.atelier-galerie-grid {
  display: grid;
  /* RÔLE : minmax(0, 1fr) - défense en profondeur F-01 cross-platform.
     POURQUOI : sans le min=0, le contenu interne (canvas pixel art + nom) peut
     forcer la colonne au-delà de 1fr et créer un overflow horizontal sur
     Android Chrome (rendu emoji Noto plus large qu'Apple Color Emoji). */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

/* RÔLE : tuile individuelle dans la vue Galerie.                         */
/* POURQUOI : on encapsule la vignette + le tap target dans une carte,    */
/*            avec un ratio carré et un cursor pointer pour signaler      */
/*            l'interactivité.                                            */
.atelier-galerie-tile {
  position: relative;
  cursor: pointer;
  aspect-ratio: 1 / 1;
  border-radius: 8px;
  /* POURQUOI bordure marquée + ombre douce (Étape 5 bis) :                 */
  /*   le frameBg des tableaux est proche du dégradé crème de l'overlay -   */
  /*   sans ces deux renforcements, les vignettes se fondaient dans le fond.*/
  /*   Bordure : trace nette du cadre. Ombre : effet "tableau accroché".    */
  border: 2px solid var(--border);
  box-shadow: 0 3px 8px rgba(0, 0, 0, .12);
  transition: transform .12s, box-shadow .12s;
}
.atelier-galerie-tile:active { transform: scale(.98); }

/* RÔLE : bouton croix de suppression sur chaque tuile (Étape 4).         */
/* POURQUOI : cercle sombre semi-transparent + ✕ blanc → lisible sur     */
/*            toutes les couleurs de tableaux. Position absolue en haut-  */
/*            gauche pour ne pas chevaucher le badge ⭐ en haut-droite.  */
.atelier-galerie-tile-delete {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, .45);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background .12s, transform .12s;
}
.atelier-galerie-tile-delete:hover  { background: rgba(0, 0, 0, .65); }
.atelier-galerie-tile-delete:active { transform: scale(.9); }

/* RÔLE : carte "+ Nouveau tableau" - placeholder pour la création.       */
/* POURQUOI : même format carré que les vignettes, bordure dashed pour    */
/*            signaler que c'est un slot vide à activer.                  */
.atelier-galerie-add {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  border-radius: 8px;
  border: 2px dashed var(--border);
  background: rgba(120, 80, 40, .03);
  cursor: pointer;
  color: var(--text2);
  font-size: 32px;
  font-family: var(--font-body);
  transition: border-color .12s, background .12s, transform .12s;
}
.atelier-galerie-add:hover  { border-color: var(--text2); background: rgba(120, 80, 40, .06); }
.atelier-galerie-add:active { transform: scale(.97); }

/* RÔLE : Slot verrouillé - emplacement de tableau pas encore débloqué (cf. ATELIER_SLOTS_REWARDS). */
/* POURQUOI : signale visuellement qu'il reste un palier à franchir + affiche l'indice "Encore X XP". */
/*            Non cliquable (pointer-events:none) - c'est un teaser, pas un bouton.                  */
.atelier-galerie-locked {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  aspect-ratio: 1 / 1;
  border-radius: 8px;
  border: 2px dashed var(--border);
  background: rgba(120, 80, 40, .02);
  color: var(--text2);
  opacity: 0.55;
  pointer-events: none;
}
.atelier-galerie-locked-icon { font-size: 28px; line-height: 1; }
.atelier-galerie-locked-hint { font-size: var(--fs-xs); text-align: center; padding: 0 6px; }

/* ═════════════════════════════════════════════════════════════════ */
/* RÔLE : Piste 2 - Mandala vivant (onglets atelier + bandeau pigments)      */
/* POURQUOI : tabbar persistante extensible (registre ATELIER_TABS) +        */
/*            bandeau de pigments responsive (flex-wrap) + zone canvas       */
/*            mandala carrée centrée. Cohérence visuelle avec l'esthétique  */
/*            "atelier baigné de lumière" (dégradé crème de l'overlay).      */
/* ═════════════════════════════════════════════════════════════════ */

/* RÔLE : header global de l'overlay atelier - titre + ✕ persistant.        */
/* POURQUOI : visible sur toutes les vues (galerie / mandala / studio) pour  */
/*            servir de repère permanent. Aligne titre à gauche et ✕ à droite */
/*            comme avant la refonte piste 2, mais désormais factorisé en un  */
/*            unique header au lieu d'être dupliqué dans chaque vue.          */
.atelier-global-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px 8px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}

/* RÔLE : tabbar horizontale en haut de l'overlay atelier.                  */
/* POURQUOI : scrollable horizontalement (overflow-x:auto) pour accueillir   */
/*            un nombre arbitraire d'onglets futurs (coloriage, zen art...).  */
/*            Quand peu d'onglets, justify-content:center équilibre. Quand   */
/*            trop, le contenu déborde et scrolle. Scrollbar masquée sur     */
/*            mobile pour rester épuré ; le pouce sert d'indicateur tactile. */
/* RÔLE : Tabbar de l'atelier - style "intercalaire de classeur" (4.8 ter).         */
/* POURQUOI : justify-content:flex-start → onglets alignés à gauche, comme des       */
/*            intercalaires. Scroll horizontal si débordement (extensibilité future).*/
/*            Padding-bottom à 0 pour que les onglets actifs "s'asseyent" sur la     */
/*            bordure basse - qui est désormais portée par les onglets eux-mêmes.    */
.atelier-tabbar {
  display: flex;
  align-items: flex-end;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
  padding: 6px 8px 0;
  gap: 2px;
  /* RÔLE : scroll horizontal uniquement, masqué tant qu'il n'y a que peu d'onglets.   */
  /* POURQUOI 4.8 duodecies : overflow-x:auto seul force le navigateur à passer        */
  /*   overflow-y en "auto" implicite (spec CSS) → un scrollbar vertical parasite      */
  /*   apparaît à cause du translateY(-2px) de l'onglet actif. overflow-y:hidden       */
  /*   explicite résout le problème. Scrollbar horizontal masqué via scrollbar-width   */
  /*   (Firefox), ::-webkit-scrollbar (Chrome/Safari) et -ms-overflow-style (Edge).    */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;        /* Firefox */
  -ms-overflow-style: none;     /* IE/Edge legacy */
  justify-content: flex-start;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.atelier-tabbar::-webkit-scrollbar { display: none; }

/* RÔLE : Onglet - style intercalaire de classeur (4.8 ter).                          */
/* POURQUOI : top-rounded (8px), bordures top/left/right, pas de bordure basse → l'   */
/*            onglet actif fusionne avec le contenu en dessous. Inactif = bordure     */
/*            haute discrète + fond léger. Actif = "tiré vers le haut" via            */
/*            translateY(-2px) + ombre + fond du contenu (transparent par dessus      */
/*            l'overlay crème), ce qui le détache des autres intercalaires.           */
.atelier-tab {
  flex: 0 0 auto;
  min-width: 80px;
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 9px 16px 8px;
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: 10px 10px 0 0;
  background: rgba(0, 0, 0, .025);
  color: var(--text2);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: transform .15s, color .15s, background .15s, box-shadow .15s;
  white-space: nowrap;
  margin-bottom: -1px; /* recouvre la bordure basse de la tabbar */
  /* RÔLE : ancrage absolu pour le badge "!" de signalement (4.8 duodecies). */
  /* POURQUOI : pendant strict du #badge-atelier sur le sticker menu - quand */
  /*   on ouvre l'atelier, le badge se "transmet" sur l'onglet concerné      */
  /*   (Galerie ou Mandala) pour qu'on comprenne d'où vient la modif.        */
  position: relative;
}
.atelier-tab:hover  { background: rgba(0, 0, 0, .05); color: var(--text); }
.atelier-tab:active { transform: scale(.98); }

/* RÔLE : Onglet actif - "tiré vers le haut" comme un intercalaire saillant.        */
/* POURQUOI : translateY(-2px) + ombre subtile vers le haut → effet relief. Fond    */
/*            transparent pour se fondre dans le contenu en dessous. Couleur texte  */
/*            renforcée. La bordure basse disparaît visuellement (cf. margin-bottom */
/*            qui recouvre la border-bottom de la tabbar).                          */
.atelier-tab.is-active {
  color: var(--text);
  background: transparent;
  transform: translateY(-2px);
  box-shadow: 0 -2px 6px rgba(0, 0, 0, .06);
  font-weight: 700;
}

.atelier-tab-label { font-size: 14px; }

/* RÔLE : pastille "!" rose sur un onglet - pendant du #badge-atelier du sticker menu. */
/* POURQUOI 4.8 duodecies : indique d'où vient la modif (nouveau slot débloqué →       */
/*   Galerie ; doses à déposer → Mandala). Mêmes dimensions et couleurs que le badge   */
/*   sticker pour cohérence visuelle. Positionnée top-right de l'onglet, en absolu.    */
.atelier-tab-badge {
  position: absolute;
  top: 2px;
  right: 4px;
  background: var(--pink);
  color: #fff;
  border-radius: 50%;
  width: 14px;
  height: 14px;
  font-size: var(--fs-xs);
  line-height: 14px;
  text-align: center;
  font-weight: 700;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .2));
  pointer-events: none;
}

/* RÔLE : cartel sous le canvas mandala - affiche l'âge du tableau + stats.          */
/* POURQUOI 4.8 nonies : transformé en vrai "cartel d'exposition" - fond crème,      */
/*            bordure fine, légère ombre. Le bloc s'adapte à la largeur du contenu   */
/*            (inline-block) pour ressembler à une vraie petite plaque posée sous    */
/*            l'œuvre. Les 2 sous-classes hiérarchisent : titre = jour, sous-ligne   */
/*            = pigments + pixels en plus petit / plus pâle.                          */
.mandala-age {
  display: inline-block;
  background: rgba(255, 255, 255, .55);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 5px 14px 6px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
  font-family: var(--font-body);
  text-align: center;
  letter-spacing: .3px;
  flex-shrink: 0;
}

/* RÔLE : ligne "titre" du cartel (Jour N ou Toile vierge). */
.mandala-age-jour {
  display: block;
  font-size: 12px;
  font-style: italic;
  font-weight: 500;
  color: var(--text);
  line-height: 1.2;
}

/* RÔLE : ligne "description" du cartel (X pigments · Y px). */
/* POURQUOI : plus petit et plus pâle que le titre - hiérarchie cartel musée. */
.mandala-age-stats {
  display: block;
  font-size: 10px;
  font-style: italic;
  color: var(--text2);
  opacity: .75;
  line-height: 1.2;
  margin-top: 1px;
}

/* RÔLE : Footer de la vue mandala - 2 lignes, alignées à droite (4.8 decies).      */
/* POURQUOI : cartel d'exposition placé au-dessus du bouton "Recommencer" (côté     */
/*            droit). Effet : la signature de musée est en regard de l'action de    */
/*            "fin" (recommencer = clôturer cette toile). align-items:flex-end →    */
/*            le cartel inline-block se cale à droite. La 2ᵉ ligne (boutons) garde  */
/*            sa largeur full grâce à width:100% sur .mandala-actions.              */
.mandala-footer {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  padding: 6px 16px calc(10px + env(safe-area-inset-bottom, 0px));
  flex-shrink: 0;
}

/* RÔLE : Conteneur des 2 boutons d'action mandala (atténuer + recommencer).         */
/* POURQUOI 4.8 octies : space-between + width:100% → "Atténuer" calé à gauche du   */
/*            footer, "Recommencer" calé à droite. Couplé à visibility:hidden       */
/*            (au lieu de display:none), "Recommencer" garde sa position quand      */
/*            "Atténuer" est masqué (cf. _mandalaUpdateActionsState).                */
.mandala-actions {
  display: flex;
  gap: var(--sp-sm);
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

/* RÔLE : Aide contextuelle one-shot d'un onglet atelier (Mandala / Symbiote).      */
/* POURQUOI : panneau inséré DANS #atelier-overlay (z-index:500) → il s'affiche      */
/*            par-dessus le contenu de l'atelier. La modale globale #modal (z-index   */
/*            300) passait dessous et n'apparaissait qu'à la fermeture de l'atelier.  */
/*            inset:0 le cale sur tout l'overlay ; z-index local au-dessus du contenu.*/
.atelier-help-overlay {
  position: absolute;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(56, 48, 74, 0.30);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  /* POURQUOI : l'overlay jardin (#canvas-fs-overlay) est pointer-events:none ; on réactive
     ici pour que le panneau reçoive le tap "Compris" et le clic à côté. */
  pointer-events: auto;
}
.atelier-help-card {
  background: var(--card, #fff);
  border-radius: 16px;
  padding: 20px 22px;
  max-width: 320px;
  width: 100%;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .22);
  text-align: center;
}
.atelier-help-card h3 {
  margin: 0 0 8px;
}
.atelier-help-card p {
  font-size: var(--fs-sm);
  color: var(--text2);
  line-height: 1.5;
  margin: 0 0 14px;
}

/* RÔLE : texte d'introduction au-dessus du contenu d'un onglet atelier.          */
/* POURQUOI : explique brièvement le contenu de l'onglet - symétrie entre Galerie  */
/*            et Mandala. Mêmes propriétés visuelles : italic, --text2, centré,    */
/*            padding sobre. .mandala-intro garde l'alias pour rétro-compat.       */
.atelier-intro,
.mandala-intro {
  font-family: var(--font-body);
  font-size: 13px;
  font-style: italic;
  color: var(--text2);
  text-align: center;
  line-height: 1.45;
  padding: 12px 18px 8px;
  flex-shrink: 0;
  /* RÔLE : réserve la hauteur de 3 lignes pour que tous les onglets de l'atelier  */
  /* aient le même espace d'intro, qu'elle fasse 2 ou 3 lignes (évite que la zone  */
  /* canvas saute en hauteur d'un onglet à l'autre). 3 × 1.45em = hauteur 3 lignes. */
  min-height: calc(3 * 1.45em);
  box-sizing: content-box;
}

/* RÔLE : bandeau de pigments dans la vue Mandala - grille 3 colonnes équilibrée. */
/* POURQUOI : 3 colonnes pour répartir les 6 pigments en 2 lignes de 3, layout    */
/*            calme et équilibré. overflow-y:auto pour rester scrollable si on   */
/*            ajoute des pigments un jour, ou si l'écran est très petit.         */
/*            max-height = 45vh pour ne pas écraser la zone canvas en-dessous.    */
/* RÔLE : Bandeau de pigments dans la vue Mandala (4.8 quater).                       */
/* POURQUOI : grille 3 colonnes × 2 lignes - équilibre visuel des 6 pigments.         */
/*            Chaque item compacté en hauteur via wrapper top (pastille + compteur    */
/*            sur la même ligne), label en-dessous. Padding minimal, plus de          */
/*            max-height : le bandeau prend juste la place qu'il faut.                */
.mandala-pigment-bar {
  display: grid;
  /* RÔLE : minmax(0, 1fr) - F-01 défense en profondeur. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
  padding: 8px 10px;
  flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}

/* RÔLE : item individuel - pastille à gauche, bloc texte (compteur + label) à droite. */
/* POURQUOI 4.8 duodecies : flex row + align-items:center → tout tient sur la hauteur  */
/*   d'une pastille (~28px). Plus de respiration verticale pour la toile en dessous.   */
/*   État vide (compteur=0) = opacity réduite. État actif (pigment sélectionné) =      */
/*   bordure + fond léger (cf. .is-active plus bas).                                   */
.mandala-pigment-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 5px 10px;
  border-radius: 10px;
  border: 1.5px solid transparent;
  /* RÔLE : Fond très subtil pour matérialiser visuellement le groupe pastille+texte. */
  /* POURQUOI 4.8 sexies : sans fond, les éléments d'un même pigment "flottent" - on  */
  /*   ne sait pas si le chiffre va avec la pastille de gauche ou de droite. Fond     */
  /*   quasi-imperceptible mais suffisant pour délimiter la zone du groupe.           */
  background: rgba(0, 0, 0, .03);
  transition: opacity .15s, border-color .15s, background .15s;
  min-width: 0;
}

/* RÔLE : bloc texte à droite de la pastille - compteur en haut, label en dessous.      */
/* POURQUOI 4.8 duodecies : empile verticalement les deux métadonnées du pigment        */
/*   (quantité numérique + mot poétique) tout en restant aligné avec la pastille en     */
/*   hauteur. min-width:0 indispensable pour que ellipsis du label fonctionne dans      */
/*   une cellule de grille étroite (iPhone SE).                                         */
.mandala-pigment-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1px;
  min-width: 0;
  line-height: 1.1;
}
.mandala-pigment-item.is-empty   { opacity: .4; }

/* RÔLE : la pastille active émet un halo de la couleur du pigment.            */
/* POURQUOI : onde qui irradie depuis le cercle puis s'estompe - façon         */
/*            mandala. Teinte fournie par --pigment-color (variable CSS        */
/*            inline injectée dans ui-mandala.js §4). color-mix(in oklab,...)  */
/*            génère les paliers d'opacité de façon perceptuellement uniforme  */
/*            (cohérent avec le futur algo OKLCH du mélange étape 5/6).        */
/*            prefers-reduced-motion respecté pour l'accessibilité.            */
.mandala-pigment-item.is-active .mandala-pigment-dot {
  animation: mandalaPulse 1.6s ease-in-out infinite;
}

@keyframes mandalaPulse {
  0%, 100% {
    box-shadow:
      inset 0 0 0 1px rgba(0, 0, 0, .12),
      0 1px 2px rgba(0, 0, 0, .12),
      0 0 0 0 color-mix(in oklab, var(--pigment-color, #000) 65%, transparent);
  }
  50% {
    box-shadow:
      inset 0 0 0 1px rgba(0, 0, 0, .12),
      0 1px 2px rgba(0, 0, 0, .12),
      0 0 0 12px color-mix(in oklab, var(--pigment-color, #000) 0%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .mandala-pigment-item.is-active .mandala-pigment-dot {
    animation: none;
    box-shadow:
      inset 0 0 0 1px rgba(0, 0, 0, .12),
      0 1px 2px rgba(0, 0, 0, .12),
      0 0 0 3px color-mix(in oklab, var(--pigment-color, #000) 75%, transparent);
  }
}

/* RÔLE : pastille colorée - disque de la couleur du pigment.                */
/* POURQUOI : 32px en grille 3 colonnes (~100px de large par cellule),       */
/*            assez visible pour identifier la couleur d'un coup d'œil.      */
/*            Bordure subtile sombre pour gérer le cas des pigments clairs.   */
.mandala-pigment-dot {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .12);
}

/* RÔLE : libellé de la catégorie sous la pastille.                          */
/* POURQUOI : texte explicite ("Sport", "Nutrition"...) pour qu'on comprenne */
/*            de quel pigment on parle, au-delà de la simple couleur. line-height */
/*            serré et ellipsis si le mot dépasse (rare, mais sécurise).          */
.mandala-pigment-label {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.1;
  text-align: left;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* RÔLE : compteur de doses sous le label.                                  */
/* POURQUOI : valeur numérique seule (sans suffixe "dose" - trop long). Tabular */
/*            nums pour stabilité visuelle entre "9" et "99+". Opacity légèrement */
/*            réduite pour hiérarchie : pastille > label > compteur.              */
/* RÔLE : Compteur de doses du pigment (4.8 quinquies - allègement typographique).    */
/* POURQUOI : version précédente trop "concurrente" avec la pastille (gros, gras).    */
/*            Italic + poids moyen + opacité réduite → le compteur devient une        */
/*            annotation discrète, la pastille reprend le rôle visuel principal.      */
/*            Tabular-nums préserve l'alignement vertical entre "9" et "12".          */
.mandala-pigment-count {
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 500;
  font-style: italic;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
  opacity: .60;
}

/* ═════════════════════════════════════════════════════════════════ */
/* RÔLE : Étape 5 - barre d'outils du Studio (pinceau, bucket, undo, grille) */
/* POURQUOI : sépare les outils des couleurs. Boutons carrés en flex.        */
/* ═════════════════════════════════════════════════════════════════ */

/* RÔLE : barre d'outils en grille 4 colonnes × 2 rangées (Étape 5 bis).  */
/* POURQUOI : 7 outils regroupés par fonction -                           */
/*            Ligne 1 (outils de tracé) : ✏️ pinceau · 🪣 bucket · 🧹 gomme · ↶ undo */
/*            Ligne 2 (modificateurs + grille) : 🌑 foncer · ☀️ éclaircir · ⊞ grille */
/*            La 4e colonne de la ligne 2 reste vide (grid-column:span 1). */
.atelier-toolbar {
  display: grid;
  /* RÔLE : minmax(0, 1fr) - F-01 défense en profondeur. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

/* RÔLE : bouton d'outil individuel - pinceau / bucket / undo / grille.   */
/* POURQUOI : flex:1 pour répartition égale ; police plus grande pour      */
/*            l'emoji ; states active/disabled.                           */
.atelier-tool {
  flex: 1;
  min-height: 36px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, .35);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background .12s, border-color .12s, transform .12s, opacity .12s;
}
.atelier-tool:hover  { background: rgba(255, 255, 255, .55); }
.atelier-tool:active { transform: scale(.94); }

/* RÔLE : état actif d'un bouton d'outil (outil courant / grille visible). */
/* POURQUOI : fond contrasté pour signaler clairement la sélection.       */
.atelier-tool.is-active {
  background: var(--text);
  color: #fff;
  border-color: var(--text);
}

/* RÔLE : état désactivé (undo sans snapshot disponible).                 */
/* POURQUOI : signale visuellement que le bouton n'est pas actionnable.   */
.atelier-tool.is-disabled {
  opacity: .35;
  cursor: not-allowed;
}
.atelier-tool.is-disabled:hover  { background: rgba(255, 255, 255, .35); }
.atelier-tool.is-disabled:active { transform: none; }

/* RÔLE : paire segmentée pinceau + bucket - les deux modes de tracé mutuellement
   exclusifs, présentés joints (« choisis l'un des deux ») sur 2 colonnes de la grille.
   POURQUOI : les distinguer des outils isolés (gomme, annuler, modificateurs). */
.atelier-tool-pair {
  grid-column: span 2;
  display: flex;
}
.atelier-tool-pair .atelier-tool {
  flex: 1;
  border-radius: 0;
}
.atelier-tool-pair .atelier-tool:first-child  { border-radius: 8px 0 0 8px; }
.atelier-tool-pair .atelier-tool:last-child   { border-radius: 0 8px 8px 0; border-left: none; }

/* Le bouton « ✦ Effacer » du symbiote utilise le style actif générique
   .btn-s.btn-s--discret.is-active (identique à l'atténuer du mandala) - rien à surcharger. */


/* ─── SYSTÈME 4 : MOTEUR DE ROUTINE (Les Habitudes) ──────────────── */

/* RÔLE : Rangée de 6 badges visuels - récap des habitudes du jour, non-cliquables */
/* POURQUOI : Vue d'ensemble instantanée avant de lire la liste détaillée */
.hab-mini-bar {
  display: flex;
  justify-content: center;
  gap: 12px;
  padding: 4px var(--sp-md) 20px; /* POURQUOI : même padding latéral que .card et #hab-home */
}

/* RÔLE : Badge individuel - cercle brillant avec reflet, lecture seule */
/* POURQUOI : L'aspect "badge décoratif" (pas de bordure, reflet brillant) signale visuellement
   que ce n'est pas un bouton - contrairement à un contour net qui évoque l'interactivité */
.hab-mini {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 19px;
  background: radial-gradient(circle at 40% 35%, rgba(255,255,255,0.18) 0%, rgba(176, 144, 208, 0.18) 60%, rgba(176, 144, 208, 0.08) 100%);
  border: none;                /* Supprimé - une bordure nette évoque un bouton cliquable */
  position: relative;          /* Ancre le pseudo-élément de reflet */
  overflow: hidden;            /* Confine le reflet dans le cercle */
  flex-shrink: 0;
  pointer-events: none;        /* Non-cliquable */
  user-select: none;
  transition: background 0.3s ease;
}

/* RÔLE : Reflet brillant - bande lumineuse dans le tiers supérieur du badge */
/* POURQUOI : Effet "badge en verre" → décoratif, pas interactif */
.hab-mini::after {
  content: '';
  position: absolute;
  top: 4px;
  left: 8px;
  width: 55%;
  height: 35%;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.45);
  filter: blur(2px);
  pointer-events: none;
}

/* RÔLE : État coché - fond vert brillant, reflet conservé */
.hab-mini.done {
  background: radial-gradient(circle at 40% 35%, rgba(255,255,255,0.25) 0%, rgba(128, 208, 168, 0.55) 55%, rgba(100, 180, 140, 0.35) 100%);
}

/* Bloc Habitude */
.hab {
  display: flex; align-items: center; gap: var(--sp-sm); padding: var(--sp-sm) var(--sp-md); border-radius: var(--r-md); min-width: 0;
  /* POURQUOI margin-bottom var(--sp-md) : le label Prochain ✿ en ::before dépasse de ~12px au-dessus - l'espace
     entre habitudes doit compenser pour que le label ne chevauche pas le bloc précédent */
  /* POURQUOI : fond lilas très doux sans bordure - respire mieux, moins de bruit visuel */
  /* POURQUOI var(--lilac-rgb) : le fond d'habitude suit la teinte principale du thème */
  border: none; margin-bottom: var(--sp-md); background: rgba(var(--lilac-rgb), 0.09); cursor: pointer;
  transition: transform 0.1s ease;
  position: relative; /* POURQUOI : nécessaire pour que ::before se positionne par rapport au .hab */
}
.hab:active { transform: scale(0.97); } /* Petit écrasement au clic */

/* État Validé */
/* POURQUOI : sans bordure, on garde juste le fond vert doux pour signaler la complétion */
/* POURQUOI var(--lilac-rgb) : le côté lilas du dégradé de validation suit la palette - le vert (--mint fixe) reste stable */
.hab.done {
  background: linear-gradient(135deg, rgba(128,208,168,.18), rgba(var(--lilac-rgb), .12));
}

/* La Checkbox vide */
.hab .ck {
  width: 24px; height: 24px; border-radius: 6px; border: 2px solid var(--border);
  display: flex; align-items: center; justify-content: center; font-size: 14px; color: transparent;
  transition: background 0.2s, border-color 0.2s;
}

/* L'animation magique s'applique quand la classe 'done' est ajoutée */
.hab.done .ck {
  background: var(--mint); border-color: var(--mint); color: #fff;
  animation: popBounce 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}

@keyframes popBounce {
  0%   { transform: scale(0.5); opacity: 0; }
  50%  { transform: scale(1.2); opacity: 1; }
  100% { transform: scale(1); }
}

/* RÔLE : Rebond doux sur le label XP et la barre quand on gagne de l'XP */
/* POURQUOI : popBounce part de scale(0.5) - trop brutal pour un élément déjà affiché.
              xpBounce part de scale(1) et fait un léger overshoot avant de revenir. */
@keyframes xpBounce {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.12); }
  70%  { transform: scale(0.96); }
  100% { transform: scale(1); }
}
.xp-gained {
  animation: xpBounce 0.45s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
@media (prefers-reduced-motion: reduce) {
  .xp-gained { animation: none; }
}

/* RÔLE : Met en évidence la prochaine habitude à cocher */
/* POURQUOI : Sans signal visuel, l'utilisatrice doit scanner toute la liste pour trouver quoi faire
   - coût décisionnel élevé au démarrage, incompatible avec la fatigue TDAH */
@keyframes halo-pulse {
  /* POURQUOI : pulsation sur le seul box-shadow, pas de déplacement -
     évite le saut de layout et reste doux sur les yeux en journée */
  /* POURQUOI var(--lilac-rgb) : le halo animé doit pulser dans la couleur du thème actif */
  0%, 100% { box-shadow: 0 0 0 3px rgba(var(--lilac-rgb), 0.20); }
  50%       { box-shadow: 0 0 0 6px rgba(var(--lilac-rgb), 0.42); }
}
.hab--next {
  /* POURQUOI : pas de border-color (bordure supprimée) - le glow animé + fond plus intense suffisent */
  /* POURQUOI var(--lilac-rgb) : fond de mise en avant cohérent avec le halo animé - même couleur, même thème */
  background: rgba(var(--lilac-rgb), 0.16);
  animation: halo-pulse 2.4s ease-in-out infinite;
}
.hab--next .ck {
  border-color: var(--lilac);
}
/* Petit label "À faire" discret au-dessus de la checkbox */
/* POURQUOI top: -11px : le label doit flotter juste au-dessus du bord supérieur du bloc .hab */
.hab--next::before {
  content: 'Prochaine';
  position: absolute;
  top: -11px;
  left: 8px;
  font-size: var(--fs-xs); /* était 9px hardcodé - aligné avec la variable */
  font-weight: bold;
  color: var(--lilac);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  pointer-events: none;
  background: var(--card); /* POURQUOI : léger fond pour rester lisible sur n'importe quelle palette */
  padding: 0 5px;
  border-radius: 3px;
}

/* RÔLE : Habitude vedette du jour - léger glow doré pour la distinguer */
/* POURQUOI : Signal doux, non anxiogène - juste une suggestion de priorité */
.hab--vedette {
  box-shadow: 0 0 0 2px rgba(245,158,11,0.30);
  background: rgba(245,158,11,0.07);
}

/* ─── SLIDERS DE LA BOTTOM SHEET "COMMENT TU TE SENS ?" ─────────── */
/* RÔLE : Couleur d'accentuation des contrôles natifs (cases à cocher, radios, et le
          slider de volume des réglages).
   POURQUOI : sans accent-color, l'état coché / le remplissage du slider prend le bleu
              système (visible surtout sur iOS). On force la palette de l'app (lilas)
              pour une cohérence iOS + desktop. Les sliders d'humeur (#etats-sheet) sont
              entièrement custom (appearance:none) → ils ignorent accent-color, pas d'impact. */
input[type=checkbox],
input[type=radio],
input[type=range] {
  accent-color: var(--lilac);
}

/* RÔLE : Thumb rond pour les sliders énergie/bonheur dans la modale d'états.
   POURQUOI : Les sliders sont dans une bottom sheet dynamique (ouvrirModalEtats).
              On réinitialise complètement l'apparence webkit pour contrôler track + thumb. */

#etats-sheet input[type=range] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 6px;                        /* hauteur du track */
  border-radius: 3px;
  background: var(--border);
  outline: none;
  cursor: pointer;
  margin: 0;
  padding: 0;
  display: block;
}

/* Track webkit - nécessaire pour que la hauteur soit respectée sur iOS */
#etats-sheet input[type=range]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: var(--border);
}

/* Thumb webkit - disque plein, bien centré sur le track */
/* POURQUOI : margin-top = -(thumbH - trackH)/2 = -(28-6)/2 = -11px pour centrer verticalement */
/* POURQUOI IDs séparés : énergie = --mood-energy (gold), bonheur = --mood-happy (violet) */
#modal-sl-energy::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--mood-energy);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.18);
  cursor: pointer;
  margin-top: -11px;
}
#modal-sl-happy::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--mood-happy);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.18);
  cursor: pointer;
  margin-top: -11px;
}

/* Firefox */
#modal-sl-energy::-moz-range-thumb {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--mood-energy);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.18);
  cursor: pointer;
}
#modal-sl-happy::-moz-range-thumb {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--mood-happy);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,0.18);
  cursor: pointer;
}
#etats-sheet input[type=range]::-moz-range-track {
  height: 6px;
  border-radius: 3px;
  background: var(--border);
}

/* Barre d'XP */
/* RÔLE : Piste de la barre XP - fond en damier de petits cubes pixel art vides */
/* POURQUOI : repeating-linear-gradient simule des cubes 8px séparés de 2px, sans image externe */
.pbar {
  height: 12px;
  border-radius: 2px;
  overflow: hidden;
  background: repeating-linear-gradient(
    90deg,
    rgba(var(--lilac-rgb), 0.12) 0px 8px,
    transparent              8px 10px
  );
}
/* RÔLE : Remplissage de la barre XP - cubes pleins gradient lilac→pink */
/* POURQUOI : Le rebond .64,1 donne un ressenti "vivant" à chaque gain d'XP */
.pfill {
  height: 100%;
  border-radius: 2px;
  transition: width .6s cubic-bezier(.34, 1.56, .64, 1);
  background: repeating-linear-gradient(
    90deg,
    var(--lilac) 0px 8px,
    var(--pink)  8px 10px
  );
}
.slbl { font-size: var(--fs-xs); font-weight: bold; text-transform: uppercase; letter-spacing: 1px; color: var(--text2); } /* était 9px */


/* ─── SYSTÈME 6 : INTROSPECTION & MÉMOIRE ────────────────────────── */

/* Le Journal Années 90 */
.j90 {
  background: var(--paper-bg); border: 3px solid var(--paper-border); border-radius: var(--r-sm); padding: var(--sp-md);
  box-shadow: inset 0 2px 8px rgba(0,0,0,.06);
}
/* RÔLE : Override spécifique au journal - garde le style papier (bordure, couleur) sans redéfinir font/size/align */
.j90 h2 {
  border-bottom: 2px dashed var(--paper-border);
  padding-bottom: var(--sp-xs);
  color: var(--paper-text);
}
/* RÔLE : Zone de saisie du journal - italic Nunito pour une écriture plus intime */
#j-text, #edit-j-txt {
  font-family: var(--font-gotchi);
  font-style: italic;
  font-weight: 400;
}

/* RÔLE : Couleur papier ivoire et taille de texte spécifiques au champ journal.
   POURQUOI : styles précédemment en inline (BD-05) - déplacés ici pour respecter
              la cascade et permettre les overrides thématiques. */
#j-text {
  background: #faf6f0;
  border-color: #c8b8a0;
  font-size: 12px;
}

/* RÔLE : Texte des entrées affichées - même registre italic doux */
.j-entry .j-text-content {
  font-family: var(--font-gotchi);
  font-style: italic;
  font-weight: 400;
}

/* RÔLE : Entrée de journal - fond légèrement teinté selon l'humeur, fade-in à l'apparition */
/* POURQUOI : Rend chaque note visuellement distincte et donne un retour immédiat de l'humeur choisie */
.j-entry {
  padding: var(--sp-sm); border: 1px dashed var(--paper-border); margin-bottom: var(--sp-sm);
  border-radius: var(--r-sm); background: var(--paper-entry);
  animation: jEntryFadeIn .25s ease both;
}
@keyframes jEntryFadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* RÔLE : Teinte de fond selon l'humeur - très douce pour ne pas écraser le contenu */
.j-entry.mood-super { background: rgba(255, 240, 160, 0.35); }
.j-entry.mood-bien  { background: rgba(160, 230, 180, 0.30); }
.j-entry.mood-ok    { background: rgba(200, 200, 220, 0.25); }
.j-entry.mood-bof   { background: rgba(200, 180, 220, 0.30); }
.j-entry.mood-dur   { background: rgba(200, 160, 160, 0.28); }

/* RÔLE : En-tête d'entrée - humeur grande à gauche, heure petite à droite */
.j-entry-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--sp-xs);
}
/* RÔLE : Icône d'humeur mise en avant - taille expressive, pas un détail */
.j-entry-mood {
  font-size: 24px;
  line-height: 1;
}
/* RÔLE : Heure de l'entrée - discrète, secondaire par rapport à l'humeur */
.j-entry .j-date {
  font-size: var(--fs-xs);
  color: var(--paper-entry-ts);
}
/* RÔLE : Séparateur visuel entre l'humeur et le texte - dashed pour rester dans l'esthétique papier */
.j-entry-divider {
  border: none;
  border-top: 1px dashed var(--paper-border);
  margin: var(--sp-xs) 0;
}
/* RÔLE : Actions édition/suppression - alignées à droite, cibles tactiles agrandies */
/* POURQUOI : Les ~24px d'origine étaient trop petits (audit C3.2), on monte à 44px min (recommandation Apple HIG) */
.j-entry .j-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-xs);
  margin-top: var(--sp-xs);
}
/* RÔLE : .j-entry .j-actions button - boutons ✏️/🗑️ sur chaque entrée du journal.    */
/* POURQUOI : Phase 3 refonte boutons (2026-05-14, décision D5 Option B) - entièrement   */
/*            absorbée par la variante .btn-icon--square du shell ghost-icône plus haut. */
/*            Les anciens fond/bordure « papier » ont disparu - cohérence visuelle avec  */
/*            .rdv-action-btn (qui porte les mêmes ✏️/🗑️ ailleurs dans l'app).          */

/* RÔLE : Séparateur visuel de date dans la liste des entrées - distingue les notes du même jour */
/* POURQUOI : Quand plusieurs notes sont écrites le même jour, il faut un repère visuel clair */
.j-day-sep {
  font-size: var(--fs-xs); color: var(--paper-text); font-family: var(--font-body);
  text-align: center; letter-spacing: 1px; margin: 10px 0 6px;
  display: flex; align-items: center; gap: 6px;
}
.j-day-sep::before, .j-day-sep::after {
  content: ''; flex: 1; height: 1px; background: var(--paper-border);
}
/* RÔLE : Retirer les pseudo-éléments ::before/::after quand le séparateur est un accordéon cliquable */
/* POURQUOI : Le header accordéon a déjà un layout flex avec label + compteur + chevron -
              les lignes décoratives before/after entreraient en conflit avec le text-align:left */
.j-day-sep.j-day-toggle::before, .j-day-sep.j-day-toggle::after { display: none; }
/* RÔLE : Feedback visuel hover sur le header d'accordéon */
.j-day-sep.j-day-toggle:hover { opacity: 0.75; }

/* RÔLE : Classe .btn-export - supprimée. */
/* POURQUOI : Phase 4 refonte boutons (2026-05-14) - dette §8.2 de la charte résolue.    */
/*            Tous les usages migrés vers .btn-s.btn-s--discret (variante du rôle        */
/*            Secondaire). Cf. style.css au-dessus pour la définition de la variante.    */

/* RÔLE : Switchers à onglets (boutique Catalogue/Créations, agenda Jour/Mois/Cycle) */
/* POURQUOI : padding:7px seul donnait ~30px - sous les 44px recommandés Apple HIG */
/* AUDIT 6.1 : min-height 44px, styles inline externalisés */
.tab-switcher-btn {
  flex: 1;
  min-height: 44px;
  padding: 0 4px;
  border-radius: 999px;
  border: none;
  font-size: var(--fs-sm);
  font-weight: bold;
  font-family: var(--font-body);
  cursor: pointer;
  transition: .15s;
  display: flex;
  align-items: center;
  justify-content: center;
  /* RÔLE : état par défaut (inactif) - fond transparent, texte secondaire */
  /* POURQUOI : QW2 audit boutons 2026-05-14 - externalisé depuis style= inline JS */
  background: transparent;
  color: var(--text2);
  box-shadow: none;
}
/* RÔLE : état actif d'un onglet sélectionné - fond blanc, accent lilac */
/* POURQUOI : aligne le pattern sur .mood-b.sel (état via classe, pas via style= inline) */
.tab-switcher-btn.is-active {
  background: #fff;
  color: var(--lilac);
  box-shadow: 0 1px 4px rgba(0,0,0,.1);
}

/* RÔLE : Boutons switcher d'environnement dans l'inventaire */
/* POURQUOI : Phase 2 refonte boutons (2026-05-14) - états actif/inactif via classe         */
/*            .is-active au lieu de 4 propriétés style= inline JS. Nuance de couleur par    */
/*            biome conservée via la custom property --biome-rgb posée côté JS (cf.         */
/*            _updInvEnvSwitcher dans ui-shop.js).                                          */
/*            Cf. docs/CHARTE_BOUTONS.md §3.5 (Navigation-Toggle).                          */
.inv-env-btn {
  --biome-rgb: 224, 224, 224; /* fallback gris neutre si hexToRgb échoue côté JS */
  flex: 1;
  min-height: 44px;
  padding: 0 2px;
  border-radius: 999px;
  border: none;
  background: rgba(var(--biome-rgb), 0.1);
  color: var(--text);
  font-size: 1.35rem; /* emoji-only : taille augmentée (était var(--fs-xs) prévu pour du texte) */
  font-weight: normal;
  box-shadow: none;
  cursor: pointer;
  transition: background .15s, box-shadow .15s, font-weight .15s;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.inv-env-btn.is-active {
  background: rgba(var(--biome-rgb), 0.25);
  box-shadow: inset 0 0 0 2.5px rgb(var(--biome-rgb));
  font-weight: bold;
}

/* RÔLE : Icône PNG biome dans le switcher d'environnement de l'inventaire */
/* POURQUOI : image-rendering:pixelated - net à toutes les tailles, pointer-events:none - le clic passe au bouton parent */
.env-icon-img {
  width: 32px;
  height: 32px;
  image-rendering: pixelated;
  pointer-events: none;
  display: block;
}

/* RÔLE : .rdv-action-btn - boutons ✏️/🗑️ sur les items RDV de l'agenda. */
/* POURQUOI : Phase 3 refonte boutons (2026-05-14) - entièrement absorbée par la variante */
/*            .btn-icon--square du shell ghost-icône factorisé plus haut. Aucune          */
/*            particularité à conserver - la classe reste utilisée côté HTML/JS pour la   */
/*            sémantique (l'ancien nom est conservé pour ne pas casser le code existant). */

/* RÔLE : Boutons emoji du formulaire de création/édition de RDV (BD-14). */
/* POURQUOI : Le conteneur est passé en flex-wrap - flex:0 0 auto empêche les boutons     */
/*            de se rétrécir. min-width/height garantissent la cible tactile 44×44.        */
/*            Le sélecteur cible les boutons [data-emoji] à l'intérieur de #rdv-sheet.    */
#rdv-sheet [data-emoji] {
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 auto;
}

/* Le Code PIN du Journal */
.pin-dots { display: flex; gap: 10px; justify-content: center; margin: 12px 0; }
.pin-dot { width: 14px; height: 14px; border-radius: 50%; border: 3px solid var(--border); transition: .2s; }
.pin-dot.f { background: var(--lilac); border-color: var(--lilac); }
/* RÔLE : minmax(0, 1fr) - F-01 défense en profondeur. */
.pin-pad { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; max-width: 200px; margin: 0 auto; }
.pin-k {
  aspect-ratio: 1; border-radius: 12px; border: 2px solid var(--border); background: #fff;
  font-size: 18px; font-weight: bold; font-family: var(--font-terminal); color: var(--text); cursor: pointer;
  display: flex; align-items: center; justify-content: center; transition: .12s;
}
.pin-k:active { background: var(--border); transform: scale(.9); }

/* ─── SYSTÈME 7 : RÉGLAGES COLLAPSIBLES ──────────────────────────── */
/* RÔLE : Sections pliables dans #p-settings pour réduire la surcharge décisionnelle */
/* POURQUOI : 8 cartes visibles d'un coup = overload cognitif. <details> natif = 0 JS nécessaire */
details.settings-section {
  background: var(--card);
  border: 2px solid var(--border);
  border-radius: 14px;
  margin-bottom: 10px;
  overflow: hidden;
}
details.settings-section > summary {
  padding: 14px 16px;
  font-weight: bold;
  font-size: var(--fs-sm);
  cursor: pointer;
  list-style: none; /* supprime le triangle natif */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  user-select: none;
}
details.settings-section > summary::-webkit-details-marker { display: none; }
/* RÔLE : Le chevron SVG est injecté par initChevronSettings() dans ui.js,
   pour être cohérent avec les autres chevrons de l'app.
   La rotation à l'ouverture est gérée par la transition CSS sur la classe .settings-chevron. */
details.settings-section > summary .settings-chevron { display: flex; flex-shrink: 0; transition: transform .2s; }
details.settings-section[open] > summary .settings-chevron { transform: rotate(180deg); }
details.settings-section > summary:active { background: rgba(0,0,0,.04); }
.settings-body {
  padding: 0 16px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* RÔLE : Intertitre de sous-groupe dans une section de Réglages */
/* POURQUOI : hiérarchiser un bloc qui mélange plusieurs familles d'actions sans alourdir */
.settings-subhead {
  margin: 4px 0 -2px;
  font-size: var(--fs-xs);
  font-weight: bold;
  color: var(--text2);
}
/* RÔLE : Filet de séparation discret entre deux sous-groupes de Réglages */
.settings-rule {
  width: 100%;
  height: 0;
  margin: 2px 0;
  border: none;
  border-top: 1px solid var(--border);
}
/* Danger zone : bordure rouge sur la section */
details.settings-section.danger { border-color: var(--danger); }
details.settings-section.danger > summary { color: var(--danger); }

/* Calendrier (Vue Progression) */
/* RÔLE : minmax(0, 1fr) - F-01 défense en profondeur (même classe de risque
   que vue mois agenda résolue Vague 1 Batch 1.9). */
.cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; }

.cal-c {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-xs); /* était 9px - numéros de jours du calendrier */
  font-weight: bold;
}

.cal-c-mini {
  width: 100%;
  aspect-ratio: 7/4;
  border-radius: 3px;
  font-size: 0;
}
.nav-r { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }

/* RÔLE : Cible tactile des chevrons SVG de navigation (journal + progress).
   POURQUOI (BD-15) : les <span> chevrons faisaient ~34px - sous la recommandation
   Apple HIG (44×44px). On force la taille minimale sans toucher au markup. */
.nav-r > span {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.nav-a {
  /* RÔLE : Boutons ◀▶ de navigation semaine/journal */
  /* POURQUOI : Étendus à 44×44px pour respecter la recommandation Apple HIG et éviter les fausses touches */
  min-width: 44px; min-height: 44px; border-radius: 8px; border: 2px solid var(--border); background: #fff; /* était 28×28 */
  font-size: 12px; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--text2);
}
.nav-a:active { background: var(--border); }

/* Picker d'Humeur (Saisie du journal) */
/* AUDIT 6.1 : cible portée à 44×44px (était 42×42, sous les recommandations Apple HIG) */
.mood-b {
  width: 44px; height: 44px; border-radius: 10px; border: 3px solid var(--border); background: #fff;
  font-size: 20px; cursor: pointer; transition: .2s; display: flex; align-items: center; justify-content: center;
}
/* POURQUOI var(--lilac-rgb) : fond de sélection de l'emoji humeur suit la couleur d'accentuation du thème */
.mood-b.sel { border-color: var(--lilac); background: rgba(var(--lilac-rgb), .1); transform: scale(1.1); }
#mood-pick.mood-required .mood-b { animation: shakeRow .4s ease; border-color: var(--danger); } /* était #e57373 hardcodé */
@keyframes shakeRow { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-4px)} 75%{transform:translateX(4px)} }


/* ─── SYSTÈME 7 : SYSTÈME D'ONGLETS & MODALES ────────────────────── */

/* Gestion des onglets SPA (Single Page Application) */
.pnl { display: none; animation: fu .2s ease; }
.pnl.on { display: block; }
@keyframes fu {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* RÔLE : Animation d'ouverture de la boîte modale - montée douce sans scale */
/* POURQUOI : translateY seul évite le clipping causé par overflow-y:auto + transform scale */
@keyframes modalPop {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
.modal-box.modal-pop {
  animation: modalPop .22s cubic-bezier(0.25, 1.15, 0.5, 1) both;
}

/* RÔLE : Centrage des titres h3 dans toutes les modales */
/* POURQUOI : Les h3 sont générés dynamiquement dans ui.js avec des styles inline variés -
              une règle CSS globale évite de modifier chaque occurrence en JS */
.modal-box h3 {
  text-align: center;
}

/* Modale Principale (Alertes, Boutique) */
/* RÔLE : pointer-events:auto explicite - garantit que la zone semi-transparente capte
   les taps même sur mobile (p5.js attachant ses listeners au document, pas au canvas).
   POURQUOI : Sans cet attribut, un tap sur le fond semi-transparent pouvait traverser
              jusqu'aux éléments HTML de #dynamic-zone derrière la modale. */
/* POURQUOI : sélecteur #modal (id) plutôt que .modal (class) - élément unique dans le DOM,
   l'id suffit. La class="modal" a été retirée du HTML (index.html) pour éviter la redondance. */
/* RÔLE : -webkit-backdrop-filter dupliqué - iOS Safari 15/16/17 ne reconnaît pas la version standard.
   POURQUOI : audit cross-platform 2026-05-18 F-07 - sans préfixe, le fond reste opaque sur iOS 15-17. */
#modal {
  position: fixed; inset: 0; background: rgba(56, 48, 74, 0.4); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  z-index: 300; display: flex; align-items: center; justify-content: center; padding: 16px;
  pointer-events: auto;
}
.modal-box {
  background: #fff; border-radius: var(--r-lg); padding: var(--sp-lg); max-width: 340px; width: 100%;
  box-shadow: 0 16px 40px rgba(56, 48, 74, 0.2);
  position: relative; /* POURQUOI : nécessaire pour positionner le .modal-close en absolute */
  max-height: 85dvh; overflow-y: auto; /* POURQUOI : empêche les modales longues de déborder hors écran */
  touch-action: pan-y; /* POURQUOI : autorise le scroll tactile vertical - sinon p5.js intercepte les touch events et bloque le scroll sur mobile */
}

/* RÔLE : Famille Ghost-Icône - boutons discrets transparents (✕, ✏️, 🗑️).            */
/* POURQUOI : Phase 3 refonte boutons (2026-05-14) - factorise le shell commun de       */
/*            .modal-close, .hdr-garden-close, .rdv-action-btn, .j-entry .j-actions     */
/*            button. Les classes spécifiques ne portent plus que leurs particularités. */
/*            Variante --square pour les ghost qui cohabitent avec une ligne (radius    */
/*            doux + hover plus subtil). Cf. docs/CHARTE_BOUTONS.md §3.6.                */
.btn-icon,
.modal-close,
.hdr-garden-close,
.rdv-action-btn,
.j-entry .j-actions button {
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  border: none;
  background: none;
  color: var(--text2);
  font-size: var(--fs-lg);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: background .15s, transform .12s;
  flex-shrink: 0;
}

/* Hover/active des ronds - .btn-icon, .modal-close, .hdr-garden-close */
/* RÔLE : :hover encadré dans @media (hover: hover) - PROBLÈME 2.
   POURQUOI : sur tactile (iOS Safari, Android), le browser simule un :hover au tap
   qui reste collé jusqu'à un tap ailleurs → croix qui garde son fond gris après
   fermeture/retour au sélecteur. La media query restreint :hover aux vrais pointeurs
   (souris desktop) - le feedback tactile reste via :active ci-dessous. */
@media (hover: hover) {
  .btn-icon:hover,
  .modal-close:hover,
  .hdr-garden-close:hover {
    background: var(--border);
  }
}
.btn-icon:active,
.modal-close:active,
.hdr-garden-close:active {
  background: var(--border);
  transform: scale(.9);
}

/* Variante carrée - radius doux, hover subtil (cohabite avec une ligne RDV ou entrée journal) */
.btn-icon--square,
.rdv-action-btn,
.j-entry .j-actions button {
  border-radius: var(--r-sm);
}
.btn-icon--square:hover,
.rdv-action-btn:hover,
.j-entry .j-actions button:hover {
  background: rgba(0, 0, 0, .05);
}
.btn-icon--square:active,
.rdv-action-btn:active,
.j-entry .j-actions button:active {
  background: rgba(0, 0, 0, .05);
  transform: scale(.9);
}

/* RÔLE : .modal-close - particularité = position absolue haut/droite */
/* POURQUOI : Sans lui, la seule façon de fermer est de taper à côté - piège UX sur mobile */
.modal-close {
  position: absolute;
  top: 10px;
  right: 10px;
}

.meteo-badge { font-size: var(--fs-xs); color: var(--text2); text-align: center; margin-top: 2px; } /* était 9px */

#update-banner {
  display: none; position: fixed; top: var(--sat); left: 0; right: 0; z-index: 1001; /* était 999 - passé à 1001 pour couvrir les boutons .hdr et #etats-overlay (1000) */
  height: calc(44px + 4px + 6px); /* RÔLE : même hauteur que le .hdr - boutons 44px + padding .hdr (2px×2) + padding-top #console-top (6px) */
  line-height: calc(44px + 4px + 6px); /* POURQUOI : centrage vertical sans flex - compatible avec banner.style.display='block' dans sw.js */
  background: var(--mint); color: #fff; text-align: center; font-size: var(--fs-sm); /* padding: 8px remplacé par height+line-height fixes */
  font-weight: bold; cursor: pointer;
}

/* Toast non-bloquant (Messages éphémères) */
#toast {
  position: fixed;
  bottom: calc(70px + var(--sab));
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: rgba(56, 48, 74, 0.88);
  color: #fff;
  padding: 8px 18px;
  border-radius: 20px;
  font-size: var(--fs-sm); /* était 11px - les toasts sont des messages à lire */
  font-family: var(--font-body);
  z-index: 500;
  opacity: 0;
  transition: opacity .3s, transform .3s;
  pointer-events: none;
  white-space: normal;
  max-width: calc(100vw - 40px);
  text-align: center;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* RÔLE : Variantes typées du toast - succès, danger, warning */
/* POURQUOI : Un seul style neutre ne permet pas de distinguer une confirmation d'une erreur.
              Les variables sémantiques --success / --danger / --warning sont maintenant utilisées. */
#toast.toast--success { background: var(--success); color: var(--text); }
#toast.toast--danger  { background: var(--danger);  color: #fff; }
#toast.toast--warning { background: var(--warning); color: var(--text); }

/* RÔLE : État de chargement standardisé sur les boutons IA */
/* POURQUOI : Chaque appel IA animait sa propre zone texte de façon ad hoc.
              .is-loading bloque le bouton et signale visuellement l'attente
              via un ✿ qui tourne juste après le texte du bouton. */
@keyframes flowerSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.btn.is-loading {
  pointer-events: none;
  opacity: 0.65;
}
.btn.is-loading::after {
  content: ' ✿';
  display: inline-block; /* RÔLE : nécessaire pour que transform fonctionne sur le pseudo-élément */
  animation: flowerSpin 1s linear infinite;
  transform-origin: center;
}
@media (prefers-reduced-motion: reduce) {
  .btn.is-loading::after { animation: none; content: ' ✿'; }
}


/* ─── SYSTÈME 6 : LE TERMINAL (Événements Cachés) ────────────────── */

/* RÔLE : Animation d'ouverture de la tablette - slide depuis le coin supérieur droit */
/* POURQUOI : @keyframes tabletOpen était référencé dans #tablet-box mais jamais défini -
              la tablette s'ouvrait donc sans transition (bug silencieux). */
@keyframes tabletOpen {
  from { opacity: 0; transform: scale(0.9) translateY(-8px); }
  to   { opacity: 1; transform: scale(1)   translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  #tablet-box { animation: none; }
}

#tablet-overlay {
  /* RÔLE : position/inset/pointer-events hérités de .app-overlay (ajouté dans index.html).
     POURQUOI : #tablet-overlay est à z-index:400 - au-dessus de .modal (300).
                Sans pointer-events:auto, une bande en haut de l'écran (padding-top)
                laissait les taps atteindre les boutons de #console-top derrière. */
  display: none; z-index: 400;
  background: rgba(0,0,0,.5); align-items: flex-start; justify-content: flex-end;
  padding: calc(var(--sat) + 48px) 12px 0 12px;
}
#tablet-overlay.open { display: flex; }

#tablet-box {
  background: var(--terminal-box); border: 2px solid var(--terminal-border); border-radius: 12px; width: 100%;
  max-width: 340px; max-height: 70dvh; display: flex; flex-direction: column;
  transform-origin: top right; animation: tabletOpen .2s ease-out; overflow: hidden;
}
#tablet-screen {
  background: var(--terminal-screen); margin: 10px; border-radius: 6px; border: 1px solid var(--terminal-screen-border);
  padding: 10px; overflow-y: auto; flex: 1;
  font-family: var(--font-terminal); font-size: var(--fs-sm); color: var(--terminal-text);
}
.tablet-line { margin-bottom: 6px; line-height: 1.4; border-bottom: 1px solid var(--terminal-line-div); padding-bottom: 6px; }
.tablet-line .tablet-time { color: var(--terminal-text-dim); font-size: var(--fs-xs); display: block; }
.tablet-line .tablet-icon { margin-right: 4px; }
#tablet-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 12px 4px; color: var(--terminal-text); font-family: var(--font-terminal);
  font-size: var(--fs-sm); border-bottom: 1px solid var(--terminal-border);
}



/* ─── ANIMATIONS SPÉCIFIQUES (Boutique & Météo) ──────────────────── */

@keyframes shopOpen {
  0%   { transform: scale(0.85) translateY(12px); opacity: 0; }
  60%  { transform: scale(1.03) translateY(-3px); opacity: 1; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}
.modal-box.shop-open {
  animation: shopOpen 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.modal-box.shop-open.shop-catalogue {
  display: flex;
  flex-direction: column;
  height: auto;
  max-height: 85dvh;
}

.modal-box.shop-open:not(.shop-catalogue) {
  display: block;
  height: auto;
  max-height: 85dvh;
  overflow-y: auto;
}

#boutique-contenu {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  padding-right: 4px;
  scrollbar-width: none; /* Firefox */
  touch-action: pan-y; /* POURQUOI : autorise le scroll tactile vertical dans la boutique sur mobile */
}

#boutique-contenu::-webkit-scrollbar {
  display: none; /* Chrome, Safari, mobile */
}

/* Agenda : hauteur fixe avec scroll interne (comme boutique catalogue) */
.modal-box.shop-open.agenda-open {
  display: flex;
  flex-direction: column;
  height: auto;
  max-height: 85dvh;
}

#agenda-contenu {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  padding-right: 4px;
  scrollbar-width: none;
  touch-action: pan-y; /* POURQUOI : autorise le scroll tactile vertical dans l'agenda sur mobile */
}

#agenda-contenu::-webkit-scrollbar {
  display: none;
}

/* RÔLE : Légende de la vue mois - 2 colonnes × 2 lignes, icônes et labels alignés */
/* POURQUOI : L'ancien flex-wrap désalignait les 4 items selon la largeur de l'écran.  */
/*            grid-template-columns:1fr 1fr force exactement 2 colonnes à taille égale. */
.legend-mois {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 16px;
}
.legend-mois > div {
  display: flex;
  align-items: center;
  gap: 6px;
  justify-content: flex-start;
}

@keyframes tamaSway {
  0%   { transform: rotate(0deg); }
  25%  { transform: rotate(0.5deg); }
  75%  { transform: rotate(-0.5deg); }
  100% { transform: rotate(0deg); }
}
@keyframes tamaSwayStrong {
  0%   { transform: rotate(0deg); }
  25%  { transform: rotate(1.5deg); }
  75%  { transform: rotate(-1.5deg); }
  100% { transform: rotate(0deg); }
}
.tama-wind { animation: tamaSway 1.4s ease-in-out infinite; }
.tama-wind-strong { animation: tamaSwayStrong 0.9s ease-in-out infinite; }

/* RÔLE : Empêche le texte long de déborder des modales */
/* POURQUOI : Ces 2 propriétés flottaient hors de toute règle CSS - elles étaient ignorées silencieusement par le navigateur */
.modal-box {
  word-break: break-word;
  overflow-wrap: break-word;
}

/* Masquer l'icône native des inputs time (agenda) */
input[type="time"]::-webkit-calendar-picker-indicator {
  opacity: 0;
  position: absolute;
  right: 0;
  top: 0;
  width: 100%;
  height: 100%;
  cursor: pointer;
  margin: 0;
  padding: 0;
}

input[type="time"] {
  position: relative;
  cursor: pointer;
}

@keyframes slideUp {
  from { transform: translateY(100%); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

/* ─── ACCESSIBILITÉ : RÉDUCTION DES ANIMATIONS ───────────────────── */
/* RÔLE : Respecter le réglage iOS "Réduire les animations" et les préférences système */
/* POURQUOI : Critique pour les troubles vestibulaires, le TDAH et la fatigue sensorielle */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}


/* ─── SYSTÈME 5 : CANVAS PLEIN ÉCRAN ─────────────────────────────── */

/*
  RÔLE : Overlay full-viewport qui couvre toute l'UI quand on ouvre le jardin en plein écran.
  POURQUOI inset:0 (au lieu de bottom:0) : couvre tout le viewport, pas juste le bas.
  POURQUOI z-index 800 : entre #tablet-overlay (400) et #etats-overlay (1000).
  POURQUOI fond palette app : cohérent avec --bg, légèrement teinté lilas via color-mix().
  Le canvas reste dans #console-top - body.garden-fullscreen le fait passer au-dessus (z:850).
*/
.canvas-fullscreen-overlay {
  position: fixed;
  inset: 0;
  z-index: 800;
  /* RÔLE : Fond beige sable - évoque la terre du jardin.
     POURQUOI #E8D5B5→#F0E0C6 : palette humus, cohérente avec GND_BASE (#8B6B47)
     du sol p5.js, sans écraser les couleurs vives des espèces dans le canvas. */
  background: linear-gradient(
    180deg,
    #E8D5B5 0%,
    #F0E0C6 100%
  );
  display: none;
  /* POURQUOI pointer-events:none : l'overlay est purement décoratif (fond coloré).
     La fermeture se fait uniquement via le bouton ✕ dans .hdr-garden.
     Sans ça, l'overlay z:800 intercepte tous les taps et bloque le bouton. */
  pointer-events: none;
  transform: translateY(100%);
  transition: transform 0.35s cubic-bezier(0.25, 1.15, 0.5, 1);
}
/* RÔLE : État ouvert - slide up depuis le bas */
.canvas-fullscreen-overlay.open {
  display: block;
  transform: translateY(0);
}

/* RÔLE : Supprimé - la poignée ne fait plus sens sur un overlay full-viewport */
.canvas-fullscreen-overlay::before {
  display: none;
}

/* RÔLE : Header jardin - masqué par défaut, visible uniquement en mode garden-fullscreen */
/* RÔLE : Header jardin - masqué par défaut, visible en mode plein écran seulement */
/* POURQUOI dans #console-top (flex column) : il s'insère naturellement avant le tama */
.hdr-garden {
  display: none;
  width: 100%;
  max-width: 420px;
  padding-bottom: 4px;
}
body.garden-fullscreen .hdr-garden {
  display: block;
  /* POURQUOI position:relative + z-index:2 : p5.js attache ses listeners au document entier,
     ce qui intercepte les taps avant les éléments DOM normaux. En créant un nouveau contexte
     de stacking au-dessus du canvas (.tama-shell z:1), le bouton ✕ reçoit les événements. */
  position: relative;
  z-index: 2;
  pointer-events: auto;
}

/* RÔLE : Titre h2 - même style que les h2 de .modal-box (boutique, agenda) */
/* POURQUOI #3A2810 : couleur terre sombre, lisible sur fond parchemin #E8D5B5 */
.hdr-garden-title {
  font-family: var(--font-title);
  font-size: 20px;
  font-weight: 700;
  color: #3A2810;
  letter-spacing: 0.3px;
  margin: 0;
}

/* RÔLE : Conteneur interne du header jardin - même structure qu'atelier-view-header.
   POURQUOI border-bottom #C4A882 : trait de séparation en brun parchemin cohérent
   avec la palette terre, à la place de var(--border) lilas. */
.hdr-garden-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 4px 8px;
  flex-shrink: 0;
  border-bottom: 1px solid #C4A882;
  width: 100%;
}

/* RÔLE : Baseline justifiée sous le titre - miroir de .atelier-baseline.
   POURQUOI justify-content:space-between sur 3 spans : les mots s'étirent
   sur la largeur exacte du titre (icon + "Mon jardin") - effet typographique
   de bloc justifié sans CSS complexe.
   POURQUOI #8B6B47 (GND_BASE) au lieu de var(--text2) lilas : palette terre. */
.garden-baseline {
  display: flex;
  justify-content: space-between;
  font-style: italic;
  font-size: 12px;
  color: #8B6B47;
  margin-top: 1px;
  letter-spacing: 0.2px;
  opacity: 0.85;
}

/* RÔLE : .hdr-garden-close - particularité = flux normal + garanties tactiles iOS. */
/* POURQUOI : Phase 3 - shell ghost-icône factorisé dans .btn-icon plus haut.        */
/*            Classe séparée de .modal-close parce que .modal-close est intercepté   */
/*            par clModal() qui vérifie e.target.id==='modal' - hors contexte        */
/*            #modal ça ne fonctionne pas. Ne reste que les spécificités de contexte.*/
.hdr-garden-close {
  position: static;
  pointer-events: auto;    /* garantit la réception des taps même si un parent a pointer-events:none */
  touch-action: manipulation; /* évite le délai 300ms iOS sur les boutons */
}

/*
  RÔLE : Quand le plein écran jardin est actif, #console-top passe au-dessus de l'overlay
  et est reconfiguré pour afficher le tama à la même position qu'en accueil normal.
  POURQUOI z-index 850 : dépasse l'overlay (800) mais reste sous #etats-overlay (1000).
  POURQUOI bottom:0 : étend la console sur tout le viewport pour que l'étiquette jardin
  remplisse l'espace sous le canvas.
  POURQUOI même padding que l'accueil : le tama reste exactement à sa place habituelle.
*/
body.garden-fullscreen #console-top {
  z-index: 850;
  /* RÔLE : Fond beige sable - continuité avec .canvas-fullscreen-overlay (option A). */
  background: #E8D5B5;
  border-bottom: none;
  box-shadow: none;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* RÔLE : Même padding que l'accueil normal - le tama ne bouge pas */
  padding-top: calc(var(--sat) + 6px);
  padding-left: var(--app-gutter);
  padding-right: var(--app-gutter);
  padding-bottom: 0;
}

/* RÔLE : Phase de préparation - masque l'UI dès le tap, AVANT que garden-fullscreen soit posé.
   POURQUOI : garden-fullscreen était posé immédiatement au tap pour éviter le flash UI, mais
              sa règle `margin-top: 0 !important` sur #tama-bubble-wrap annulait instantanément
              la transition compact (margin-top:-48px → 0), empêchant transitionend de se déclencher.
              garden-preparing masque l'UI sans toucher à #tama-bubble-wrap : la transition CSS
              se déroule normalement, et garden-fullscreen n'est posé qu'une fois margin-top=0. */
body.garden-preparing .hdr,
body.garden-preparing .bubble,
body.garden-preparing #compact-tab-label,
body.garden-preparing #hab-progress-bar {
  display: none !important;
}
body.garden-preparing #dynamic-zone,
body.garden-preparing .menu-languette {
  display: none !important;
}
/* RÔLE : Masque le tama pendant la transition compact (400ms) - il réapparaît en fondu
          une fois le layout stabilisé, à sa taille finale.
   POURQUOI : En mode compact, #tama-shell-main a max-width:220px + une transition CSS.
              Quand compact est retiré, le tama grossit de 220px → sa taille normale pendant
              400ms - visuellement il "arrive du coin gauche". Le masquer pendant ce temps
              et le révéler seulement dans _doOpen() donne le même résultat qu'une ouverture
              depuis l'onglet accueil (tama déjà à taille finale). */
body.garden-preparing #tama-shell-main {
  opacity: 0;
}

/* RÔLE : Masque le header normal et la bulle - remplacés par .hdr-garden */
body.garden-fullscreen .hdr,
body.garden-fullscreen .bubble,
body.garden-fullscreen #compact-tab-label,
body.garden-fullscreen #hab-progress-bar {
  display: none !important;
}

/* RÔLE : Masque les éléments UI hors #console-top */
body.garden-fullscreen #dynamic-zone,
body.garden-fullscreen .menu-languette {
  display: none !important;
}

/* RÔLE : Libère le wrapper tama de ses décalages compact - retour position neutre.
   POURQUOI pas de margin-top:0 !important ici : quand garden-fullscreen est posé,
   la transition est déjà terminée (margin-top vaut déjà 0). Le !important n'est plus
   nécessaire et son absence évite d'interférer avec de futures transitions. */
body.garden-fullscreen #tama-bubble-wrap {
  width: 100%;
  max-width: 420px;
}

/* RÔLE : Le shell occupe toute la largeur disponible */
body.garden-fullscreen .tama-shell {
  max-width: 100%;
  padding: 0;
  margin: 0;
}

/* RÔLE : Coins plus arrondis + contour brun bois en plein écran jardin */
/* POURQUOI border-color #8B6B47 : cohérent avec GND_BASE (sol p5.js) - l'écran
   semble encadré dans du bois, ancré dans la palette terre de l'onglet. */
body.garden-fullscreen .tama-screen {
  border-radius: 14px;
  border-width: 2px;
  border-color: #8B6B47;
}

/* ── Conteneur injecté dans #console-top (flex column) ──────────── */
.canvas-fs-info {
  width: 100%;
  max-width: 420px;
  margin: 8px auto 0;
  padding: 0 0 calc(env(safe-area-inset-bottom, 0px) + 10px);
  flex: 1;
  display: flex;
  align-items: stretch;
  overflow: hidden; /* POURQUOI : clip le contenu - le scroll est géré par .garden-label-scroll */
  min-height: 0;    /* POURQUOI : flexbox shrink correct dans un parent flex column */
}

/* ── Carte étiquette jardin ──────────────────────────────────────── */
/* RÔLE : Fond parchemin + bordure brun - évoque une étiquette botanique kraft.
   POURQUOI #F5ECD8 + #C4A882 : palette terre chaude en cohérence avec
   le sol p5.js (GND_BASE #8B6B47) et le fond overlay #E8D5B5. */
.garden-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #F5ECD8;
  border: 1.5px solid #C4A882;
  border-radius: var(--r-lg);
  overflow: hidden;
  min-height: 0;
}
/* RÔLE : Header identité + footer phrase - fond légèrement plus soutenu (#EFE0C8)
   pour encadrer le contenu sans alourdir. */
.garden-label > .garden-label-section:first-child {
  background: #EFE0C8;
}

/* ── Zone scrollable : Composition + Aujourd'hui ───────────────── */
/* RÔLE : Seul ce bloc défile - le nom (haut) et la vitalité/phrase (bas) restent ancrés */
/* POURQUOI flex:1 + min-height:0 : prend tout l'espace disponible entre les deux blocs fixes */
/* POURQUOI -webkit-overflow-scrolling:touch : scroll momentum fluide sur iOS */
/* POURQUOI lockScroll() n'a pas besoin d'être modifié : il remonte les ancêtres du touchmove
   et laisse passer dès qu'il trouve overflowY=auto avec scrollHeight>clientHeight */
.garden-label-scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  min-height: 0;
}

/* ── Section = bloc avec padding interne ───────────────────────── */
.garden-label-section {
  padding: 9px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* RÔLE : Section Composition - fond légèrement teinté pour la distinguer visuellement */
/* POURQUOI : donner une hiérarchie subtile sans border supplémentaire */
/* POURQUOI plus de flex:1/min-height:0/overflow:hidden : le scroll est géré par
   .garden-label-scroll - la section prend sa hauteur naturelle sans se comprimer */
.garden-label-section:nth-child(2) {
  /* RÔLE : Légère teinte terre sur la 2e section (Vitalité) pour la distinguer */
  background: rgba(139, 107, 71, 0.05);
}

/* ── Titre de section - petit label majuscule discret ──────────── */
.garden-label-section-title {
  font-family: var(--font-body);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: #8B6B47;
  margin-bottom: 4px;
}
/* RÔLE : Modificateur Composition - titre plus grand pour une section inventaire
   POURQUOI 13px + letter-spacing réduit : suffisant pour affirmer la hiérarchie
   sans écraser les lignes de variantes (10px) juste en dessous. */
.garden-label-section-title--lg {
  font-size: 13px;
  letter-spacing: 0.3px;
  text-transform: none;
  margin-bottom: 7px;
}

/* ── Nom du jardin ──────────────────────────────────────────────── */
.garden-label-name {
  font-family: var(--font-title);
  font-size: 18px;
  font-weight: 700;
  color: #3A2810;
  line-height: 1.2;
}

/* ── Seed + âge - style numéro de série botanique ───────────────── */
/* POURQUOI font-terminal + #8B6B47 : évoque une étiquette de pépinière
   avec son numéro de référence - monospace discret sur fond parchemin. */
.garden-label-meta {
  font-family: var(--font-terminal, monospace);
  font-size: var(--fs-xs);
  color: #8B6B47;
  font-weight: 400;
  letter-spacing: 0.5px;
}

/* ── Séparateur pointillé pixel-art ────────────────────────────── */
/* POURQUOI #C4A882 : brun clair parchemin - ligne de démarcation sans rupture */
.garden-label-divider {
  height: 1px;
  flex-shrink: 0;
  background: repeating-linear-gradient(
    to right,
    #C4A882 0px,
    #C4A882 4px,
    transparent 4px,
    transparent 8px
  );
}

/* ── Ligne de données : icône + texte ──────────────────────────── */
.garden-label-row {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  color: #4A3520;
  line-height: 1.4;
  min-width: 0; /* POURQUOI : permet au texte de tronquer plutôt que de déborder */
}
.garden-label-row span:last-child {
  flex: 1;
  min-width: 0;
  word-break: break-word;
  overflow-wrap: anywhere;
}
/* Lignes par type - légèrement indentées, texte un poil plus petit */
/* RÔLE : Différencier visuellement les lignes de sous-détail de la ligne principale */
/* POURQUOI : var(--text) était identique aux lignes normales - pas de hiérarchie lisible */
.garden-label-row--sub {
  padding-left: 2px;
  font-size: 10px;    /* plus petit que var(--fs-xs) = 11px - vraiment discret */
  color: #7B5B3C;     /* brun intermédiaire (GND_MID) - hiérarchie lisible sur parchemin */
}
/* Ligne total - badge récapitulatif */
/* RÔLE : Bloc "Vue d'ensemble" - lecture globale du cycle de vie du jardin.
   POURQUOI bloc séparé avec border-top : marque visuellement que c'est une
   synthèse de tout ce qui précède, pas une ligne de détail supplémentaire.
   POURQUOI padding-top 10px : espace généreux pour détacher du reste de la liste. */
.garden-label-row--global {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 12px;
  padding: 10px 10px 8px;
  background: rgba(139, 107, 71, 0.07);
  border-radius: 8px;
  border: 0.5px solid #C4A882;
}
/* RÔLE : Label "Vue d'ensemble" - petit titre explicatif au-dessus de la phrase */
.garden-label-global-prefix {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: #8B6B47;
}
/* RÔLE : Phrase dynamique (ex. "La plupart des plantes sont en pleine croissance") */
/* POURQUOI 13px + italic : taille lisible, ton légèrement contemplatif - distingue
   cette synthèse narrative des informations techniques de la liste. */
.garden-label-global-txt {
  font-size: 13px;
  font-style: italic;
  font-weight: 500;
  color: #3A2810;
  line-height: 1.4;
}

/* ── Icône de chaque ligne ──────────────────────────────────────── */
.gli {
  flex-shrink: 0;
  width: 18px;
  text-align: center;
  font-size: 13px;
  margin-top: 1px;
}

/* ── Section footer : phrase contemplative - fixe en bas ────────── */
/* RÔLE : Section footer - fond parchemin soutenu + padding généreux.
   POURQUOI #EFE0C8 : même teinte que le header → encadrement symétrique
   de l'étiquette (haut/bas foncés, contenu central clair). */
.garden-label-section--footer {
  gap: 0;
  padding-bottom: 14px;
  background: #EFE0C8;
}

/* ── Vitalité : barre globale + état court ──────────────────────── */
.garden-label-vitality {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

/* ── Barres ▓░ - deux tailles ───────────────────────────────────── */
/* RÔLE : taille normale pour la barre globale, petite pour les deux détails */
/* POURQUOI #639922 : vert végétal - les barres de vitalité évoquent la pousse */
.garden-label-bars {
  font-family: var(--font-terminal);
  font-size: 13px;
  color: #639922;
  letter-spacing: 1px;
  white-space: nowrap;
  flex-shrink: 0;
}
.garden-label-bars--sm {
  font-size: 10px;
  letter-spacing: 0.5px;
}

/* ── État court (Épanoui / En forme…) ───────────────────────────── */
/* POURQUOI #3A6B2A : vert forêt sombre - contraste lisible sur #F5ECD8 */
.garden-label-state {
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: #3A6B2A;
  flex: 1;
  min-width: 0;
}

/* ── Détail vitalité : deux lignes 🌱 / 💜 ──────────────────────── */
/* RÔLE : Bloc des deux sous-jauges (Routines + Bien-être) qui composent la barre globale.
   POURQUOI border-left #C4A882 : marque visuellement que ces deux lignes sont des
   sous-composantes de la barre du dessus - elles s'y additionnent, elles ne sont pas
   indépendantes. La ligne verticale relie visuellement les détails à leur résultante.
   POURQUOI margin-top 6px : espace généreux entre la grande barre et le détail. */
.garden-label-vitality-detail {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: 6px;
  margin-bottom: 8px;
  padding-left: 10px;
  border-left: 2px solid #C4A882;
}
.garden-label-vitality-row {
  display: flex;
  align-items: center;
  gap: 7px;
}
.garden-label-vitality-icon {
  font-size: 11px;
  width: 16px;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
/* RÔLE : Label court (Routines / Bien-être) - identifie chaque sous-jauge.
   POURQUOI pas text-transform:uppercase : "BIEN-ÊTRE" cassait en deux lignes
   à cause du tiret + contrainte de largeur. Casse normale = plus court à l'écran.
   POURQUOI width:56px : "Bien-être" est le label le plus long - 56px suffit sans wrap. */
.garden-label-vitality-label {
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 700;
  color: #8B6B47;
  letter-spacing: 0.1px;
  width: 56px;
  flex-shrink: 0;
  line-height: 1.2;
}
.garden-label-vitality-lbl {
  font-family: var(--font-body);
  font-size: 10px;
  color: #7B5B3C;
  flex: 1;
  min-width: 0;
}

/* ── Phrase narrative vitalité ──────────────────────────────────── */
/* RÔLE : 1-2 phrases expliquant l'état du jardin avec contexte */
/* POURQUOI border-left #C4A882 : même ton que les séparateurs - brun parchemin */
.garden-label-phrase {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  color: #7B5B3C;
  line-height: 1.5;
  word-break: break-word;
  padding: 7px 10px;
  background: rgba(139, 107, 71, 0.07);
  border-radius: 8px;
  border-left: 2px solid #C4A882;
}

/* ── Ligne graines souterraines ─────────────────────────────────── */
/* RÔLE : signale les plantes en germination invisible sous terre */
/* POURQUOI #8B6B47 + opacity 0.75 : discret mais lisible sur parchemin */
.garden-label-row--seeds {
  font-size: var(--fs-xs);
  color: #8B6B47;
  opacity: 0.75;
  margin-top: 4px;
  font-style: italic;
}

/* ── Phrase contemplative - bas de carte ────────────────────────── */
/* POURQUOI text-align:center : la phrase est le dernier mot du jardin -
   centrée sur fond #EFE0C8, elle ressemble à l'inscription d'une étiquette. */
.garden-label-about {
  font-style: italic;
  color: #7B5B3C;
  font-size: var(--fs-xs);
  line-height: 1.5;
  word-break: break-word;
  text-align: center;
}

/*
  RÔLE : Bouton ✕ de fermeture - coin supérieur droit, en position fixed pour rester
  ancré même si l'overlay flex scroll (ne scrolle pas mais sécurité).
  POURQUOI z-index 851 : au-dessus de #console-top (850) - toujours cliquable.
  POURQUOI style palette app : cohérent, pas de blanc-sur-noir.
*/
.canvas-fs-close {
  position: fixed;
  top: calc(var(--sat) + 10px);
  right: 16px;
  z-index: 851;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  background: var(--card);
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.15s;
  box-shadow: 0 1px 4px var(--shadow);
}
.canvas-fs-close:active { transform: scale(0.9); background: var(--border); }


/* ─── SYSTÈME JEUX (Hub mini-jeux) ───────────────────────────────── */

/* RÔLE : Conteneur du hub - prend toute la hauteur disponible pour le carrousel */
/* POURQUOI flex column : on empile [carrousel] + [dots] verticalement dans la hauteur */
#game-hub {
  display: flex;
  flex-direction: column;
  flex: 1;          /* POURQUOI : occupe tout l'espace vertical de #game-main */
  min-height: 0;    /* POURQUOI : flex item doit pouvoir rétrécir sous sa taille intrinsèque */
  padding: var(--sp-sm) 0 0;
}

/* RÔLE : Piste scroll-snap horizontale - une carte visible à la fois, peek des voisines */
/* POURQUOI scroll-snap et non JS : fluide nativement sur iOS, pas de jank */
.game-carousel {
  display: flex;
  flex: 1;               /* POURQUOI : occupe toute la hauteur disponible dans #game-hub */
  min-height: 0;
  overflow-x: scroll;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;  /* POURQUOI : momentum scroll iOS */
  gap: var(--sp-sm);
  padding: var(--sp-sm) 40px;  /* POURQUOI : 40px de peek de chaque côté */
  /* POURQUOI masquer la scrollbar : visuellement propre - le peek signale déjà le scroll */
  scrollbar-width: none;
}
.game-carousel::-webkit-scrollbar {
  display: none;
}

/* ─── Couleurs par jeu (bandeau + dégradé illustration) ───────────── */
/* RÔLE : Variables CSS posées sur chaque carte selon data-jeu-id - consommées par
          .game-card-header et .game-card-illustration */
/* POURQUOI variables sur la carte et non des classes séparées : un seul sélecteur
   par jeu au lieu de dupliquer toutes les règles - plus DRY et plus lisible */

/* cristaux : violet lilas */
.game-card[data-jeu-id="cristaux"] {
  --card-theme:  #9a70c8;          /* POURQUOI : violet saturé mais pas criard - lisible sur blanc */
  --card-grad-a: #e8dcf8;          /* POURQUOI : lilas très clair - fond haut de la zone illustration */
  --card-grad-b: #cdb8ef;          /* POURQUOI : lilas médium - fond bas, dégradé doux */
  --card-border: rgba(154, 112, 200, 0.55);
}

/* bulles : bleu ciel aqua */
.game-card[data-jeu-id="bulles"] {
  --card-theme:  #5aaad4;          /* POURQUOI : bleu ciel doux, contraste suffisant pour le texte blanc */
  --card-grad-a: #d8f0fc;          /* POURQUOI : bleu très pâle - évoque l'eau et l'air */
  --card-grad-b: #b0daf0;          /* POURQUOI : aqua clair - bas de zone illustration */
  --card-border: rgba(90, 170, 212, 0.55);
}

/* potions : rose pêche */
.game-card[data-jeu-id="potions"] {
  --card-theme:  #d4789a;          /* POURQUOI : rose moyen - chaleureux, féminin sans être agressif */
  --card-grad-a: #fce8f0;          /* POURQUOI : rose très clair - pétale de fleur */
  --card-grad-b: #f4c4d8;          /* POURQUOI : pêche rosé - transition douce vers le rose */
  --card-border: rgba(212, 120, 154, 0.55);
}

/* ─── Carte principale ────────────────────────────────────────────── */
/* RÔLE : Enveloppe portrait style carte Pokémon - 3 zones empilées (header/illustration/footer) */
/* POURQUOI position:relative : nécessaire pour le ::before holographique */
/* POURQUOI overflow:hidden : les coins arrondis doivent clipper les zones internes */
.game-card {
  /* Layout carrousel */
  scroll-snap-align: center;
  flex-shrink: 0;
  width: calc(100% - 80px);  /* POURQUOI 80px : 40px de peek de chaque côté */
  min-height: 0;
  /* RÔLE : Forcer la carte à occuper toute la hauteur du carousel - PROBLÈME 3.
     POURQUOI explicite et non align-items:stretch implicite du parent :
     dans un flex container avec overflow-x:scroll (Safari iOS notamment),
     le stretch implicite n'étire pas toujours les enfants à 100%. Sans cette
     règle, la carte se contentait de sa hauteur intrinsèque et l'illustration
     (height:50%) tombait sur son plancher min-height:110px.
     POURQUOI height et non flex:1 : flex:1 jouerait sur l'axe principal
     (horizontal ici) - on touche au cross-axis via height pour ne pas
     impacter la largeur calc(100% - 80px) au-dessus.
     box-sizing:border-box (reset global en tête de fichier) inclut la border 2.5px → pas de débord. */
  height: 100%;

  /* Structure interne portrait */
  display: flex;
  flex-direction: column;
  align-items: stretch;    /* POURQUOI stretch et non center : les zones doivent s'étirer en largeur */

  /* Esthétique carte Pokémon cosy - contour holographique arc-en-ciel */
  /* RÔLE : Le gradient border simule un reflet chromé/shiny sur le bord de la carte */
  /* POURQUOI background à deux couches : seul moyen CSS natif de faire un gradient-border
     sans pseudo-élément - padding-box = fond uni de la carte, border-box = gradient visible
     uniquement dans la bande du border (2.5px) */
  background:
    linear-gradient(var(--card), var(--card)) padding-box,
    linear-gradient(135deg, #FFD070 0%, #FF90C0 25%, #A080FF 50%, #60D0FF 75%, #70FFB8 100%) border-box;
  border: 2.5px solid transparent;
  border-radius: 16px;     /* POURQUOI 16px et non --r-lg(14px) : plus proche des vraies cartes Pokémon */
  /* POURQUOI glow violet en plus du shadow standard : renforce le côté shiny sur le fond coloré */
  box-shadow:
    0 0 10px rgba(160, 120, 255, 0.35),
    0 8px 24px rgba(0,0,0,0.12);
  overflow: hidden;

  /* Comportement */
  position: relative;
  cursor: pointer;   /* POURQUOI : toute la carte est cliquable - pas seulement le bouton */
  transition: box-shadow 0.15s, transform 0.12s;
}

/* RÔLE : Brillance holographique simulée - reflet diagonal lumineux sur toute la carte */
/* POURQUOI ::before et non un vrai gradient : désactivable sur --disabled sans toucher
   à la carte, et se superpose à l'image d'illustration pour donner le vernis shiny */
/* POURQUOI pointer-events:none : ne doit pas intercepter les taps */
/* POURQUOI z-index:2 : au-dessus de l'image d'illustration (z-index:0) et de l'emoji */
.game-card::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 16px;
  background: linear-gradient(
    135deg,
    rgba(255,255,255,0.22) 0%,
    transparent            35%,
    transparent            65%,
    rgba(255,255,255,0.12) 100%
  );
  pointer-events: none;
  z-index: 2;
}

/* RÔLE : Feedback tactile léger au tap sur la carte */
.game-card:active {
  transform: scale(0.985);
  box-shadow: 0 4px 12px rgba(0,0,0,0.12);
}

/* ─── Zone 1 : Bandeau titre (≈15% hauteur) ──────────────────────── */
/* ─── Zone 1 : Bandeau titre (compact - style étiquette Pokémon) ─── */
/* RÔLE : Header coloré très fin - juste le titre + badge score, comme l'étiquette nom/PV */
/* POURQUOI padding réduit : on veut que ce bandeau soit discret, la vraie valeur est en bas */
.game-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px var(--sp-md) 5px;   /* POURQUOI 6/5px : bandeau fin, pas dominant */
  background: var(--card-theme, var(--lilac));
  flex-shrink: 0;
  gap: var(--sp-sm);
}

/* RÔLE : Titre du jeu dans le bandeau - Caveat bold, blanc */
.game-card-title {
  font-family: var(--font-title);
  font-size: var(--fs-md);         /* POURQUOI fs-md et non fs-lg : bandeau compact */
  font-weight: 700;
  color: #fff;
  line-height: 1.1;
  flex: 1;
}

/* RÔLE : Badge meilleur score (ex : 💎 247) - style PV d'une carte Pokémon */
/* POURQUOI Nunito bold : stat chiffrée - lisibilité > chaleur à cette taille */
.game-card-badge {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  color: #fff;
  background: rgba(255,255,255,0.22);
  border-radius: 20px;
  padding: 2px 7px;
  white-space: nowrap;
  flex-shrink: 0;
}

/* ─── Zone 2 : Illustration centrale (~50% hauteur) ──────────────── */
/* RÔLE : Zone principale visuelle - image PNG centrée + dégradé de fond en fallback */
/* POURQUOI 50% : deux "tiers" de la carte (header ≈10%, illustration ≈50%, footer ≈40%) */
/* POURQUOI overflow:hidden : clip l'image PNG qui est position:absolute inset:0 */
.game-card-illustration {
  flex-shrink: 0;
  height: 50%;                     /* POURQUOI 50% : illustration prend 2 tiers visuels */
  min-height: 110px;               /* POURQUOI plancher : image lisible sur petits écrans */
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(
    160deg,
    var(--card-grad-a, #f0e8ff) 0%,
    var(--card-grad-b, #d8c8f0) 100%
  );
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.45);
  position: relative;
  overflow: hidden;
}

/* RÔLE : Image d'illustration PNG - couvre toute la zone, centrée, sans déformation */
/* POURQUOI object-fit:cover + object-position:center : images carrées croppées
   sur leur partie centrale - les bords sont coupés proprement */
/* POURQUOI z-index:0 : sous le fondu ::after (z-index:1) et le vernis ::before (z-index:2) */
.game-card-illus-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
  z-index: 0;
}

/* RÔLE : Recadrage par jeu - ajuste le point focal de chaque illustration */
/* POURQUOI per-carte et non global : chaque image a son sujet principal à une hauteur différente */
/* cristaux : rivière arc-en-ciel + cristaux dans la moitié basse → descendre légèrement */
.game-card[data-jeu-id="cristaux"] .game-card-illus-img { object-position: center 65%; }
/* potions : tubes dans le tiers central-bas → descendre légèrement */
.game-card[data-jeu-id="potions"] .game-card-illus-img  { object-position: center 60%; }
/* bulles : bulles réparties sur toute l'image → center center (défaut) */

/* RÔLE : Fondu bas - adoucit la transition entre image sombre et footer clair */
/* POURQUOI ::after sur l'illustration et non sur la carte : le clip overflow:hidden de
   .game-card-illustration confine le fondu à la seule zone image, sans déborder sur le footer */
/* POURQUOI z-index:1 : au-dessus de l'image (0) mais sous le vernis holographique ::before (2) */
/* POURQUOI height:50% : dégradé progressif sur la moitié basse - suffisant pour effacer
   la coupure brutale sans gommer trop d'image */
.game-card-illustration::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 50%;
  background: linear-gradient(to bottom, transparent 0%, var(--card) 100%);
  z-index: 1;
  pointer-events: none;
}

/* RÔLE : Emoji icône - taille réduite en proportion de la zone illustration plus petite */
/* POURQUOI 56px : visible et expressif sans occuper toute la zone */
.game-card-icon {
  font-size: 56px;
  line-height: 1;
  text-align: center;
  filter:
    drop-shadow(0px  3px 0 rgba(255,255,255,0.9))
    drop-shadow(0px -3px 0 rgba(255,255,255,0.9))
    drop-shadow( 3px 0px 0 rgba(255,255,255,0.9))
    drop-shadow(-3px 0px 0 rgba(255,255,255,0.9))
    drop-shadow(0px  5px 6px rgba(0,0,0,0.10));
  position: relative;
  z-index: 0;
}

/* ─── Zone 3 : Footer infos (flex:1 - prend tout l'espace restant) ── */
/* RÔLE : Zone principale d'information - description + scores détaillés + bouton */
/* POURQUOI flex:1 : c'est la zone la plus importante visuellement, comme le corps d'une
   carte Pokémon (attaques, stats) - elle doit occuper la majorité de la carte */
.game-card-footer {
  flex: 1;                         /* POURQUOI flex:1 : occupe tout l'espace sous l'illustration */
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  padding: var(--sp-sm) var(--sp-md) var(--sp-md);
  background: rgba(0,0,0,0.03);
  overflow: hidden;
}

/* RÔLE : Description courte du jeu - Nunito italic, style "flavour text" carte Pokémon */
/* POURQUOI italic : marque le texte comme descriptif/narratif, distinct des stats */
/* POURQUOI border-bottom : séparateur fin entre la description et les scores */
.game-card-desc {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-style: italic;
  color: var(--text2);
  line-height: 1.4;
  text-align: center;

  /* RÔLE : Encadré "phylactère glossy" aux couleurs du jeu - PROBLÈME 4.
     Remplace l'ancien border-bottom plat par un cadre arrondi avec reflet shiny,
     cohérent avec le gradient holographique de .game-card. */
  /* POURQUOI --card-border : variable définie par carte (lignes ~3500/3508/3516) -
     l'encadré prend la teinte du jeu (violet/bleu/rose) sans hardcoder de couleur. */
  /* POURQUOI background linear-gradient blanc semi-transparent : donne du volume
     sans masquer la teinte de fond du footer (rgba(0,0,0,0.03)) - l'encadré flotte. */
  /* POURQUOI box-shadow inset 0 1px 0 rgba(255,255,255,0.85) : reflet glossy en haut,
     style vernis / résine - cohérent avec le ::before holographique de la carte. */
  background: linear-gradient(180deg,
    rgba(255,255,255,0.65) 0%,
    rgba(255,255,255,0.35) 60%,
    rgba(255,255,255,0.55) 100%);
  border: 1px solid var(--card-border, rgba(0,0,0,0.10));
  border-radius: 10px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.85),     /* highlight top - vernis */
    inset 0 -1px 0 rgba(255,255,255,0.30),    /* léger reflet bas */
    0 1px 2px rgba(0,0,0,0.05);               /* ombre douce externe */
  padding: 6px 10px;
  margin-bottom: var(--sp-sm);
  flex-shrink: 0;

  /* RÔLE : Hauteur fixe = 3 lignes (3 × 1.4em + padding vertical) - garantit que
     le score "1 min" s'affiche exactement à la même hauteur sur toutes les cartes.
     Les 3 descriptions font ~65 chars et wrappent toutes à 3 lignes sur mobile.
     box-sizing:border-box (reset global en tête de fichier) inclut padding+border dans cette hauteur. */
  height: 5em;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* RÔLE : Grille des scores - une ligne par mode de jeu */
/* POURQUOI flex-direction:column avec gap : chaque score sur sa propre ligne, aéré */
.game-card-scores {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1;
  min-height: 0;
  margin-bottom: var(--sp-sm);
}

/* ─── PICKER DE DURÉE PARTAGÉ (3 jeux) ──────────────────────── */

/* ─── Animations lancement de jeu ────────────────────────────────── */

/* RÔLE : Pulse "carte qui s'ouvre" au tap sur Jouer - option A du wahou */
/* POURQUOI scale 1→1.04→0.9 + opacity→0 : simule une carte qui s'ouvre vers l'utilisatrice */
@keyframes card-launch {
  0%   { transform: scale(1);    opacity: 1; }
  35%  { transform: scale(1.04); opacity: 1; }
  100% { transform: scale(0.9);  opacity: 0; }
}
.game-card--launching {
  animation: card-launch 0.28s cubic-bezier(0.4, 0, 1, 1) forwards;
  pointer-events: none;
}

/* RÔLE : Entrée du sélecteur de durée - zoom depuis légèrement en dessous */
/* POURQUOI cubic-bezier élastique : léger rebond final → ressenti "vivant" et cosy */
@keyframes picker-enter {
  from { opacity: 0; transform: scale(0.9) translateY(14px); }
  to   { opacity: 1; transform: scale(1)   translateY(0);    }
}

/* ─── Sélecteur de durée ─────────────────────────────────────────── */

/* RÔLE : Container picker - carte blanche avec hero image, flottante sur le fond dégradé.
   POURQUOI overflow:hidden : clip le hero image aux corners arrondis de la carte.
   POURQUOI margin:8px : respiration par rapport aux bords du #game-main. */
.hg-picker {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-height: 300px;
  /* RÔLE : Occuper toute la hauteur du parent #game-canvas-container - PROBLÈME 3 picker.
     POURQUOI flex: 1 : le container parent est désormais en flex column (cf. fix
     ci-dessus dans #game-canvas-container) → le picker peut s'étirer naturellement. */
  flex: 1;
  font-family: var(--font-body);
  background: var(--card, #fff);
  border-radius: 16px;
  overflow: hidden;
  margin: 8px;
  animation: picker-enter 0.35s cubic-bezier(0.34, 1.35, 0.64, 1) both;
  box-shadow: 0 4px 20px rgba(0,0,0,0.12);
}

/* RÔLE : Bannière illustration - image du jeu en fond, crop centré, fondu vers le blanc en bas */
/* POURQUOI height:150px : suffisant pour être impactant sans écraser le contenu */
/* POURQUOI ::after fondu : transition douce entre l'image sombre et le fond blanc du picker */
.hg-picker__hero {
  width: 100%;
  height: 150px;
  background-size: cover;
  background-position: center 60%;
  flex-shrink: 0;
  position: relative;
}
.hg-picker__hero::after {
  content: '';
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: 65%;
  background: linear-gradient(to bottom, transparent, var(--card, #fff));
  pointer-events: none;
}

/* RÔLE : Zone de contenu sous le hero - reprend le layout flex centré original */
.hg-picker__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 4px 20px 20px;
  overflow-y: auto;
  flex: 1;
}

/* RÔLE : Emoji du jeu - caché quand le hero image est présent, fallback sinon */
.hg-picker__emoji {
  font-size: 2.4rem;
  line-height: 1;
  display: block;
}
.hg-picker--has-hero .hg-picker__emoji {
  display: none;
}

/* RÔLE : Nom du jeu en font-title - couleur injectée inline selon le jeu */
.hg-picker__titre {
  font-family: var(--font-title);
  font-size: var(--fs-xl);
  color: var(--text);
  text-align: center;
  line-height: 1.2;
}

/* RÔLE : Variables --card-border par picker - récupère la teinte du jeu pour le
   contour glossy de .hg-picker__desc. PROBLÈME 4 - pendant côté picker.
   POURQUOI ids et non data-jeu-id : les pickers sont identifiés par id dans
   hgCreerPickerDuree() (cx-duree-picker, bl-duree-picker, pt-duree-picker).
   Mêmes valeurs que .game-card[data-jeu-id="..."] plus haut - cohérence visuelle
   entre la card du hub et son picker. */
#cx-duree-picker { --card-border: rgba(154, 112, 200, 0.55); }
#bl-duree-picker { --card-border: rgba( 90, 170, 212, 0.55); }
#pt-duree-picker { --card-border: rgba(212, 120, 154, 0.55); }

/* RÔLE : Bloc description + règles du jeu.
   POURQUOI text-align:left : les descriptions sont multi-lignes, la lecture
   est plus confortable alignée à gauche que centrée. */
.hg-picker__desc {
  font-size: var(--fs-sm);
  color: var(--text2);
  text-align: left;

  /* RÔLE : Encadré "phylactère glossy" aux couleurs du jeu - PROBLÈME 4 (picker).
     Reprend strictement le style de .game-card-desc pour cohérence entre la card
     du hub et son sélecteur de durée. */
  /* POURQUOI gradient blanc translucide : sur fond blanc du picker l'effet est
     subtil - c'est la bordure colorée + le box-shadow qui portent le glossy. */
  background: linear-gradient(180deg,
    rgba(255,255,255,0.65) 0%,
    rgba(255,255,255,0.35) 60%,
    rgba(255,255,255,0.55) 100%);
  border: 1px solid var(--card-border, rgba(0,0,0,0.10));
  border-radius: 10px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.85),     /* highlight top - vernis */
    inset 0 -1px 0 rgba(255,255,255,0.30),    /* léger reflet bas */
    0 1px 2px rgba(0,0,0,0.05);               /* ombre douce externe */

  padding: 10px 14px;
  width: 100%;
  max-width: 280px;
  line-height: 1.6;
}

/* RÔLE : Info joker doré - couleur distinctive, identique dans Bulles et Cristaux.
   POURQUOI display:block + margin-top : séparé visuellement de la description
   principale, comme une note en bas du bloc. */
.hg-picker__joker {
  font-size: var(--fs-xs);
  display: block;
  margin-top: 6px;
}

/* RÔLE : Label "Combien de temps ?" avant les boutons durée */
.hg-picker__label {
  font-size: var(--fs-xs);
  color: var(--text2);
  opacity: 0.75;
  text-align: center;
}

/* RÔLE : Rangée des 3 boutons durée (1/2/3 min) côte à côte */
.hg-picker__btns {
  display: flex;
  gap: 10px;
  justify-content: center;
  width: 100%;
  max-width: 280px;
}

/* RÔLE : Bouton Zen - pleine largeur, couleur verte pour le distinguer visuellement.
   POURQUOI distinct : le mode Zen est fondamentalement différent (infini, sans timer). */
.hg-picker .hg-picker__zen {
  width: 100%;
  max-width: 280px;
  color: #4a9e6b;
  border-color: #4a9e6b;
}
.hg-picker .hg-picker__zen:hover {
  background: rgba(74, 158, 107, 0.08);
}

/* RÔLE : Note discrète sous les boutons */
.hg-picker__note {
  font-size: var(--fs-xs);
  color: var(--text2);
  opacity: 0.5;
  text-align: center;
}

/* RÔLE : Bouton retour au hub */
.hg-picker__back {
  font-size: var(--fs-sm);
  touch-action: manipulation;
}

/* ─────────────────────────────────────────────────────────────── */

/* RÔLE : Une ligne de score - label à gauche, valeur à droite */
/* POURQUOI justify-content:space-between : alignement propre label ↔ valeur, style stats */
.game-card-score-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  color: var(--text2);
  line-height: 1.4;
  padding: 2px 0;
  border-bottom: 1px solid rgba(0,0,0,0.05);  /* POURQUOI : séparateur très discret entre lignes */
}

/* RÔLE : Label du mode (ex : "🕐 1 min") - mixte Nunito + emoji */
.game-card-score-label {
  font-family: var(--font-body);
  color: var(--text2);
  opacity: 0.8;
}

/* RÔLE : Valeur du score - Caveat pour la chaleur sur les chiffres importants */
/* POURQUOI Caveat : les chiffres ont plus de personnalité, cohérent avec l'esthétique cosy */
/* POURQUOI couleur --text : plus lisible que --text2 pour la valeur principale */
.game-card-score-val {
  font-family: var(--font-title);
  font-size: var(--fs-sm);         /* POURQUOI fs-sm : légèrement plus grand que le label */
  font-weight: 700;
  color: var(--text);
}
/* RÔLE : Valeur vide (pas encore joué) - grisée et moins affirmée */
.game-card-score-val--empty {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  color: var(--text2);
  opacity: 0.45;
  font-weight: 400;
}

/* RÔLE : Bouton Jouer - pleine largeur, collé en bas du footer */
/* POURQUOI margin-top:auto : pousse le bouton tout en bas quelle que soit la hauteur du footer */
.game-card-btn {
  width: 100%;
  flex-shrink: 0;
  margin-top: auto;
  touch-action: manipulation;
}

/* ─── Dots de pagination ──────────────────────────────────────────── */
/* RÔLE : Dots de pagination - indique la carte active sous le carrousel */
/* POURQUOI dots et non numérotation : plus cosy, cohérent avec les indicateurs de l'app */
.game-carousel-dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  padding: var(--sp-sm) 0 var(--sp-md);
  flex-shrink: 0;  /* POURQUOI : ne pas se comprimer */
}
/* RÔLE : Dots de pagination - couleurs adaptées au fond dégradé coloré du hub jeux
   POURQUOI violet translucide et non var(--border) : sur fond pastel coloré,
   --border (gris/transparent) devient invisible - une teinte mauve ancrée dans le dégradé
   du fond garantit le contraste sans détoner */
.game-carousel-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(110, 60, 180, 0.3);
  transition: background 0.2s, transform 0.2s;
}
.game-carousel-dot--active {
  background: rgba(110, 60, 180, 0.8);
  transform: scale(1.25);
}

/* ─── Variante désactivée ─────────────────────────────────────────── */
/* RÔLE : Variante grisée pour les jeux "Bientôt" - visuellement présents mais non interactifs */
/* POURQUOI : Montre la roadmap sans générer de frustration - l'utilisatrice sait ce qui arrive */
.game-card--disabled {
  opacity: 0.45;
  pointer-events: none;
  /* POURQUOI filter grayscale : renforce le côté "indisponible" sans changer les couleurs */
  filter: grayscale(0.5);
  /* POURQUOI border neutre : les --card-border colorées ne doivent pas s'appliquer */
  border-color: var(--border);
}
/* RÔLE : Supprime le brillant holographique sur les cartes désactivées */
/* POURQUOI : la brillance est un signal de "jouable" - la retirer renforce l'état indisponible */
.game-card--disabled::before {
  display: none;
}

/* RÔLE : Zone canvas du jeu actif - normalement caché, dans le flux */
#game-canvas-container {
  position: relative; /* POURQUOI : les boutons HTML fin de partie (position:absolute) se calent dessus */
  width: 100%;
  min-height: 200px;
  /* RÔLE : Étirer le container sur toute la hauteur de #game-main - PROBLÈME 3 picker.
     Sans ça, le sélecteur de durée (.hg-picker) flottait en haut avec un grand vide
     en dessous (cf. capture Émilie 2026-05-15). */
  /* POURQUOI flex: 1 + min-height: 0 : permet au container d'occuper l'espace disponible
     dans #game-main (flex column) sans bloquer le shrink éventuel. */
  /* POURQUOI display: flex column : transmet la hauteur étirée à l'enfant .hg-picker
     qui peut alors résoudre son flex: 1. */
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* RÔLE : Mode plein-écran jeu - canvas couvre tout #game-main (zone sous le header)
   POURQUOI inset:0 dans #game-main et non dans #game-overlay :
     #game-main est déjà flex:1 et prend exactement l'espace sous le header.
     En ancrant le canvas à position:absolute inset:0 dans ce parent, le jeu occupe
     toute la surface disponible sans déborder sur le header ni sur la safe area. */
#game-canvas-container.game-canvas--fullscreen {
  position: absolute;
  inset: 0;          /* top/right/bottom/left: 0 - couvre tout #game-main */
  padding: 0;        /* POURQUOI : annule le padding hérité éventuel du parent */
  z-index: 2;        /* POURQUOI : au-dessus du contenu normal du #game-main */
  /* RÔLE : Annuler le display: flex column de l'état picker - p5 attend un container
     block pour positionner correctement son canvas. Avec position:absolute inset:0,
     le block remplit toute la zone, identique au comportement original. */
  display: block;
}


/* RÔLE : Placeholder visuel sprint 1 - centré, ton discret */
.game-placeholder {
  width: 100%;
  padding: var(--sp-lg);
  background: var(--card);
  border: 2px dashed var(--border);
  border-radius: var(--r-lg);
  text-align: center;
}

/* RÔLE : Fond de l'overlay jeux - dégradé multicolore pastel pour donner envie de jouer
   POURQUOI gradient fixe et non var(--bg) : le fond jeux a sa propre identité visuelle,
   indépendante du thème saison - lavande → ciel → menthe → crème.
   POURQUOI ces teintes : pastel doux (néon doux), lisibles en texte sombre, cohérentes
   avec l'ambiance cosy de l'appli sans être trop saturées. */
#game-overlay {
  background: linear-gradient(160deg, #E8D5FF 0%, #D0F0FF 40%, #D5FFE8 70%, #FFF5C8 100%);
}

/* RÔLE : Header du hub jeux - structure identique à .hdr-garden-inner
   POURQUOI border-bottom semi-transparent : sur fond coloré, une bordure pleine
   serait trop dure - rgba permet de s'adapter aux variations du dégradé. */
.hdr-game-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px 8px;
  flex-shrink: 0;
  border-bottom: 1px solid rgba(160, 120, 200, 0.25);
  width: 100%;
}

/* RÔLE : Baseline justifiée sous le titre jeux - même pattern que .garden-baseline
   POURQUOI couleur mauve : tire sur la teinte lavande du dégradé, reste lisible */
/* POURQUOI space-evenly et non space-between : 5 mots de longueurs inégales -
   space-evenly répartit l'espace autour de chaque mot (pas seulement entre eux),
   ce qui donne une distribution visuellement plus homogène que space-between */
.game-baseline {
  display: flex;
  justify-content: space-evenly;
  font-style: italic;
  font-size: 12px;
  color: #7048A8;
  margin-top: 1px;
  letter-spacing: 0.2px;
  opacity: 0.85;
}

/* RÔLE : Zone scrollable du hub - max-width centré sur grands écrans */
/* POURQUOI max-width 480px : l'app est pensée mobile - au-delà les cartes s'étirent trop */
/* POURQUOI position:relative : sert d'ancre pour #game-canvas-container.game-canvas--fullscreen
   (position:absolute inset:0) - sans ça le canvas s'ancrerait sur l'overlay ou la page */
#game-main {
  position: relative;
  max-width: 480px;
  margin: 0 auto;
  width: 100%;
}

/* RÔLE : Bouton retour hub - toujours au-dessus du canvas fullscreen (z-index:2)
   POURQUOI position:absolute dans #game-main (position:relative) : le canvas fullscreen
   couvre tout #game-main via inset:0. Le bouton doit être ancré dans ce même parent
   avec un z-index supérieur pour rester visible et cliquable pendant le jeu. */
#game-back-btn {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  white-space: nowrap;
}

/* ─────────────────────────────────────────────────────────────────────
   OVERLAY LANDSCAPE - iOS ne respecte pas manifest.json "orientation"
   RÔLE : Couvre l'écran en mode paysage pour bloquer l'usage non voulu
   POURQUOI z-index 9999 : doit passer au-dessus de tout (etats-overlay: 1000, toast: 1001) */
#rotate-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--bg, #ddd6e8);
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  font-family: var(--font-title, sans-serif);
  color: var(--text, #333);
  text-align: center;
  padding: 24px;
}

/* RÔLE : affiche l'overlay UNIQUEMENT sur téléphone en paysage.
   POURQUOI max-height 600px : un PC/tablette est aussi « landscape » mais haut
   → non bloqué (sinon le cadre téléphone desktop serait masqué).
   ⚠️ POURQUOI APRÈS le bloc #rotate-overlay{display:none} : à spécificité égale
   (un seul ID), c'est l'ordre source qui tranche. Placée AVANT (état précédent),
   le display:none la neutralisait → l'overlay ne s'affichait jamais (bug iPhone). */
@media (orientation: landscape) and (max-height: 600px) {
  #rotate-overlay { display: flex; }
}

#rotate-overlay .rotate-icon {
  font-size: 3rem;
  animation: rotateHint 2s ease-in-out infinite;
}

#rotate-overlay p {
  font-size: 1.1rem;
  margin: 0;
  line-height: 1.4;
}

@keyframes rotateHint {
  0%, 100% { transform: rotate(0deg); }
  40%       { transform: rotate(-90deg); }
  60%       { transform: rotate(-90deg); }
}

/* ─── SYSTÈME 5 : INVENTAIRE - CARTES & FILTRES ──────────────────────
   RÔLE : Styles des deux cartes de l'inventaire (Équipés / Rangés+Grenier)
          et de la barre de filtres texte.
   POURQUOI séparés du JS : ces règles servent plusieurs états du rendu
   (actif, focus, transition) et sont plus maintenables en CSS qu'inline.
   ─────────────────────────────────────────────────────────────────── */

/* CARTE 1 : "Équipés maintenant"
   RÔLE : Fond dégradé lilas/ciel doux pour distinguer visuellement
          la zone active du reste de l'inventaire.
   POURQUOI gradient : contraste suffisant sans couleur saturée qui
          fatiguerait l'œil au quotidien. */
.props-card-equipped {
  background: var(--solid);
  border: 2px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-md);
  margin-bottom: 10px;
}

/* CARTE 2 : "Rangés + Grenier"
   RÔLE : Fond blanc neutre pour mettre en valeur CARTE 1 par contraste. */
.props-card-stored {
  background: var(--solid);
  border: 2px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-md);
  margin-bottom: 12px;
}

/* BARRE DE FILTRES TEXTE
   RÔLE : Conteneur colonne - deux lignes fixes (3 boutons + 2 boutons).
   POURQUOI flex-direction:column : on contrôle explicitement la répartition
          en deux rangées via .props-filters-row plutôt que de laisser
          flex-wrap décider seul (risque de 5+0 ou 4+1 sur grand écran). */
.props-filters-bar {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-bottom: 10px;
}

/* UNE RANGÉE DE FILTRES
   RÔLE : Ligne de boutons qui se répartissent équitablement en largeur.
   POURQUOI flex:1 sur les boutons : chaque ligne occupe 100% et les
          boutons se divisent l'espace également (3 sur la 1re, 2 sur la 2e). */
.props-filters-row {
  display: flex;
  gap: 5px;
  width: 100%;
}

/* BOUTON FILTRE (état inactif)
   RÔLE : Apparence neutre - fond transparent, bordure discrète. */
.props-filter-btn {
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  padding: 5px 10px;
  border-radius: var(--r-md);
  font-size: var(--fs-xs);
  font-weight: normal;
  font-family: var(--font-body);
  cursor: pointer;
  background: transparent;
  color: var(--text2);
  border: 1.5px solid var(--border);
  transition: background .12s, color .12s, border-color .12s, font-weight .12s;
  white-space: nowrap;
  line-height: 1.4;
}

/* BOUTON FILTRE (état actif)
   RÔLE : Fond lilas pâle + texte profond + bordure lilas + gras -
          met en évidence la catégorie sélectionnée. */
.props-filter-btn--active {
  background: var(--lilac-light);
  color: var(--lilac-dark);
  border-color: var(--lilac);
  font-weight: 700;
}

/* LABEL DE GROUPE (Ambiance / Décor / Accessoires)
   RÔLE : Titre de section en capitales légères dans l'inventaire. */
.inv-group-label {
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text2);
  opacity: .75;
  margin-bottom: 6px;
  margin-top: 4px;
}

/* LABEL DE SOUS-GROUPE (Tête / Cou / Yeux / Nature / Ambiance / Océan)
   RÔLE : Subdivision plus fine à l'intérieur d'un groupe, ton discret. */
.inv-sub-label {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .8px;
  color: var(--text2);
  opacity: .55;
  margin-top: 8px;
  margin-bottom: 4px;
  padding-left: 2px;
}

/* CASE VIDE (emplacement disponible dans CARTE 1)
   RÔLE : Placeholder pour un slot libre - décor, ambiance ou accessoire.
          Même dimensions qu'une carte prop, ton atténué, bordure pointillée. */
.inv-slot-empty {
  border: 1.5px dashed var(--border);
  border-radius: var(--r-md);
  padding: 6px 4px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 90px;
  gap: 2px;
  text-align: center;
  color: var(--text2);
  opacity: .4;
  cursor: default;
}

/* SOFT CAP PÉTALES - halo rose d'abondance (audit R6 §5.1)
   RÔLE : Signal visuel doux quand le stock de pétales dépasse PETALES_SOFT_CAP.
          Classe posée/retirée par updUI() (ui-settings-hud.js) sur les compteurs
          #petales-l, #petales-wallet, #petales-wallet-boutique.
   POURQUOI un halo et non une désaturation : désaturer un stock plein le ferait
          paraître dévalué (« tes pétales ne servent à rien »). Le halo dit l'inverse :
          abondance positive. Jamais bloquant, jamais d'alarme rouge.
   color-mix : suit la palette active (--pink) automatiquement, comme --lilac-xlight. */
.petales-abondance {
  border-radius: 999px;
  box-shadow: 0 0 7px 2px color-mix(in srgb, var(--pink) 65%, transparent);
  transition: box-shadow .4s ease;
}

/* RÔLE : ferrage à gauche auto des blocs de texte > 3 lignes (hgAutoAlignLongText, ui-core.js) */
.hg-txt-left { text-align: left; }

/* RÔLE : anti-orphelins typographiques (mots seuls en fin de ligne).
   POURQUOI : balance équilibre les titres courts ; pretty évite les orphelins
   des paragraphes. Complète _noOrphan() (toasts) et hgAutoAlignLongText (ferrage). */
h1, h2, h3, h4 { text-wrap: balance; }
p, li, #mbox, #agenda-contenu { text-wrap: pretty; }
