  /* ============================================================
     MY MICROBIOTE — design system
     Inspiré des grandes applis récentes (X, etc.) : fond noir
     profond, une colonne centrale bordée de filets, typo système,
     pilules, filets fins, navigation en bas façon app mobile.
     Les noms de variables historiques (--wheat, --moss, --rust…)
     sont conservés : le JS génère des styles inline qui les utilisent.
     ============================================================ */
  :root{
    /* surfaces */
    --soil-900:#000000;          /* fond de page */
    --soil-800:#0b0e0d;          /* cartes / surfaces */
    --soil-700:#191d1b;          /* champs, chips */
    --line:#2b312e;              /* filets */
    /* texte */
    --parchment:#e7e9ea;
    --parchment-dim:#8b9691; /* contraste AA sur fond noir */
    /* sémantique (statuts, accents) */
    /* DEUX rôles, deux jetons (03/09/2026, demandé par Éric : « toutes les
       couleurs jaune fluo ne seraient pas mieux en vert de l'icône ? »).
       Le doré faisait deux métiers à la fois — une ACTION (Enregistrer,
       l'onglet actif, un survol) et un ÉTAT (pile à la cible, une charge, une
       note datée d'hier) — et on ne savait pas lequel on lisait. En passant
       les actions au vert de la marque, le doré ne dit plus qu'une chose :
       « regarde par ici ». Il n'est pas dilué, il est purifié.
       --action suit le thème : il vaut le vert de l'icône en sombre, et le
       vert profond du thème clair, où le vif serait illisible sur blanc. */
    --wheat:#f5b82e;             /* ÉTAT : pile à la cible, charge, série */
    --wheat-dim:#a8842a;
    --action:#00ba7c;            /* ACTION : le vert de l'icône */
    --action-dim:#0a8f60;
    --moss:#00ba7c;              /* ok / à jour */
    --moss-bright:#00d68f;
    --rust:#f4212e;              /* ÉTAT : retard / danger, en TEXTE et en filet */
    /* --rust-dim : le même rouge quand il devient un FOND qui porte du texte
       blanc (survol de « Tout effacer », de « Annuler »). Un seul rouge ne
       peut pas faire les deux : assez clair pour se lire sur une carte
       sombre, assez sombre pour porter du blanc. Mesuré le 04/09/2026 —
       blanc sur --rust : 4,11:1, sous le seuil ; sur --rust-dim : 4,56:1. */
    --rust-dim:#e61f2b;
    --clay:#7a6a58;
    --hover:rgba(231,233,234,0.04);
    --arc-track:#232926; /* piste des anneaux SVG */
    /* ---- Echelle typographique (30/08/2026) ----
       Cinq tailles, pas vingt-trois. Un demi-pixel d'ecart n'est pas une
       hierarchie : personne ne voit 12 contre 12,5, mais l'appli le payait en
       incoherence, chaque nouvelle regle choisissant sa valeur au juge.
       Ne servent PAS a dimensionner les icones et les emojis : une frimousse de
       ressenti ou le logo se dimensionnent pour eux-memes (voir les regles
       laissees en pixels : .brand-logo, .feel-btn, .dex-sprite, .wa-avatar...).
       Le chiffre de l'anneau n'est pas ici non plus : il est dessine dans le SVG. */
    --t-xs:11px;    /* legendes, mentions, intitules de tuiles */
    --t-sm:13px;    /* texte secondaire, sous-titres, explications */
    --t-md:15px;    /* texte courant, noms d'aliments, champs */
    --t-lg:17px;    /* titres de cartes et de sections */
    --t-xl:22px;    /* chiffres des tuiles */
    /* ---- Rayons ----
       Trois valeurs. Une exception documentee : .dex-month, carre de 17 px,
       garde 5 px — un rayon de 10 y donnerait un cercle. */
    /* ---- Mouvement (30/08/2026) ----
       Trois durées et UNE courbe, comme l'échelle typographique : 41 transitions
       utilisaient 10 durées et 4 courbes différentes — rien ne bougeait tout à
       fait pareil, sans qu'on sache dire pourquoi. Les animations d'ambiance
       (pulsations, étincelle) gardent leur tempo propre : ce ne sont pas des
       réponses à un geste. */
    --d-vite:120ms;    /* retour tactile : enfoncement, survol, fondu court */
    --d-normale:180ms; /* dépliage, apparition d'un panneau */
    --d-ample:240ms;   /* changement d'écran, glissement de page */
    --courbe:cubic-bezier(.2,.8,.3,1); /* la courbe du glissement de pages, partout */
    --r-sm:10px;    /* petits elements : pastilles de mois, lignes de resultat */
    --r-md:16px;    /* cartes, panneaux, champs */
    --r-full:9999px;/* boutons, puces, barres de progression */
    --radius:var(--r-md); /* ancien nom, garde : il est utilise partout */
    --font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  }
  /* -webkit-tap-highlight-color : supprime le voile bleu/gris qu'Android et iOS
     posent au toucher (rectangle qui déborde des boutons arrondis). */
  *{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
  html,body{margin:0;padding:0;}
  /* Le fond est aussi posé sur <html> : sur téléphone, la zone sous la page
     (barres du navigateur, clavier, rebond de défilement) reste de la bonne
     couleur au lieu d'apparaître en blanc. Le JS pose la classe de thème sur
     <html> ET <body> (voir applyPrefs). */
  html{
    scrollbar-color:#3a423e transparent; background:#000;
    /* Place de la barre de défilement TOUJOURS réservée. Sans ça, une page
       courte (Calendrier, Informations…) n'a pas de barre, une page longue si :
       la largeur utile change d'une page à l'autre, et comme toute la mise en
       page est centrée (colonne, menu latéral en calc(50% - …)), l'écran
       entier se décalait à chaque changement de page. */
    scrollbar-gutter:stable;
  }
  /* Aucun défilement horizontal : sans ça, l'animation de glissement des pages
     (left:±44px) élargit brièvement la fenêtre et TOUT l'écran se décale. */
  html, body{overflow-x:clip;}
  html.theme-wa{background:#0b141a;}
  html.theme-light{background:#eef1ef;}
  /* MARQUEUR « on est ici » — le mois courant dans la reglette des saisons, le
     jour du jour dans le calendrier.

     AUCUNE COULEUR UNIQUE NE PEUT FAIRE CE TRAVAIL, et c est arithmetique :
     ces cases prennent tantot un fond sombre, tantot le vert plein, et il
     faudrait etre a la fois plus clair que le vert et plus sombre que le noir.
     Le marqueur est donc un DOUBLE lisere, clair dehors / sombre dedans : sur
     le vert c est le sombre qui porte (8,3:1), sur une case sombre c est le
     clair (15,9:1), et les deux se detachent l un de l autre. NE PAS LE
     REPASSER EN UNE SEULE COULEUR : c est exactement ce qui a produit le bug
     du 04/09/2026 — le contour du mois courant etait var(--action), devenu le
     vert de --moss a la bascule du 03/09, donc un contour vert SUR un fond
     vert (rapport de contraste 1,00, mesure). En dore il valait deja 1,42.

     IL EST DECLARE SUR body ET NON SUR :root, et ce n est pas un detail : un
     var() ecrit dans une variable se resout sur l element qui PORTE la
     declaration. Les themes posent leurs couleurs sur body.theme-* ; un
     --marqueur declare dans :root se resoudrait donc sur <html>, ou --parchment
     et --soil-900 valent encore le theme sombre — mesure au banc : en theme
     clair le marqueur sortait blanc-sur-noir. Toute variable composite qui cite
     une couleur de theme se declare sur body. */
  body{
    --marqueur:inset 0 0 0 1px var(--parchment), inset 0 0 0 2px var(--soil-900);
    background:var(--soil-900);
    color:var(--parchment);
    font-family:var(--font);
    font-size:var(--t-md);
    line-height:1.45;
    min-height:100vh;
    min-height:100dvh; /* hauteur réelle de l'écran mobile (barres dynamiques comprises) */
    -webkit-font-smoothing:antialiased;
  }
  button{font-family:var(--font);}
  ::selection{background:rgba(245,184,46,0.35);}
  /* (le bloc prefers-reduced-motion vit avec les réglages d'animations, plus bas) */

  /* --- Colonne centrale --- */
  /* --dec : DÉCALAGE DE RECENTRAGE (A-1 de l'audit du 30/08/2026).
     La colonne de 640 px était centrée sur l'écran et le rail accroché À CÔTÉ
     d'elle : la masse visuelle n'était donc jamais équilibrée. Mesuré avant
     correction — marge gauche / marge droite : 1440 px → 119/407, 1280 px →
     39/327, 960 px → 61/167, 1600 px → 199/143. C'est l'ASSEMBLAGE (rail +
     colonne + colonne de droite) qui doit être centré, pas la colonne seule ;
     --dec vaut la moitié de la différence entre ce qui borde à gauche et ce qui
     borde à droite, et il est appliqué à TOUT ce qui se place par rapport au
     centre : .wrap, .topbar, .side-nav, .side-widgets, le dock, les messages.
       860–1259  : rail 68 + 24 d'air à gauche, rien à droite  → +46
       1260–1519 : rail 250 + 24                               → +137
       ≥ 1520    : 274 à gauche, 344 à droite                  → −35
     Ne pas changer une largeur de rail ou de colonne sans refaire ce calcul. */
  :root{--dec:0px;}
  .wrap{
    max-width:640px;
    margin:0 auto;
    padding:12px 16px calc(96px + env(safe-area-inset-bottom));
    min-height:100vh;
  }
  @media (min-width:700px){
    .wrap{border-left:1px solid var(--line); border-right:1px solid var(--line);}
  }
  /* Fond UNI sous la page Aliments (toutes versions) et la page Informations
     (grand écran) : les motifs dessinés du thème « Sombre doux » passaient
     derrière les longues listes et rendaient la lecture pénible. */
  body.tab-foods .wrap, body.tab-infos .wrap{background:var(--soil-900);}

  /* --- Barre du haut (sticky, floutée) --- */
  .topbar{
    position:sticky; top:0; z-index:60;
    /* Effet X : elle glisse hors de l'écran quand on défile vers le bas
       (body.topbar-hidden, posé par le JS sur les 3 pages principales). */
    transition:transform var(--d-ample) var(--courbe);
    /* Flou limité à cette seule petite surface (rayon réduit + couche isolée) :
       l'effet verre sans le coût des trois couches floutées d'avant. */
    background:rgba(0,0,0,0.75);
    backdrop-filter:blur(6px) saturate(1.4);
    -webkit-backdrop-filter:blur(6px) saturate(1.4);
    will-change:backdrop-filter;
    border-bottom:1px solid var(--line);
    padding-top:env(safe-area-inset-top); /* encoche / barre d'état en app installée */
  }
  /* Plus de classe tout-ou-rien : le decalage est pose en style en ligne par
     topbarPose(), proportionnellement au defilement (voir app.js). La transition
     declaree plus haut est coupee pendant ce suivi, sinon chaque evenement de
     defilement relancerait une animation de 240 ms et l entete trainerait
     derriere le doigt. Elle reste pour le retour a zero d un changement de page. */
  body.topbar-suivi .topbar{transition:none;}
  /* Hors des 3 pages principales (Calendrier, Stats, Intolérances, Paramètres,
     Informations), l'entête n'a pas de sens : elle disparaît entièrement. */
  body.topbar-gone .topbar{display:none;}
  /* Sans l'entête, c'est le contenu qui doit respecter l'encoche (iPhone en app installée). */
  body.topbar-gone .wrap{padding-top:calc(12px + env(safe-area-inset-top, 0px));}
  .topbar-inner{
    max-width:640px; margin:0 auto;
    display:flex; align-items:center; justify-content:space-between; gap:12px;
    padding:10px 16px;
  }
  @media (min-width:700px){
    .topbar-inner{border-left:1px solid var(--line); border-right:1px solid var(--line);}
  }
  .topbar-left{display:flex; align-items:center; gap:8px; min-width:0;}
  .topbar-date{white-space:nowrap;}
  @media (max-width:520px){
    .topbar-date{display:none;}
  }
  /* C'est un <button> (il ouvre les Paramètres, comme l'avatar de X) : on lui
     retire l'habillage de bouton du navigateur. */
  .brand-logo{
    width:36px; height:36px; flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    font-size:20px;
    background:var(--soil-700);
    border:none; padding:0; color:inherit; font-family:inherit;
    border-radius:50%;
    cursor:pointer;
    transition:filter var(--d-normale) var(--courbe);
  }
  /* Le logo de l'appli remplace l'emoji 🦠 (30/08/2026) : c'est l'artichaut de
     l'icône d'accueil, donc la même image que sur l'écran du téléphone — on
     reconnaît l'appli au même signe partout. L'image remplit le rond. */
  .brand-logo img{width:100%; height:100%; border-radius:50%; display:block; object-fit:cover;}
  .brand-logo:active{filter:brightness(1.35);}
  .sub{font-size:var(--t-sm); color:var(--parchment-dim); margin-top:1px;}
  .topbar-right{display:flex; align-items:center; gap:8px; flex:0 0 auto;}
  .streak-chip{
    font-size:var(--t-sm); font-weight:700;
    color:var(--wheat);
    background:rgba(245,184,46,0.12);
    border:1px solid rgba(245,184,46,0.3);
    border-radius:9999px;
    padding:4px 10px;
    white-space:nowrap;
  }
  .icon-btn{
    width:34px; height:34px; flex:0 0 auto;
    border-radius:50%;
    border:1px solid var(--line);
    background:transparent;
    color:var(--parchment-dim);
    font-size:var(--t-md); font-weight:700; font-style:italic;
    cursor:pointer;
    display:inline-flex; align-items:center; justify-content:center;
    transition:background var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe);
  }
  @media (hover:hover) and (pointer:fine){
    .icon-btn:hover{background:var(--hover); color:var(--parchment);}
  }

  /* --- Onglets principaux (haut), façon X : texte + barre arrondie sous l'actif --- */
  .top-tabs{
    max-width:640px; margin:0 auto;
    display:flex;
    position:relative; /* ancre la barre dorée coulissante */
  }
  @media (min-width:700px){
    .top-tabs{border-left:1px solid var(--line); border-right:1px solid var(--line);}
  }
  .top-tab{
    flex:1;
    background:none; border:none;
    color:var(--parchment-dim);
    font-family:var(--font);
    font-size:var(--t-md); font-weight:600;
    padding:0;
    cursor:pointer;
    transition:background var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe);
  }
  /* Survol : le fond se teinte ET le nom s'allume, comme sur X. Réservé à la
     souris : sur téléphone, le navigateur garde l'état « survol » collé après
     une tape — c'est ce qui laissait un rectangle blanc translucide sur
     l'onglet touché, rectangle qui ne repartait plus. */
  @media (hover:hover) and (pointer:fine){
    .top-tab:hover{background:var(--hover); color:var(--parchment);}
    .top-tab:active{background:rgba(231,233,234,0.08);}
  }
  .top-tab .top-tab-txt{
    display:inline-flex; align-items:center;
    position:relative;
    padding:13px 4px;
  }
  .top-tab.active{color:var(--parchment); font-weight:800;}
  /* La barre dorée est un élément unique qui GLISSE d'un onglet à l'autre
     (comme sur X) — le JS (positionTabBar) calcule sa position et sa largeur. */
  .top-tabs-bar{
    position:absolute; bottom:0; left:0;
    height:4px; width:0;
    border-radius:9999px;
    background:var(--action);
    opacity:0;
    transition:left var(--d-ample) var(--courbe), width var(--d-ample) var(--courbe), opacity var(--d-normale) var(--courbe);
    pointer-events:none;
  }

  /* --- Navigation basse --- */
  /* Elle s'efface quand on descend une longue liste et revient dès qu'on
     remonte ou qu'on touche le bas de la page — comme sur X. */
  .bottom-nav{
    transition:transform var(--d-normale) var(--courbe);
    position:fixed; left:0; right:0; bottom:0; z-index:70;
    background:rgba(0,0,0,0.96);
    border-top:1px solid var(--line);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .bottom-nav-inner{
    max-width:640px; margin:0 auto;
    display:flex;
  }
  .nav-btn{
    flex:1;
    background:none; border:none;
    color:var(--parchment-dim);
    font-size:var(--t-xs); font-weight:600;
    padding:8px 4px 10px;
    cursor:pointer;
    display:flex; flex-direction:column; align-items:center; gap:3px;
    transition:color var(--d-normale) var(--courbe);
  }
  .nav-btn .nav-ico{font-size:20px; line-height:1; display:flex; transition:transform var(--d-normale) var(--courbe);}
  .nav-btn .nav-ico svg{display:block;}
  /* Icônes deux états, façon X / WhatsApp : contour (.ico-line) au repos,
     silhouette pleine (.ico-fill) quand on est sur la page. Vaut pour la barre
     du bas ET le menu latéral du grand écran. */
  /* Ces trois regles portent .nav-btn / .side-btn en tete pour une raison :
     la regle voisine `.nav-btn .nav-ico svg{display:block}` est plus specifique
     qu'un simple `.nav-ico .ico-fill`, et gagnait donc contre le display:none —
     les DEUX icones (contour ET silhouette) s'affichaient l'une sous l'autre
     dans la barre du bas, en permanence. */
  .nav-btn .nav-ico .ico-fill, .side-btn .side-ico .ico-fill{display:none;}
  .nav-btn.active .nav-ico .ico-line, .side-btn.active .side-ico .ico-line{display:none;}
  .nav-btn.active .nav-ico .ico-fill, .side-btn.active .side-ico .ico-fill{display:block;}
  /* Éclair blanc au toucher, façon X : il s'allume sous le doigt puis s'efface
     tout seul en un instant. On passe par une animation plutôt que par :active,
     que les navigateurs mobiles laissent collé sur le dernier élément touché. */
  .top-tab.tapped{animation:tapFlash var(--d-ample) ease-out;}
  /* Appui sur la barre du bas, façon X et WhatsApp : une pastille arrondie
     apparaît derrière l'icône, grandit et s'efface aussitôt. Sur un
     pseudo-élément, donc sans rien ajouter au balisage ; pointer-events:none
     pour qu'elle n'intercepte jamais le toucher. */
  .nav-btn .nav-ico{position:relative;}
  /* inset:-6px, et non -9px -18px (corrige le 30/08/2026). L'icone fait 22,7 px
     et ne commence qu'a 7,2 px du haut du bouton : une pastille de 57 x 39 px
     depassait de 1,8 px au-dessus du bouton — donc par-dessus le filet de la
     barre et sur la page — et mordait sur le libelle en dessous. Un carre
     d'inset egal donne un vrai CERCLE centre sur l'icone (34,7 px, 36,8 px au
     sommet de l'animation) qui tient dans le bouton des quatre cotes. */
  .nav-btn .nav-ico::before{
    content:"";
    position:absolute; inset:-6px;
    border-radius:9999px;
    background:currentColor;
    opacity:0;
    transform:scale(0.6);
    pointer-events:none;
  }
  .nav-btn.tapped .nav-ico::before{animation:navAppui 420ms cubic-bezier(.2,.8,.3,1);}
  @keyframes navAppui{
    0%  {opacity:0.26; transform:scale(0.6);}
    40% {opacity:0.18; transform:scale(1);}
    100%{opacity:0; transform:scale(1.06);}
  }
  @keyframes tapFlash{
    from{background-color:rgba(231,233,234,0.14);}
    to{background-color:transparent;}
  }
  /* Même raison que les onglets du haut : pas d'état collant sur téléphone. */
  @media (hover:hover) and (pointer:fine){
    .nav-btn:hover{color:var(--parchment);}
    .nav-btn:hover .nav-ico{transform:translateY(-1px);}
    .nav-btn:active .nav-ico{transform:scale(0.88);}
  }
  .nav-btn.active{color:var(--action);}
  .nav-btn.active .nav-ico{transform:scale(1.08);}

  /* --- Clavier ouvert (telephone) ---
     Un champ de saisie prend le focus : le clavier monte, et la barre du bas —
     qui est en position:fixed — venait se poser juste au-dessus de lui, entre le
     champ et les touches. Elle n'y sert a rien (on ne change pas de page en
     pleine saisie) et elle mange la place. On l'efface donc le temps de la
     frappe, et ce qui flottait au-dessus d'elle redescend d'autant. */
  body.bottomnav-hidden .bottom-nav{transform:translateY(100%);}
  /* Ce qui flottait au-dessus d'elle descend avec elle. On anime `bottom` et
     non `transform` : le dock porte déjà un transform, que le glissement de
     pages pilote au doigt. */
  body.bottomnav-hidden .foods-dock{bottom:calc(10px + env(safe-area-inset-bottom));}
  body.bottomnav-hidden .toast-stack{bottom:calc(14px + env(safe-area-inset-bottom));}
  body.kb-open .bottom-nav{display:none;}
  body.kb-open .foods-dock{bottom:calc(10px + env(safe-area-inset-bottom));}
  body.kb-open .toast-stack{bottom:calc(14px + env(safe-area-inset-bottom));}

  /* --- Panneaux d'onglets --- */
  .tab-panel{display:none;}
  /* léger fondu à l'arrivée d'une page : le changement d'onglet n'est plus brut.
     Opacité seule (pas de transform) : le dock de recherche des Aliments est en
     position:fixed dans son panneau, un transform animé le ferait sauter. */
  .tab-panel.active{display:block; animation:panelIn var(--d-normale) var(--courbe);}
  @keyframes panelIn{from{opacity:0;} to{opacity:1;}}
  /* Arrivée par glissement lors d'un swipe ou d'un clic entre les 3 pages
     principales. On anime `left` (position relative) et non transform : un
     transform ferait sauter le dock fixe de l'onglet Aliments. */
  .tab-panel{position:relative;}
  .tab-panel.active.slide-from-right{animation:slideFromRight var(--d-ample) var(--courbe);}
  .tab-panel.active.slide-from-left{animation:slideFromLeft var(--d-ample) var(--courbe);}
  @keyframes slideFromRight{from{opacity:0; left:44px;} to{opacity:1; left:0;}}
  @keyframes slideFromLeft{from{opacity:0; left:-44px;} to{opacity:1; left:0;}}
  /* Arrivée après un swipe au doigt : le glissement a déjà eu lieu sous le
     doigt, on ne rejoue aucune animation (ni glissé ni fondu). */
  .tab-panel.no-anim{animation:none !important;}
  /* Pendant qu'une page suit le doigt, le dock de recherche est épinglé dans sa
     page par le JS (pinDock) : il glisse donc avec elle. Reste à le rendre
     insensible au toucher le temps du geste. */
  body.tab-foods .foods-dock{display:block;}
  /* Pendant qu'une page suit le doigt, le JS déplace le dock du même mouvement
     que sa page ; il reste seulement à le rendre insensible au toucher. */
  body.page-swiping .foods-dock{pointer-events:none;}
  /* Squelette de chargement montré pendant le swipe vers une page lourde
     (Aliments, Calendrier, Stats) : ronds + barres qui pulsent, façon X. */
  #swipeSkeleton{display:none;}
  .sk-row{display:flex; gap:12px; align-items:flex-start; padding:14px 4px; border-bottom:1px solid var(--line); animation:skPulse 1.2s ease-in-out infinite;}
  .sk-avatar{width:40px; height:40px; border-radius:50%; background:var(--soil-700); flex:0 0 auto;}
  .sk-lines{flex:1; padding-top:4px;}
  .sk-line{height:12px; border-radius:var(--r-full); background:var(--soil-700); margin-bottom:10px; width:80%;}
  .sk-line.short{width:45%;}
  @keyframes skPulse{0%, 100%{opacity:1;} 50%{opacity:0.45;}}
  /* Aperçu du dock (recherche + filtres) dans le squelette de la page Aliments :
     le panneau ne disparaît plus d'un coup pendant le glissement. */
  .sk-dock{
    position:absolute; left:10px; right:10px; bottom:72px;
    border:1px solid var(--line); border-radius:var(--r-md);
    background:var(--soil-800);
    padding:12px; /* suit le dock : le squelette doit avoir sa silhouette */
    animation:skPulse 1.2s ease-in-out infinite;
  }
  .sk-dock-chips{display:flex; gap:6px; margin-bottom:10px;}
  .sk-dock-chips span{height:26px; border-radius:9999px; background:var(--soil-700); flex:1;}
  .sk-dock-search{height:34px; border-radius:9999px; background:var(--soil-700);}
  .tab-panel .cat:last-child{margin-bottom:0;}

  /* --- Chevron unifié ---
     UN SEUL composant pour « ça se déplie » : avant, le même geste se disait de
     cinq façons (▸ pivotant, flèche CSS, SVG basculant, ▸/▾ échangés d'un coup,
     ▾ figé). Dessiné en bordures, il pointe en BAS fermé, en HAUT ouvert, et
     pivote toujours à la même vitesse. Déclinaison .nav (pointe à droite,
     statique) pour « ça ouvre un écran » — naviguer n'est pas déplier ;
     .nav.back pointe à gauche. Les ‹ › des fiches restent des glyphes : ils
     avancent dans une liste, ils ne déplient rien. */
  .chev{
    display:inline-block; flex:0 0 auto;
    width:8px; height:8px;
    border-right:2px solid currentColor;
    border-bottom:2px solid currentColor;
    transform:rotate(45deg);
    position:relative; top:-2px;
    /* top est anime avec la rotation : la pointe du chevron n'est pas au centre
       de sa boite (elle depasse de 2,8 px du cote ou elle pointe), d'ou le
       recalage. Ferme -2 / ouvert +2 : symetrique, et le glissement remplace le
       saut de 3 px qu'on voyait a l'ouverture. */
    transition:transform var(--d-normale) var(--courbe), top var(--d-normale) var(--courbe);
  }
  .chev.open{transform:rotate(-135deg); top:2px;}
  .chev.nav{transform:rotate(-45deg); top:0;}
  /* Le chevron déborde de sa boîte de 1,65 px de chaque côté quand il pivote :
     l'espace typographique qui le sépare du mot suivant est mangée. */
  .undo-link .chev{margin-right:4px;}
  .chev.nav.back{transform:rotate(135deg);}

  /* --- Cartes génériques --- */
  .log-panel, .score-card, .suggest-panel, .hide-panel, .app-tip, .mol-card{
    background:var(--soil-800);
    border:1px solid var(--line);
    border-radius:var(--radius);
    padding:16px;
    margin-bottom:12px;
  }
  /* Titre de carte et de section. Il etait en 12 px MAJUSCULES interlettrees
     grises — la combinaison la moins lisible qu'on puisse composer, et c'etait
     le texte le plus repete de l'appli. Pire : le meme style etait redefini
     quatre fois (.log-title, .app-tip-head, .set-title, .info-section h3) et
     servait a des <h2> et des <h3> de section, donc de vraies structures de
     document rendues en 12 px. Une seule regle maintenant, a taille de titre.
     L'ancien style survit sous .fs-label, pour ce qui est reellement secondaire
     (intitules de tuiles, legendes) : c'est LUI, l'intitule discret. */
  .log-title, .app-tip-head, .set-title, .info-section h3{
    font-size:var(--t-lg); font-weight:600;
    letter-spacing:-0.01em;
    color:var(--parchment);
    margin-bottom:12px;
  }
  /* Ligne d'invite du premier lancement (constat 02) : une phrase sous le champ,
     et rien d'autre à l'écran tant que le journal est vide. */
  .log-hint{font-size:var(--t-sm); line-height:1.5; color:var(--parchment-dim); margin-top:10px;}

  /* --- Champs --- */
  select, input[type=date], input[type=text]{
    font-family:var(--font);
    background:var(--soil-700);
    border:1px solid transparent;
    color:var(--parchment);
    border-radius:var(--r-md);
    padding:11px 14px;
    font-size:var(--t-md);
    flex:1 1 160px;
    min-width:0;
    transition:border-color var(--d-normale) var(--courbe), background var(--d-normale) var(--courbe);
  }
  select:focus, input:focus{outline:none; border-color:var(--action); background:var(--soil-800);}
  /* Le focus clavier n'était dessiné qu'à UN endroit de toute l'appli (.info-head) :
     partout ailleurs, on héritait de l'anneau par défaut du navigateur, qui n'a
     rien à voir avec le reste. Une règle, tous les boutons. Les champs de texte
     en sont exclus : ils ont déjà leur bordure dorée ci-dessus, et un input
     déclenche :focus-visible même à la souris — l'anneau apparaîtrait au clic. */
  button:focus-visible, select:focus-visible, summary:focus-visible,
  [tabindex]:not([tabindex="-1"]):focus-visible{
    outline:2px solid var(--action);
    outline-offset:2px;
    border-radius:var(--r-sm);
  }
  input::placeholder{color:var(--parchment-dim);}

  /* --- Composer (journal) --- */
  /* position:relative : c'est .log-row qui ancre desormais #acResults, sorti de
     .ac-wrap le 31/08/2026. Un enfant en position:absolute n'est pas un element
     flex, la ligne n'en est donc pas modifiee. */
  .log-row{display:flex; flex-wrap:wrap; gap:8px; position:relative;}
  /* « > button » et non « button » (corrige le 31/08/2026). La croix
     d'effacement du champ est aussi un <button> DANS .log-row : elle heritait du
     fond dore, du rembourrage 11/20 et du rayon de « Enregistrer », d'ou une
     pastille doree de 54 x 36 px dans un champ de 44 — les bords se
     chevauchaient. Le selecteur d'enfant direct ne prend que #logBtn. */
  .log-row > button{
    flex:0 0 auto;
    background:var(--action);
    color:#000;
    border:none;
    border-radius:9999px;
    padding:11px 20px;
    font-size:var(--t-md);
    font-weight:800;
    cursor:pointer;
    transition:filter var(--d-normale) var(--courbe), transform var(--d-vite) var(--courbe);
  }
  .log-row > button:hover{filter:brightness(1.1);}
  .log-row > button:active{transform:scale(0.98);}
  /* Le champ date ne s'étire pas : juste la place de « jj/mm/aaaa » + l'icône */
  /* Seconde ligne du composeur (constat 04) : deux boutons-textes discrets.
     La date à gauche — grise sur « Aujourd'hui », DORÉE dès qu'elle porte un
     autre jour, pour qu'on ne puisse pas enregistrer au mauvais endroit sans le
     voir. Le compte du jour à droite, qui déplie le récapitulatif. */
  /* .when-count seul : le bouton de date global (.when-toggle, .when-caret,
     .when-panel, .date-quick) a été retiré le 31/08/2026 avec la ligne « quand »
     du composeur — la date est désormais sur chaque ligne du panier
     (voir .basket-date). Ne reste que le compteur de notes du jour. */
  /* Titre a gauche, compteur du jour a droite (31/08/2026). */
  /* align-items:center et non baseline : la ligne peut porter un SVG (le badge
     du carnet), et un SVG n'a pas de ligne de base utile — aligné sur elle, il
     poussait le titre vers le bas ET se retrouvait décalé. C'est ce qui faisait
     paraître le titre du carnet « loin du haut du cadre » (31/08/2026).
     Le margin-bottom passe sur la RANGÉE : mis à zéro sur .log-title sans être
     rendu ailleurs, il collait le titre au champ de saisie. */
  .log-title-row{display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:12px;}
  .log-title-row .log-title{margin-bottom:0;}
  .when-count{
    flex:0 0 auto;
    background:none; border:none; padding:2px 0;
    font-family:var(--font); font-size:var(--t-sm); font-weight:600;
    color:var(--parchment-dim); cursor:pointer;
    display:inline-flex; align-items:center; gap:5px;
  }
  .when-count.on{color:var(--parchment);}
  .when-count:empty{display:none;}
  @media (hover:hover) and (pointer:fine){
    .when-count:hover{color:var(--action);}
  }
  .confirm-msg{font-size:var(--t-sm); color:var(--moss-bright); margin-top:10px;}
  .confirm-msg:empty{display:none;}
  .tip-trempage{
    margin-top:6px; padding-top:6px;
    border-top:1px solid var(--line);
    font-size:var(--t-sm); line-height:1.5; color:var(--parchment-dim);
  }

  /* --- « Astuce » (conseils sur l'appli, Journal ; « Le saviez-vous ? » jusqu'au 30/08/2026) ---
     Même carte que les autres panneaux du Journal (fond, bordure, rayon, marge
     hérités de la règle groupée plus haut) : seul le contenu diffère. */
  .app-tip-body{font-size:var(--t-sm); line-height:1.55; color:var(--parchment-dim);}
  .app-tip-body b{color:var(--parchment);}
  .app-tip-actions{margin-top:10px;}

  /* --- Autocomplete --- */
  /* flex-basis 160 et non 260 (corrigé le 2026-08-31). C'est la base — et non la
     largeur après rétrécissement — qui décide si une ligne flex se replie. Avec
     260, il fallait 260 + 8 (gap) + 122 (« Enregistrer ») = 390 px de ligne pour
     tenir sur un rang ; un téléphone de 390 px n'en offre que 324, et le bouton
     tombait seul en dessous SUR TOUS LES TÉLÉPHONES (mesuré à 360, 390, 412 et
     430 px — la bascule était vers 454).

     Attention au calcul : la ligne ne fait pas « largeur de l'écran moins 32 »
     mais moins 64 — .wrap met 16 px de chaque côté ET .log-panel remet 16 px.
     Sur un écran de 320 px il ne reste donc que 254 px de ligne. Avec 120, il
     faut 120 + 8 (gap) + 122 (« Enregistrer ») = 250 px : ça passe partout,
     jusqu'au plus étroit des téléphones encore en service.

     Baisser la base ne rétrécit le champ nulle part : elle ne décide QUE du
     point de repliement, et flex-grow:1 lui redonne ensuite toute la place
     libre — le champ fait toujours 194 px sur un téléphone de 390 et 442 px
     sur un grand écran, exactement comme avec 260. */
  .ac-wrap{position:relative; display:flex; flex:1 1 120px; min-width:0;}
  /* 46 et non 34 (04/09/2026, signalé par Éric : « bouton QR code coupé par le
     texte »). Mesuré : le bouton du scanner occupe 37 px depuis le bord droit
     du champ (right:10px + 27 px de large), le texte passait donc DESSOUS et
     donnait l'impression d'un bouton coupé. 46 = 37 + 9 px d'air. */
  .ac-wrap input{width:100%; padding-right:46px;}
  .ac-results{
    position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:30;
    display:none; max-height:360px; overflow-y:auto;
    background:var(--soil-800);
    border:1px solid var(--line);
    border-radius:var(--r-md);
    box-shadow:0 12px 40px rgba(0,0,0,0.7);
    /* même fondu d'apparition que les menus (rejoué à chaque affichage) */
    animation:popIn var(--d-vite) var(--courbe);
    transform-origin:top center;
  }
  /* Pied de liste : le catalogue est classé en entier, on n'en rend qu'une partie.
     Pas la classe .ac-result — cette ligne ne doit ni se cliquer ni se surligner
     au clavier (voir acLignes()). */
  .ac-more{
    padding:8px 14px; font-size:var(--t-sm); font-style:italic;
    color:var(--parchment-dim); background:var(--soil-700);
    border-bottom:1px solid var(--line);
  }
  .ac-result{
    padding:9px 14px; font-size:var(--t-md);
    border-bottom:1px solid var(--line);
    cursor:pointer;
    transition:background var(--d-vite) var(--courbe);
    display:flex; align-items:center; gap:11px;
  }
  /* Le dessin réutilise l'avatar des listes, en un peu plus petit. */
  .ac-result .ac-avatar{width:32px; height:32px; font-size:17px;}
  .ac-result .ac-main{flex:1 1 auto; min-width:0;}
  .ac-result:last-child{border-bottom:none;}
  .ac-result.hl{background:var(--hover);}
  @media (hover:hover) and (pointer:fine){
    .ac-result:hover{background:var(--hover);}
  }
  .ac-result .ac-name{color:var(--parchment); font-weight:600;}
  .ac-result .ac-hint{display:block; font-size:var(--t-sm); color:var(--parchment-dim); margin-top:2px;}
  /* display:block : .ac-result est un conteneur FLEX (avatar + texte). Sur la
     ligne « + en faire une <b>recette</b> (plusieurs ingredients) », les trois
     morceaux — texte, <b>, texte — devenaient trois elements flex separes par le
     gap de 11 px, d'ou l'affichage sur trois lignes avec « recette » seul au
     milieu. Cette ligne n'a pas d'avatar : elle n'a rien a faire en flex. */
  .ac-result.ac-new{display:block; color:var(--action); font-weight:600;}
  .ac-preview{
    margin-top:10px; padding:12px;
    background:var(--soil-700);
    border-radius:var(--r-md);
    font-size:var(--t-sm); color:var(--parchment-dim);
    display:none;
  }
  /* Bloc, pas rangée : chaque entrée du panier est une ligne à part entière
     (nom + ce qu'elle coche + ses boutons), « Tout annuler » ferme la liste. */
  .ac-preview.show{display:block;}
  .ac-cancel{
    display:inline-block; margin-top:10px;
    background:transparent;
    border:1px solid var(--rust);
    color:var(--rust);
    border-radius:9999px;
    padding:8px 14px;
    font-size:var(--t-sm); font-weight:700;
    cursor:pointer;
  }
  .ac-cancel:hover{background:var(--rust-dim); color:#fff;}
  .new-food-form{
    margin-top:10px; padding:12px;
    background:var(--soil-700);
    border-radius:var(--r-md);
    display:none; flex-direction:column; gap:8px;
  }
  .new-food-form.show{display:flex;}
  .new-food-form .nf-label{
    font-size:var(--t-xs); font-weight:700;
    text-transform:uppercase; letter-spacing:0.8px;
    color:var(--parchment-dim);
  }
  .new-food-form .nf-row{display:flex; gap:8px; flex-wrap:wrap;}

  /* --- Composer une recette (créer / modifier) --- */
  .recipe-form input[type="text"]{
    width:100%; box-sizing:border-box;
    background:var(--soil-800); color:var(--parchment);
    border:1px solid var(--line); border-radius:var(--r-md);
    padding:9px 12px; font-size:var(--t-md); font-family:inherit;
    /* La regle globale des champs porte flex:1 1 160px ; dans une colonne flex,
       « grandir » veut dire grandir en HAUTEUR — le champ devenait une grosse
       boite vide. On le remet a sa hauteur naturelle. */
    flex:0 0 auto;
  }
  .recipe-form input[type="text"]:focus{outline:none; border-color:var(--action);}
  .recipe-guide{
    font-size:var(--t-sm); line-height:1.5;
    color:var(--parchment-dim);
    background:rgba(245,184,46,0.06);
    border-left:3px solid var(--action);
    border-radius:0 var(--r-sm) var(--r-sm) 0;
    padding:9px 12px;
  }
  .recipe-guide b{color:var(--action);}
  .recipe-field{display:flex; flex-direction:column; gap:6px;}
  .recipe-label{
    font-size:var(--t-xs); font-weight:700;
    text-transform:uppercase; letter-spacing:0.6px;
    color:var(--parchment-dim);
  }
  /* Suggestions : liste courte qui n'apparaît que pendant la frappe. */
  .recipe-results{display:none; flex-direction:column; gap:2px; max-height:190px; overflow-y:auto;}
  .recipe-results.show{display:flex;}
  .recipe-results .rr-item{
    text-align:left; width:100%;
    background:var(--soil-800); color:var(--parchment);
    border:1px solid var(--line); border-radius:var(--r-sm);
    padding:7px 10px; font-size:var(--t-sm); font-family:inherit; cursor:pointer;
  }
  .recipe-results .rr-item:hover{border-color:var(--action); color:var(--action);}
  .recipe-results .rr-cat{color:var(--parchment-dim); font-size:var(--t-xs);}
  .recipe-chips{display:flex; flex-wrap:wrap; gap:6px;}
  .recipe-chips:empty{display:none;}
  .recipe-chip{
    display:inline-flex; align-items:center; gap:6px; white-space:nowrap;
    background:var(--soil-800); border:1px solid var(--line);
    border-radius:9999px; padding:5px 10px; font-size:var(--t-sm);
  }
  .recipe-chip button{
    background:none; border:none; color:var(--parchment-dim);
    cursor:pointer; font-size:var(--t-md); line-height:1; padding:0;
  }
  .recipe-chip button:hover{color:var(--rust);}
  .recipe-chosen{display:flex; flex-wrap:wrap; gap:6px;}
  .recipe-chosen:empty{display:none;}
  .recipe-chosen .recipe-chip{border-color:var(--action); color:var(--action);}
  .recipe-preview{
    font-size:var(--t-sm); line-height:1.5;
    color:var(--parchment-dim);
    border-top:1px solid var(--line);
    padding-top:9px;
  }
  .recipe-preview b{color:var(--moss-bright);}
  .recipe-preview:empty{display:none;}
  /* Liste « Mes recettes » des Paramètres. */
  .my-recipe{
    display:flex; align-items:center; gap:10px; flex-wrap:wrap;
    padding:9px 0; border-bottom:1px solid var(--line);
  }
  .my-recipe:last-child{border-bottom:none;}
  .my-recipe-main{flex:1 1 200px; min-width:0;}
  .my-recipe-name{font-weight:700; font-size:var(--t-md);}
  .my-recipe-detail{font-size:var(--t-sm); color:var(--parchment-dim); margin-top:2px;}

  /* Pastilles : encore utilisées par le récap du jour (.recap-chips). */
  .basket-chip{
    display:inline-flex; align-items:center; gap:4px; white-space:nowrap;
    background:var(--soil-800);
    border:1px solid var(--line);
    border-radius:9999px;
    padding:4px 6px 4px 12px;
    font-size:var(--t-sm);
    color:var(--parchment);
  }
  .basket-chip .basket-remove{padding:4px 6px; border-radius:0;}
  .basket-chip .basket-remove:hover{background:none;}

  /* --- Panier repas ---
     Une ligne par aliment, le dernier ajouté en haut. En pastilles, les boutons
     se chevauchaient dès trois ou quatre entrées. */
  .basket-list{margin-bottom:2px;}
  /* Deux étages : la ligne du haut porte le nom et les commandes, le détail
     occupe TOUTE la largeur en dessous (31/08/2026). Le détail était coincé à
     côté du bouton de date et « Crucifères » passait à la ligne pour rien. */
  /* LE FILET SÉPARE DEUX ENTRÉES, PANNEAUX COMPRIS (04/09/2026, signalé par
     Éric : « la zone d'explication est collée à la ligne qui délimite le haut
     de cette zone… même si on n'a ajouté qu'un aliment ! »). Il était porté
     par .basket-row, or les panneaux « pourquoi » et « préparation » vivent
     APRÈS elle : dès qu'on en ouvrait un, la ligne cessait d'être :last-child,
     le filet réapparaissait — collé au-dessus du panneau — et il ne séparait
     plus rien. Il est maintenant sur .basket-item, qui enveloppe la ligne ET
     ses panneaux : au-dessus de rien quand l'entrée est seule, exactement
     entre deux entrées sinon. */
  .basket-item{padding:7px 0; border-bottom:1px solid var(--line);}
  .basket-list > .basket-item:last-child{border-bottom:none;}
  .basket-row{font-size:var(--t-sm); color:var(--parchment);}
  /* Le nom et LA CROIX SEULE, collée au bord droit. */
  .basket-haut{display:flex; align-items:flex-start; gap:8px;}
  .basket-haut .basket-name{flex:1 1 auto; min-width:0;}
  /* Date de LA note, sur sa ligne (31/08/2026). Discrète tant qu'elle dit
     « Aujourd'hui », dorée dès qu'elle dit autre chose — même signal que
     l'ancien bouton global, mais à côté de ce qu'il date. */
  /* (gabarit commun : voir .basket-pill) */
  /* Le chevron dit « ça s'ouvre » : sans lui, rien n'indiquait que la date se
     touche (31/08/2026, demandé par Éric). Il est plus petit que les autres,
     pour tenir dans une pilule de 11 px de texte. */
  .basket-pill .chev{width:5px; height:5px; border-width:1.5px; margin-left:1px;}
  .basket-date:hover{color:var(--parchment); border-color:var(--parchment-dim);}
  .basket-date.autre{color:var(--wheat); border-color:var(--wheat-dim); font-weight:700;}
  /* Le champ natif ne sert qu'à ouvrir le sélecteur : il ne doit pas prendre de
     place ni de tabulation (le bouton juste avant fait les deux). */
  .basket-date-input{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    border:0; opacity:0; pointer-events:none;
  }
  /* Deux lignes au plus, puis on coupe : celui qui vient de taper l'aliment le
     reconnaît, et la ligne du panier ne peut plus enfler (04/09/2026). */
  .basket-name{
    color:var(--parchment); font-weight:600; line-height:1.35; overflow-wrap:anywhere;
    display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden;
  }
  /* UN SEUL GABARIT POUR LES TROIS PILULES (04/09/2026 — « boutons aujourd'hui,
     pourquoi et préparation ne sont pas de la même taille »). Elles étaient
     écrites trois fois, avec trois rembourrages et deux tailles de police. Le
     gabarit est ici ; chaque pilule ne garde que sa couleur d'état. */
  .basket-actions{display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:7px;}
  .basket-pill{
    flex:0 0 auto;
    display:inline-flex; align-items:center; gap:6px;
    background:none; border:1px solid var(--line); border-radius:var(--r-full);
    padding:3px 10px; min-height:24px;
    font-family:var(--font); font-size:var(--t-xs); font-weight:600; line-height:1.5;
    color:var(--parchment-dim); cursor:pointer; white-space:nowrap;
    transition:color var(--d-normale) var(--courbe), border-color var(--d-normale) var(--courbe);
  }
  .basket-detail{margin-top:2px; font-size:var(--t-sm); line-height:1.45; color:var(--parchment-dim); overflow-wrap:anywhere;}
  .basket-why:hover{color:var(--action); border-color:var(--action);}
  .basket-why.open{color:var(--action); border-color:var(--action); background:rgba(245,184,46,0.08);}
  .basket-why-panel{border-radius:var(--r-sm); margin:8px 0 5px;}
  /* La croix n'est PAS une pilule : elle a un autre métier (retirer), sa place
     canonique est le coin haut droit, et lui donner le même cadre que les trois
     actions l'aurait noyée parmi elles. */
  .basket-remove{
    flex:0 0 auto;
    background:none; border:none;
    color:var(--parchment-dim);
    cursor:pointer; font-size:var(--t-md); line-height:1;
    padding:2px 4px; margin:-2px -4px 0 0; border-radius:var(--r-sm);
  }
  .basket-remove:hover{color:var(--rust); background:var(--hover);}
  .undo-link{color:var(--action); text-decoration:underline; text-underline-offset:3px; cursor:pointer;}

  /* --- Le secondaire du Journal : une seule ligne, sous l'anneau ---
     (constat 01) Cinq cartes — accueil, suggestions, défi, palier, astuce —
     restent rendues par leurs fonctions habituelles, mais UNE SEULE s'affiche à
     la fois sous 1520 px, en rotation d'un jour à l'autre. On lui retire tout
     habillage de carte : ce n'est plus une carte de plus, c'est la suite de
     l'anneau. Au-delà de 1520 px, le JS déplace le conteneur dans la colonne de
     droite et les cinq s'y déplient (règles dans le bloc @media 1520). */
  /* LE CADRE EST REVENU (04/09/2026, signalé par Éric : « le texte "défi de la
     semaine" apparaît sans section, au milieu de la page Journal »). Le 30/08
     on avait retiré tout habillage parce que ces cartes étaient CINQ de plus
     dans une colonne qui en montrait neuf. Depuis, elles tournent : il n'y en a
     qu'UNE à l'écran. Une carte de plus sur quatre ne fait pas un mur ; un
     paragraphe sans cadre au milieu de deux cartes, si — il se lit comme un
     texte tombé là. Le conteneur reprend donc le même habillage que les autres
     cartes du Journal, et le titre son style de titre de carte. */
  #journalSecondary.sec-ligne{margin:0;}
  #journalSecondary.sec-ligne > *{
    background:var(--soil-800);
    border:1px solid var(--line);
    border-radius:var(--radius);
    padding:16px;
    margin:0 0 12px;
  }
  /* Le TITRE reste (corrigé le 30/08/2026, C-4 de l'audit) : enlever le cadre,
     oui — c'est ce qui évite une carte de plus ; enlever le nom laissait un
     paragraphe orphelin entre deux cartes, sans cadre et sans intitulé, suivi
     d'un bouton « une autre → ». Ça se lisait comme un message d'erreur. Il
     passe en intitulé discret, à la taille de ce qu'il annonce. */
  #journalSecondary.sec-ligne .challenge-history{display:none;}
  /* Le titre redevient un titre de carte, comme partout ailleurs — l'intitulé
     discret ne se justifiait que sans cadre. */
  #journalSecondary.sec-ligne .log-title,
  #journalSecondary.sec-ligne .app-tip-head{margin:0 0 8px;}
  #journalSecondary.sec-ligne .suggest-row,
  #journalSecondary.sec-ligne .app-tip-body,
  #journalSecondary.sec-ligne .challenge-row{
    font-size:var(--t-sm); line-height:1.55; color:var(--parchment-dim);
  }

  /* La ligne d'action, sous l'anneau : la seule chose qu'on vient chercher et
     que le score ne dit pas — quoi manger aujourd'hui. Elle vivait dans la
     carte Suggestions, quatre cartes plus bas. */
  .score-action{
    margin-top:12px; padding-top:11px;
    border-top:1px solid var(--line);
    font-size:var(--t-md); line-height:1.5;
    color:var(--parchment-dim);
  }
  .score-action b{color:var(--parchment); font-weight:700;}
  .score-action .score-late{color:var(--wheat); font-size:var(--t-sm);}
  .score-action.ok{color:var(--moss-bright);}

  /* Aliment à découvrir : c'est un vrai bouton, il pré-remplit la saisie. Il
     l'était déjà dans la colonne de droite du grand écran ; il l'est maintenant
     partout, puisqu'il n'y a plus qu'une seule carte de suggestions. */
  /* .sug-food a disparu le 31/08/2026 : les suggestions ne sont plus des
     boutons mais des lignes de lecture (.sug-item). */

  /* --- L'anneau de score : quatre paliers, et une récompense ---
     Rouge sous 25 %, or sous 50 %, vert sous 75 %, et au-delà un vert vif QUI
     S'ALLUME. C'est le seul endroit de l'appli qui brille : une récompense ne
     vaut que si elle est rare, et si on la voit sans la chercher.
     La pulsation s'arrête d'elle-même pour qui a coché « réduire les
     animations » (règle globale body.reduce-motion) ; la lueur fixe, elle,
     reste — ce n'est pas du mouvement, c'est de la couleur. */
  /* Le halo est un ANNEAU DESSINÉ (.score-arc-halo, tracé épais et translucide
     posé sous le trait), pas seulement une ombre portée : une ombre de 4 px sur
     un trait de 5 px ne se voit pas, et le <svg> la découpait à son cadre.
     D'où overflow:visible sur l'anneau, et la lueur en deux couches — l'anneau
     translucide qu'on voit en permanence, l'ombre portée qui l'adoucit. */
  .score-arc{overflow:visible;}
  .score-arc-halo{
    opacity:0.28;
    filter:blur(2.5px);
    animation:scoreHalo 2.6s ease-in-out infinite;
  }
  .score-arc.sc-top .score-arc-fill{
    filter:drop-shadow(0 0 5px var(--moss-bright));
    animation:scoreLueur 2.6s ease-in-out infinite;
  }
  /* Le chiffre passe lui aussi au vert vif : c'est ce qu'on regarde en premier,
     autant qu'il porte le signal. (Une propriété CSS l'emporte sur l'attribut
     fill= du SVG, il n'y a rien d'autre à changer.) */
  .score-arc.sc-top .score-arc-val{fill:var(--moss-bright);}
  @keyframes scoreHalo{
    0%, 100%{opacity:0.20;}
    50%{opacity:0.52;}
  }
  @keyframes scoreLueur{
    0%, 100%{filter:drop-shadow(0 0 3px var(--moss-bright));}
    50%{filter:drop-shadow(0 0 10px var(--moss-bright));}
  }
  /* L'étincelle : un éclat clair qui fait LE TOUR de l'anneau en ~1,8 s, puis
     se tait pendant ~5 s. C'est l'effet « boule de cristal » demandé le
     30/08/2026 : sporadique — un événement, pas un état. Rotation en CSS (la
     propriété transform l'emporte sur l'attribut, donc pas d'attribut transform
     sur ce cercle) ; base opacity:0, donc invisible quand « réduire les
     animations » coupe les animations. Tempo propre : c'est de l'ambiance, pas
     une réponse à un geste — hors système --d-*. */
  /* L'ÉCLAT. Premier essai : un petit segment clair qui faisait le tour de
     l'anneau. Mesuré au banc de captures : il ne se voyait pas — trop pâle sur
     le vert vif, et présent une seconde sur sept. Celui-ci allume TOUT l'arc en
     blanc, deux fois de suite, comme un reflet qui passe sur du verre. On ne
     peut pas le manquer, et il reste rare : 0,7 s toutes les 5 s.
     opacity:0 en base : animations coupées, il ne reste rien d'inerte à l'écran
     (le halo, lui, est fixe et demeure). */
  .score-arc-glint{
    opacity:0;
    filter:drop-shadow(0 0 7px #ffffff);
    animation:scoreEclat 5s ease-out 1s infinite;
  }
  @keyframes scoreEclat{
    0%, 84%  {opacity:0;}
    87%      {opacity:0.95;}
    90%      {opacity:0.15;}
    93%      {opacity:0.8;}
    100%     {opacity:0;}
  }
  /* Les sous-scores et les vignettes reprennent le même signal, en plus discret. */
  .score-sub-item.sc-top{text-shadow:0 0 8px rgba(0,214,143,0.45); font-weight:700;}
  .score-mini.sc-top{border-color:rgba(0,214,143,0.35);}
  .score-mini.sc-top .score-mini-val{color:var(--moss-bright);}

  /* --- Score de diversité --- */
  .score-card{position:relative; cursor:pointer; user-select:none;}
  .score-card:empty{display:none;}
  .score-card.open{cursor:default;}
  .score-head{display:flex; align-items:center; gap:14px;}
  /* SOUS 520 px, LES QUATRE SOUS-SCORES PASSENT SOUS L'ANNEAU (04/09/2026,
     signalé par Éric : « intitulés des sous-scores coupés sur téléphone »).
     Mesuré : à 360 px la colonne de droite ne fait plus que 120 px et trois des
     quatre intitulés se plient sur deux lignes (38 px au lieu de 19) ; à 390 px
     avec le texte agrandi, les quatre. Pleine largeur, ils tiennent tous sur
     une ligne. L'anneau garde ses deux boutons à sa droite. */
  @media (max-width:519px){
    .score-head{flex-wrap:wrap;}
    .score-arc-wrap{margin-right:auto;}
    .score-info{order:3; flex:1 0 100%; margin-top:10px;}
  }
  .score-arc-wrap{flex:0 0 auto;}
  .score-info{flex:1 1 auto; min-width:0;}
  .score-sub{display:flex; flex-wrap:wrap; gap:4px 16px; font-size:var(--t-sm);}
  .score-sub-item{font-weight:600;}
  .score-sub-item.locked{color:var(--parchment-dim); opacity:0.55; font-weight:400;}
  .score-chevron{
    display:inline-flex; align-items:center; justify-content:center;
    flex:0 0 auto; align-self:center;
    width:34px; height:34px;
    display:flex; align-items:center; justify-content:center;
    border:1px solid var(--line); border-radius:50%;
    font-size:16px; line-height:1;
    color:var(--parchment-dim); cursor:pointer;
    transition:background var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe);
  }
  .score-chevron:hover{background:var(--hover); color:var(--parchment);}
  .score-details{
    margin-top:12px; padding-top:12px;
    border-top:1px solid var(--line);
    font-size:var(--t-sm); color:var(--parchment-dim); line-height:1.7;
  }
  .score-details b{color:var(--parchment); font-weight:700;}
  /* Un anneau par sous-score, en deux groupes : ce qui entre dans le score global,
     et le socle qui n'y entre pas. La separation doit rester lisible d'un coup d'oeil,
     c'est tout l'interet d'avoir sorti les fenetres longues de l'anneau. */
  .score-group{margin-bottom:16px;}
  .score-group-title{
    font-size:var(--t-xs); font-weight:700; text-transform:uppercase; letter-spacing:0.8px;
    color:var(--parchment-dim); margin-bottom:4px;
  }
  /* Le titre du long terme est BLANC comme les autres (31/08/2026, demandé par
     Éric). Il était en or — or l'or signale partout ailleurs une action ou une
     réussite, pas une section. */
  .score-group-sub{font-size:var(--t-sm); line-height:1.55; color:var(--parchment-dim); margin-bottom:10px;}
  /* Une vignette par sous-score : anneau + intitulé + valeur brute. Choix d'Éric
     du 2026-08-31, après avoir essayé les barres : la forme est celle du grand
     anneau du haut, donc les six vignettes se lisent avec le même œil que le
     score global. Deux colonnes, une seule sous 430 px (voir plus bas). */
  .score-mini-grid{display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px;}
  .score-comment{
    background:none; border:none; padding:2px 0;
    font-family:var(--font); font-size:var(--t-sm); color:var(--parchment-dim);
    text-decoration:underline; text-underline-offset:3px; cursor:pointer;
  }
  .score-comment:hover{color:var(--action);}
  .score-mini{
    display:flex; align-items:center; gap:9px; min-width:0;
    background:var(--soil-700); border-radius:var(--r-md); padding:8px 10px;
  }
  .score-mini.locked{opacity:0.55;}
  .score-mini-arc{flex:0 0 auto; line-height:0;}
  .score-mini-txt{min-width:0;}
  .score-mini-lbl{
    font-size:var(--t-sm); font-weight:700; color:var(--parchment);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  /* Le détail PASSE À LA LIGNE (31/08/2026). Il était en nowrap + ellipse, hérité
     du temps où il tenait en trois mots (« 15 / 30 plantes ») ; depuis qu'il
     explique ce que mesure le pourcentage, « chaque catégorie tenue à son
     rythme » se faisait couper à « son ryth… » — une explication tronquée
     n'explique rien. Les six vignettes sont dans une grille, elles gardent donc
     la même hauteur même si l'une passe sur deux lignes. */
  .score-mini-val{
    font-size:var(--t-sm); line-height:1.35; color:var(--parchment-dim);
  }
  /* Deux vignettes côte à côte ne tiennent plus sous 430 px : l'anneau fait
     44 px et le libellé passerait sous l'ellipse dès « Rythme 12 mois ». */
  @media (max-width:430px){
    .score-mini-grid{grid-template-columns:1fr;}
  }
  .trend-wrap{margin-top:4px;}
  .trend-legend{font-size:var(--t-xs); color:var(--parchment-dim); margin-top:4px;}
  .trend-svg{display:block; max-width:100%;}

  /* --- Suggestions & rappels --- */
  /* UN SEUL CORPS DE TEXTE POUR TOUT LE SECONDAIRE (31/08/2026). Les cinq
     cartes avaient chacune sa taille et son encre : suggestions en 15 px encre
     pleine, astuce en 13 px gris, défi en 15 px, palier en 15 px. Elles disent
     toutes la même sorte de chose — un état, une invitation — et se lisent donc
     de la même façon : 13 px, gris, l'encre pleine réservée à ce qui compte
     (un nom, un nombre). Une seule règle pour les quatre. */
  .suggest-row, .app-tip-body, .challenge-why, .challenge-history{
    font-size:var(--t-sm); line-height:1.55; color:var(--parchment-dim); margin-top:6px;
  }
  .suggest-row b, .app-tip-body b, .challenge-why b{color:var(--parchment); font-weight:700;}
  /* Le motif de liste du panneau : une ligne cliquable, le nom en encre pleine,
     la raison dessous en gris. Le même que les lignes de réglage et que le menu
     des sections — l'appli n'a qu'un dialecte de liste. */
  .volet-liste{display:flex; flex-direction:column; margin-top:6px;}
  /* Une ligne de lecture, pas un bouton (31/08/2026) : ni curseur, ni survol,
     ni cible de clic. Le nom en encre pleine, la raison dessous en gris. */
  .volet-liste .sug-item{
    display:flex; flex-direction:column; align-items:flex-start; gap:1px;
    border-bottom:1px solid var(--line);
    padding:7px 0;
  }
  .volet-liste .sug-item:last-child{border-bottom:none;}
  .sug-nom{font-size:var(--t-sm); font-weight:700; color:var(--parchment);}
  /* 13 px comme tout le corps de la colonne (31/08/2026, Eric : « y a 20 typo,
     c est difficilement lisible »). Elle etait a 11 px : une cinquieme taille
     dans un panneau qui en comptait deja huit, et du gris pale de 11 px se lit
     mal. La colonne n a plus que TROIS roles de texte : titre 17/600 encre,
     corps 13/400 gris, element fort 13/700 encre. */
  .sug-raison{font-size:var(--t-sm); font-weight:400; line-height:1.45; color:var(--parchment-dim);}
  /* Bandeau d avertissement, pas une carte : rayon et rembourrage reduits pour
     qu il ne compte pas comme un des trois blocs du Journal (constat 01). */
  /* Le bandeau de rappel de sauvegarde a ete retire le 31/08/2026 (demande
     d Eric : les comptes le remplaceront). Ses styles partent avec lui. */

  /* --- Cartes de catégories --- */
  .cat{
    background:var(--soil-800);
    border:1px solid var(--line);
    border-radius:var(--radius);
    margin-bottom:10px;
    overflow:hidden;
    transition:border-color var(--d-normale) var(--courbe);
  }
  .cat:hover{border-color:#3a423e;}
  .cat-head{
    display:flex; align-items:center; gap:14px;
    padding:14px 16px;
    cursor:pointer;
    transition:background var(--d-normale) var(--courbe);
  }
  @media (hover:hover) and (pointer:fine){
    .cat-head:hover{background:var(--hover);}
  }
  .arc-wrap{flex:0 0 auto;}
  .cat-info{flex:1 1 auto; min-width:0;}
  .cat-name{font-size:var(--t-md); font-weight:700; color:var(--parchment); letter-spacing:-0.1px;}
  .cat-meta{font-size:var(--t-sm); color:var(--parchment-dim); margin-top:2px;}
  .cat-meta .divider{opacity:0.4; margin:0 6px;}
  /* Le glyphe « ▸ » a été remplacé par le composant .chev (B-3 de l'audit du
     30/08/2026) : c'était le dernier des cinq dialectes de chevron qui avaient
     été unifiés, et sur seize lignes affichées d'un coup, il se voyait. */
  .chevron{flex:0 0 auto; color:var(--parchment-dim); display:inline-flex; align-items:center; padding-left:2px;}
  .cat.open .chevron .chev{transform:rotate(-135deg); top:2px;}
  /* Quatrième état : une catégorie que le journal n'a pas encore eu le temps de
     voir passer. Ni verte ni rouge — elle n'a rien à se reprocher. */
  .cat.neuf{border-left:3px solid var(--line);}
  .cat.good{border-left:3px solid var(--moss);}
  .cat.warn{border-left:3px solid var(--wheat);}
  .cat.overdue{border-left:3px solid var(--rust);}
  .cat.neuf, .cat.good, .cat.warn, .cat.overdue{border-left-width:4px;}
  /* FOND TEINTÉ, remis le 31/08/2026 à la demande d'Éric. Le C-5 du 30/08
     l'avait retiré (« le même fait écrit trois fois — anneau, filet, fond — sur
     neuf cartes rouges d'affilée »). Ce qui rendait l'écran illisible n'était
     pas le fond mais le NOMBRE de cartes rouges : jamais notée comptait pour en
     retard, donc presque tout était rouge. Maintenant qu'une catégorie pas
     encore découverte reste neutre (voir catVisualState), les couleurs sont
     rares et le fond redevient lisible.
     Trois précautions : la teinte est sur .cat-head et non sur .cat, pour ne pas
     déborder sur la liste dépliée ; elle reste très basse (5 à 7 %) — c'est un
     fond, pas un aplat ; et .cat.neuf n'en reçoit AUCUNE, c'est tout l'objet de
     la demande. */
  .cat.good .cat-head{background:rgba(0,186,124,0.07);}
  .cat.warn .cat-head{background:rgba(245,184,46,0.07);}
  .cat.overdue .cat-head{background:rgba(244,33,46,0.06);}
  @media (hover:hover) and (pointer:fine){
    .cat.good .cat-head:hover{background:rgba(0,186,124,0.12);}
    .cat.warn .cat-head:hover{background:rgba(245,184,46,0.12);}
    .cat.overdue .cat-head:hover{background:rgba(244,33,46,0.11);}
  }
  .items{display:none; border-top:1px solid var(--line);}
  .cat.open .items{display:block;}
  .group-label{
    font-size:var(--t-xs); font-weight:700;
    text-transform:uppercase; letter-spacing:1px;
    color:var(--parchment-dim);
    padding:12px 16px 4px 20px;
  }

  /* --- Lignes d'aliments --- */
  /* Liste compacte : dans la page Catégories, on vient parcourir des dizaines de
     lignes d'un coup d'œil, pas les contempler une par une. Hauteur ramenée de
     45 à ~34 px le 2026-08-29 — même règle pour le téléphone et le grand écran,
     il n'y a pas de variante par taille ici. */
  .item{
    display:flex; align-items:center; gap:8px;
    padding:5px 14px 5px 16px;
    border-bottom:1px solid var(--line);
    transition:background var(--d-vite) var(--courbe);
  }
  /* La ligne entière ouvre la fiche depuis le 04/09/2026 : le curseur doit le
     dire, et le focus clavier doit se voir (elle porte role="button"). */
  .item[data-action]{cursor:pointer;}
  .item[data-action]:focus-visible{outline:2px solid var(--action); outline-offset:-2px;}
  @media (hover:hover) and (pointer:fine){
    .item:hover{background:var(--hover);}
  }
  .item:last-child{border-bottom:none;}
  /* AUCUN nom ne passe a la ligne (30/08/2026). Un nom coupe par « … » se lit ;
     un nom sur deux lignes casse le rythme de toute la liste. min-width:0 est
     indispensable : sans lui, un enfant de flex refuse de retrecir sous la
     largeur de son texte et l'ellipse ne se declenche jamais. */
  .item-name{
    flex:1 1 auto; min-width:0;
    font-size:var(--t-md); color:var(--parchment); line-height:1.25;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  /* La date ne reserve plus 74 px quand elle est vide — c'etait 74 px pris au
     nom sur toutes les lignes jamais goutees, pour n'afficher rien. Et elle est
     ecrite court (« 30/08 ») : une liste n'a pas la place d'une date complete. */
  .item-days{font-size:var(--t-sm); color:var(--parchment-dim); flex:0 0 auto; text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap;}
  .item-days:empty{display:none;}
  .dot{width:8px; height:8px; border-radius:50%; flex:0 0 auto;}
  .item .stats-btn, .item .fav-btn, .item .menu-btn{
    background:none; border:none;
    color:var(--parchment-dim);
    cursor:pointer; font-size:var(--t-md);
    /* 30 px de zone tactile pour une ligne de 34 : la marge négative laisse le
       bouton mordre sur le padding sans faire grandir la ligne. */
    width:30px; height:30px;
    margin:-6px -2px;
    border-radius:50%;
    flex:0 0 auto;
    display:inline-flex; align-items:center; justify-content:center;
    transition:background var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe), transform var(--d-vite) var(--courbe);
  }
  /* retour visuel au clic : le bouton rond se comprime brièvement, façon X */
  .item .stats-btn:active, .item .fav-btn:active,
  .item .menu-btn:active{transform:scale(0.85);}
  .item .stats-btn:hover, .item .fav-btn:hover, .item .menu-btn:hover{color:var(--parchment); background:var(--hover);}
  .item .menu-btn{font-size:17px; font-weight:700;}
  .item .item-name.dex-link{cursor:pointer;}
  .item .item-name.dex-link:hover{color:var(--action);}
  .item .item-name.undiscovered{opacity:0.6; font-size:0.95em;}

  /* Sous 640 px, la colonne occupe tout l'ecran et le nom n'a plus que ~86 px.
     Les deux raccourcis (favori, statistiques) quittent la ligne : ils sont de
     toute facon proposes dans le menu ⋮, qui reste. 80 px rendus au nom. */
  @media (max-width:640px){
    .item .fav-btn, .item .stats-btn{display:none;}
  }

  /* --- Lignes d'aliments façon WhatsApp (onglet Aliments uniquement) --- */
  .wa-row{
    padding:4px 12px 4px 14px;
    gap:12px;
    align-items:center;
    border-bottom:none;
    position:relative;
    cursor:pointer;
  }
  /* Le filet part sous l'ICÔNE (left:14px, le bord gauche de l'avatar) et non
     sous le texte (62px = 14 de marge + 36 d'avatar + 12 de gouttière). Un trait
     qui démarre au milieu de la ligne laisse l'avatar flotter au-dessus du vide
     (31/08/2026, relevé par Éric). */
  .wa-row::after{
    content:"";
    position:absolute; left:14px; right:0; bottom:0;
    height:1px; background:var(--line);
  }
  .wa-row:last-child::after, .wa-row:has(+ .dex-panel)::after,
  .wa-row:has(+ .stats-panel)::after, .wa-row:has(+ .edit-panel)::after{display:none;}
  .wa-avatar{
    width:36px; height:36px; flex:0 0 auto;
    border-radius:50%;
    background:var(--soil-700);
    display:flex; align-items:center; justify-content:center;
    font-size:19px; line-height:1;
    overflow:hidden;
    user-select:none;
  }
  .wa-avatar svg{width:70%; height:70%; display:block;}
  /* non découverts : avatar entièrement grisé, pour un contraste net avec les validés */
  .wa-row.row-undiscovered .wa-avatar{opacity:0.4; filter:grayscale(1);}
  .wa-main{
    flex:1 1 auto; min-width:0;
    display:flex; align-items:center;
  }
  .wa-main .item-name{font-size:var(--t-md); font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
  .wa-main{min-width:0;}
  .wa-time{flex:0 0 auto; font-size:var(--t-sm); color:var(--parchment-dim); font-variant-numeric:tabular-nums; white-space:nowrap;}
  .wa-time.recent{color:var(--moss); font-weight:700;}
  .wa-actions{flex:0 0 auto; display:inline-flex; align-items:center;}
  /* à la souris, les actions n'apparaissent qu'au survol de la ligne (comme WhatsApp Web) */
  @media (hover:hover) and (pointer:fine){
    .wa-row .wa-actions{opacity:0; transition:opacity var(--d-vite) var(--courbe);}
    .wa-row:hover .wa-actions, .wa-row:focus-within .wa-actions{opacity:1;}
  }

  /* --- Menu d'actions flottant (⋮), façon X --- */
  .action-menu{
    position:fixed; z-index:120;
    background:#000;
    border:1px solid var(--line);
    border-radius:var(--r-md);
    min-width:230px;
    overflow:hidden;
    box-shadow:0 0 15px rgba(255,255,255,0.08), 0 10px 34px rgba(0,0,0,0.85);
    /* apparition en fondu + léger zoom, façon menus de X (rejouée à chaque ouverture) */
    animation:popIn var(--d-vite) var(--courbe);
    transform-origin:top right;
  }
  @keyframes popIn{from{opacity:0; transform:scale(0.96);} to{opacity:1; transform:scale(1);}}
  .action-menu-item{
    display:flex; align-items:center; gap:12px; width:100%;
    background:none; border:none;
    color:var(--parchment);
    font-size:var(--t-md); font-weight:700;
    text-align:left;
    padding:13px 16px;
    cursor:pointer;
    transition:background var(--d-vite) var(--courbe);
  }
  .action-menu-item svg{flex:0 0 auto;}
  .item .fav-btn.on{color:var(--action);}
  .item .fav-btn svg, .item .stats-btn svg{display:block;}
  .group-label svg{width:12px; height:12px; vertical-align:-2px; margin-right:3px; color:var(--action);}
  .action-menu-item:hover{background:var(--hover);}
  .action-menu-item.danger{color:var(--rust);}

  /* --- Pile de toasts (messages temporaires en bas d'écran) --- */
  .toast-stack{
    position:fixed;
    bottom:calc(72px + env(safe-area-inset-bottom));
    left:calc(50% + var(--dec));
    transform:translateX(-50%);
    width:min(420px, calc(100% - 24px));
    z-index:130;
    display:flex;
    flex-direction:column;
    gap:8px;
    pointer-events:none; /* la pile laisse passer les clics, chaque toast les reprend */
  }
  .toast{
    pointer-events:auto;
    background:#1b1f1e;
    border:1px solid var(--line);
    border-radius:var(--r-md);
    padding:10px 10px 10px 14px;
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    font-size:var(--t-sm); color:var(--parchment);
    box-shadow:0 8px 30px rgba(0,0,0,0.6);
    transition:opacity var(--d-ample) var(--courbe), transform var(--d-ample) var(--courbe);
  }
  .toast.out{opacity:0 !important; transform:translateY(8px);}
  .toast-msg{flex:1 1 auto; min-width:0;}
  .toast-undo{
    flex:0 0 auto;
    background:transparent;
    border:1px solid var(--action);
    color:var(--action);
    border-radius:9999px;
    padding:6px 14px;
    font-size:var(--t-sm); font-weight:700;
    cursor:pointer;
  }
  .toast-undo:hover{background:rgba(245,184,46,0.12);}

  /* --- Lignes découvertes / à découvrir (onglet Aliments) --- */
  .item.row-discovered{background:rgba(0,186,124,0.05);}
  .item.row-undiscovered{background:rgba(231,233,234,0.025);}
  @media (hover:hover) and (pointer:fine){
    .item.row-discovered:hover{background:rgba(0,186,124,0.09);}
    .item.row-undiscovered:hover{background:var(--hover);}
  }

  /* --- Écrans Intolérances / Paramètres --- */
  .panel-close-row{display:flex; justify-content:space-between; align-items:flex-start; gap:10px;}

  /* --- Panneaux secondaires des lignes --- */
  /* Panneaux dépliés (fiche, stats, édition) : même langage visuel, accrochés
     à leur ligne — fond commun, liseré doré partagé, jonctions en pointillés. */
  .stats-panel{
    font-size:var(--t-sm); color:var(--parchment-dim);
    padding:10px 16px 12px 20px;
    border-bottom:1px solid var(--line);
    border-left:3px solid var(--action);
    background:var(--soil-700);
    display:flex; flex-direction:column; gap:3px;
    font-variant-numeric:tabular-nums;
  }
  .edit-panel{
    display:flex; flex-direction:column; align-items:flex-start; gap:10px;
    padding:12px 16px 14px 20px;
    border-bottom:1px solid var(--line);
    border-left:3px solid var(--action);
    background:var(--soil-700);
  }
  /* La ligne parente d'un panneau ouvert se fond avec lui : même fond, même
     liseré, plus de trait entre elle et son contenu ; le nom passe en doré. */
  .item:has(+ .dex-panel), .item:has(+ .stats-panel), .item:has(+ .edit-panel){
    background:var(--soil-700);
    border-bottom:none;
    border-left:3px solid var(--action);
    padding-left:17px; /* 20px - 3px de liseré : le contenu ne bouge pas */
  }
  .item:has(+ .dex-panel) .item-name, .item:has(+ .stats-panel) .item-name,
  .item:has(+ .edit-panel) .item-name{color:var(--action); font-weight:700;}
  /* Bouton stats : icône pleine et dorée quand le panneau est déplié */
  .item .stats-btn.on{color:var(--action);}
  /* Plusieurs panneaux ouverts sous la même ligne : un seul bloc, séparé
     à l'intérieur par un pointillé discret au lieu d'un trait plein. */
  .dex-panel:has(+ .stats-panel), .dex-panel:has(+ .edit-panel),
  .stats-panel:has(+ .edit-panel){border-bottom:none;}
  .dex-panel + .stats-panel, .dex-panel + .edit-panel,
  .stats-panel + .edit-panel{border-top:1px solid var(--arc-track);}
  /* …et la même jonction pointillée entre la ligne de l'aliment et son premier panneau */
  .item + .dex-panel, .item + .stats-panel, .item + .edit-panel{border-top:1px solid var(--arc-track);}
  .edit-actions{display:flex; flex-wrap:wrap; gap:8px;}
  .history-panel{
    display:flex; flex-direction:column; gap:6px;
    width:100%; margin-top:2px; padding:10px 12px;
    background:var(--soil-700);
    border-radius:var(--r-md);
  }
  .history-row{display:flex; justify-content:space-between; align-items:center; font-size:var(--t-sm); color:var(--parchment);}
  .history-empty{font-size:var(--t-sm); color:var(--parchment-dim);}
  /* inline-flex + align-items:center : sans ça, l'icône SVG se posait sur la
     ligne de base du texte — 7 px de marge en haut contre 10 en bas dans les
     boutons de l'historique, ce qui se voit. Relevé par Éric. */
  .btn-mini{
    display:inline-flex; align-items:center; justify-content:center; gap:5px;
    background:transparent;
    color:var(--parchment);
    border:1px solid var(--line);
    border-radius:9999px;
    padding:6px 12px;
    font-size:var(--t-sm); font-weight:600;
    cursor:pointer; flex:0 0 auto;
    transition:background var(--d-normale) var(--courbe), border-color var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe);
  }
  .btn-mini:hover{border-color:var(--action); color:var(--action); background:rgba(245,184,46,0.06);}
  .btn-mini.ghost{opacity:0.6;}
  /* Au repos, le bord reste neutre : c'est le TEXTE qui porte le rouge. Un
     cadre rouge a cote d'un bouton ordinaire criait plus fort que l'action
     courante ("Modifier la date") dans le meme groupe. Le rouge plein revient
     au survol, au moment ou l'on vise vraiment. */
  .btn-mini.danger{border-color:var(--line); color:var(--rust);}
  .btn-mini.danger:hover{background:var(--rust-dim); border-color:var(--rust-dim); color:#fff;}

  /* --- Fiche aliment --- */
  .dex-panel{
    background:var(--soil-700);
    border-left:3px solid var(--action);
    padding:14px 16px 14px 20px; /* aligné sur la ligne parente et les autres panneaux */
    margin:0;
    border-bottom:1px solid var(--line);
    /* fondu d'ouverture (recréé par innerHTML à chaque render, donc rejoué) */
    animation:panelIn .14s ease-out;
  }
  .dex-head{display:flex; align-items:center; gap:12px; flex-wrap:wrap;}
  .dex-num{font-size:var(--t-sm); font-weight:700; color:var(--wheat-dim); font-variant-numeric:tabular-nums;}
  /* Halo clair autour du contour des illustrations : les aliments sombres ou
     très détaillés se détachent mieux du fond. */
  .dex-sprite{font-size:36px; line-height:1;
    filter:drop-shadow(0 0 1px rgba(231,233,228,0.55)) drop-shadow(0 0 4px rgba(231,233,228,0.28));}
  .dex-sprite svg{width:1em; height:1em; display:block;}
  .dex-sprite.undiscovered{filter:grayscale(1) brightness(0.55)
    drop-shadow(0 0 1px rgba(231,233,228,0.4)) drop-shadow(0 0 3px rgba(231,233,228,0.18));}
  .dex-title{flex:1; min-width:120px;}
  .dex-name{font-weight:800; font-size:var(--t-lg); color:var(--parchment); letter-spacing:-0.2px;}
  .dex-types{display:flex; gap:5px; margin-top:5px; flex-wrap:wrap;}
  .dex-type{
    font-size:var(--t-xs); font-weight:700;
    text-transform:uppercase; letter-spacing:0.6px;
    padding:3px 9px; border-radius:9999px; color:#fff;
  }
  .dex-capture{font-size:var(--t-xs); font-weight:600; text-align:right; color:var(--moss-bright); line-height:1.5;}
  .dex-capture.never{color:var(--parchment-dim);}
  .dex-flavor{font-style:italic; color:var(--parchment); font-size:var(--t-md); margin-top:10px; line-height:1.5;}
  .dex-row{font-size:var(--t-sm); color:var(--parchment-dim); margin-top:8px; line-height:1.45; display:flex; gap:7px; align-items:baseline; flex-wrap:wrap;}
  .dex-row b{color:var(--parchment); font-weight:600; white-space:nowrap;}
  .dex-row.dex-why{background:rgba(245,184,46,0.08); border-radius:var(--r-sm); padding:8px 10px;}
  .dex-row.dex-why b{color:var(--action);}
  .dex-months{display:inline-flex; gap:2px; font-size:var(--t-xs); font-weight:700;}
  .dex-month{width:17px; height:17px; display:inline-flex; align-items:center; justify-content:center; border-radius:5px; background:var(--soil-800); color:var(--parchment-dim);}
  .dex-month.on{background:var(--moss); color:#fff;}
  .dex-month.now{box-shadow:var(--marqueur);}
  .dex-season-badge{font-size:var(--t-xs); font-weight:700; color:var(--moss-bright);}

  /* --- Fiche d'information de catégorie --- */
  .cat-dex{
    background:rgba(245,184,46,0.04);
    border-bottom:1px solid var(--line);
    padding:12px 16px 13px;
    font-size:var(--t-sm); color:var(--parchment-dim); line-height:1.5;
  }
  .cat-dex-row{display:flex; gap:7px; align-items:baseline; margin-top:6px;}
  .cat-dex-row:first-child{margin-top:0;}
  .cat-dex-row b{color:var(--action); font-weight:700; white-space:nowrap; font-size:var(--t-sm);}
  .cat-dex-row span{color:var(--parchment-dim);}

  /* --- Onglet Aliments : stats --- */
  .foods-stats{margin-bottom:12px;}
  .fs-grid{display:grid; grid-template-columns:repeat(3, 1fr); gap:8px;}
  .fs-tile{
    background:var(--soil-800);
    border:1px solid var(--line);
    border-radius:var(--radius);
    padding:12px 14px;
  }
  .fs-label{
    font-size:var(--t-xs); font-weight:700;
    text-transform:uppercase; letter-spacing:0.8px;
    color:var(--parchment-dim);
    margin-bottom:6px;
  }
  .fs-value{font-size:var(--t-xl); font-weight:800; color:var(--parchment); line-height:1.1; letter-spacing:-0.5px; font-variant-numeric:tabular-nums;}
  .fs-value .fs-total{font-size:var(--t-md); font-weight:500; color:var(--parchment-dim);}
  .fs-delta{font-size:var(--t-sm); margin-top:4px; font-variant-numeric:tabular-nums;}
  .fs-delta.up{color:var(--moss-bright);}
  .fs-delta.down{color:var(--rust);}
  .fs-delta.flat{color:var(--parchment-dim);}
  .fs-discovery{grid-column:1 / -1;}
  .fs-bar{height:6px; background:var(--soil-700); border-radius:var(--r-full); overflow:hidden; margin-top:8px;}
  .fs-bar-fill{height:100%; background:var(--action); border-radius:var(--r-full);}

  /* --- Onglet Aliments : liste ---
     Plus de cadre autour de la liste : les lignes s'affichent en pleine
     largeur, façon liste de contacts, pour ne pas perdre d'espace. */
  .foods-hint{font-size:var(--t-sm); color:var(--parchment-dim); margin:2px 2px 10px;}
  .foods-list{margin:0;}
  .foods-empty{padding:24px; text-align:center; color:var(--parchment-dim); font-size:var(--t-md);}
  /* Plus de « margin:0 -16px » sous 600 px (retiré le 30/08/2026, B-1 de
     l'audit) : les lignes allaient de 0 à 390 px alors que TOUT le reste de la
     page — la carte du carnet, la phrase d'aide, le dock — s'arrête à 16 px du
     bord. Le filet de chaque ligne mourait donc contre le bord de l'écran, sans
     marge, 446 fois. Le débord de 10 px qui reste sert au fond du survol et de
     la sélection ; le texte, lui, reste aligné sur la colonne. */
  /* Plus de variante par taille : la liste garde les gouttières de la page.
     Le texte des lignes tombe alors exactement sous celui des cartes (16 px de
     page + 16 px de ligne = 32, comme 16 + 16 de carte). */

  /* --- Section « Aliments masqués » (repliable, façon discussions archivées) --- */
  .hidden-foods-toggle{
    display:flex; align-items:center; gap:12px;
    padding:11px 14px;
    cursor:pointer; user-select:none;
    color:var(--parchment-dim);
    font-size:var(--t-sm); font-weight:600;
    border-bottom:1px solid var(--line);
    transition:background var(--d-vite) var(--courbe);
  }
  @media (hover:hover) and (pointer:fine){
    .hidden-foods-toggle:hover{background:var(--hover);}
  }
  .hidden-foods-toggle .hf-ico{
    width:36px; height:36px; flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    background:var(--soil-700);
    border-radius:50%;
  }
  .hidden-foods-toggle .hf-label{flex:1 1 auto;}
  .hidden-foods-toggle .hf-count{
    flex:0 0 auto;
    font-size:var(--t-sm); font-weight:700;
    color:var(--parchment-dim);
    font-variant-numeric:tabular-nums;
  }
  .hidden-foods-toggle .hf-chevron{flex:0 0 auto; display:inline-flex;}
  .hidden-foods-body .wa-row .item-name{color:var(--parchment-dim);}
  .hidden-foods-body .wa-avatar{opacity:0.4; filter:grayscale(1);}
  .hidden-foods-body .unhide-btn{white-space:nowrap;}

  /* --- Dock flottant (recherche + filtres) --- */
  /* Le dock vit au niveau de la page (et non dans l'onglet Aliments) : il
     flotte au-dessus de tout, comme les messages ou le menu ⋮, et n'est donc
     jamais emporté ni déformé par le déplacement d'une page. */
  .foods-dock{
    display:none;
    position:fixed;
    bottom:calc(64px + env(safe-area-inset-bottom));
    left:calc(50% + var(--dec));
    transform:translateX(-50%);
    /* Largeur alignée sur le contenu de la page : la colonne fait 640 px avec
       16 px de marge intérieure de chaque côté, soit 608 px utiles — la largeur
       exacte du panneau compteur et de la liste, au-dessus desquels la barre
       flotte. Sur téléphone, c'est la seconde valeur qui gagne. */
    width:min(608px, calc(100% - 20px));
    z-index:50;
    /* VERRE DÉPOLI, façon barre d'outils iOS (31/08/2026, Éric : « donne un
       style apple à ce panneau »). Translucide à 92 % + flou d'arrière-plan :
       c'est le flou, et non un dégradé posé à côté, qui empêche la liste de
       gêner derrière. Le fondu du 30/08 est parti avec (voir plus bas).
       La couleur est écrite en dur et non var(--soil-800) : il faut le canal
       alpha, et les thèmes la redéfinissent chacun de leur côté. */
    background:rgba(11,14,13,0.92);
    -webkit-backdrop-filter:blur(22px) saturate(180%);
    backdrop-filter:blur(22px) saturate(180%);
    border:1px solid var(--line);
    /* Rayons CONCENTRIQUES : le champ à l'intérieur est une pilule de 44 px de
       haut, donc de rayon 22 ; avec 8 px de marge intérieure, l'extérieur veut
       30. C'est la règle Apple — un arrondi extérieur doit valoir l'intérieur
       plus la marge, sinon les deux courbes se contrarient, et c'est ce qui
       faisait « moche » ici (16 px autour d'une pilule de 22).
       30 px n'entre pas dans l'échelle à trois rayons, mais l'échelle vaut pour
       les CARTES : ici le rayon est imposé par le contenu, comme les icônes le
       sont pour la typo. */
    border-radius:30px;
    /* 8 px et non 12 : la barre faisait 68 px de haut pour un champ de 44,
       soit un tiers de vide. Relevé par Éric (« trop volumineux, trop d'espace
       au-dessus et en dessous »). */
    padding:8px;
    box-shadow:0 8px 30px rgba(0,0,0,0.45);
    transition:opacity var(--d-vite) var(--courbe), bottom var(--d-normale) var(--courbe);
  }
  /* LA FORME NE CHANGE PAS AU DÉPLIAGE (31/08/2026, Éric : « les arrondis des
     bords changent »). La règle d'ici faisait passer le rayon de 30 à 16 px et
     la marge de 8 à 12 en même temps que les filtres s'ouvraient : le panneau
     ne grandissait pas, il se métamorphosait. Un objet qui s'agrandit reste le
     même objet — c'est la règle, et elle vaut aussi pour le dépliage du score
     et des sections. Le rayon et la marge sont donc posés UNE fois, plus haut,
     et rien ici ne les redéfinit. */
  /* LE FONDU EST PARTI (31/08/2026, Éric : « retire le dégradé d'opacité sous
     le panneau filtre, c'est dégueulasse »). C'étaient deux pseudo-éléments
     posés hors du dock : une bande dégradée de 56 px au-dessus et un aplat de
     220 px en dessous, pour qu'une ligne de la liste ne soit pas tranchée net
     par le bord. Le défaut qu'ils corrigeaient est réel, mais le verre dépoli
     le règle mieux : sous un dock flou, le texte qui passe derrière est
     illisible donc inoffensif — c'est exactement ce que fait iOS, et sans
     peindre 276 px de fond par-dessus la page. Ne pas les remettre. */
  /* ANCIENNE MISE EN PAGE REMISE (31/08/2026, Éric : « le nouveau est hideux »).
     Deux changements du 30/08 sont annulés :
     1) le dédoublement de la ligne sous 520 px (C-2), qui donnait au téléphone
        un dock de deux rangées — champ sur toute la largeur, puis compteur et
        bouton Filtres en dessous — soit une carte flottante qui mangeait le bas
        de l'écran, filtres dépliés compris ;
     2) le padding-top:6px des filtres dépliés et le margin:0 du champ.
     Le champ, le compteur et le bouton Filtres tiennent donc de nouveau sur UNE
     ligne à toutes les largeurs. Contrepartie assumée et connue : sous 520 px le
     texte d'invite « Rechercher une plante… » est tronqué — c'était le motif du
     C-2, Éric a vu les deux et préfère la ligne compacte.
     Ce qui RESTE du 30/08, parce que ce n'est pas de la mise en page et que ça
     corrigeait un vrai défaut : les bandes de fondu ::before/::after, qui
     évitent qu'une ligne de la liste soit tranchée net par le bord du dock. */
  /* margin:0 — la marge intérieure de 8 px du dock suffit. Avec « 8px 0 0 » la
     barre faisait 70 px de haut pour un champ de 46 : 8 de dock + 8 de marge
     au-dessus, 8 de dock en dessous, donc deux fois plus d'air en haut qu'en
     bas. La rangée ne se décolle que quand les filtres sont dépliés. */
  .foods-dock .foods-search{margin:0; display:flex; align-items:center; gap:8px;}
  .foods-dock.expanded .foods-search{margin-top:10px;}
  .foods-search input{width:100%; border-radius:9999px;}
  .search-wrap{position:relative; flex:1; min-width:0;}
  .search-wrap input{width:100%; padding-right:34px;}
  .search-clear{
    position:absolute; right:11px; top:50%; transform:translateY(-50%);
    background:none; border:none; /* c'est un <button> (accès clavier) */
    color:var(--parchment-dim); cursor:pointer; font-size:var(--t-sm); display:none;
    padding:4px; line-height:1;
  }
  .search-clear svg{display:block;}
  .search-clear:hover{color:var(--parchment);}
  .search-clear.visible{display:block;}
  .dock-count{font-size:var(--t-sm); font-weight:600; color:var(--parchment-dim); white-space:nowrap; font-variant-numeric:tabular-nums;}
  /* Bouton « Filtres » : même mécanique à toutes les largeurs (celle du
     téléphone, généralisée) — le bloc de filtres est replié par défaut, le
     bouton le déplie et le replie, sans toucher aux filtres actifs.
     L'ancienne flèche de repli du grand écran a été supprimée. */
  .foods-dock .foods-filters{display:none;}
  .foods-dock.expanded .foods-filters{display:block;}
  #panelFoods.active{padding-bottom:180px;}

  /* --- Filtres (chips) --- */
  .foods-filters{margin:0;}
  .ff-row{display:flex; flex-wrap:wrap; gap:6px; margin-top:6px;}
  .ff-chip{
    display:inline-flex; align-items:center; gap:5px;
    font-family:var(--font); /* les puces sont maintenant de vrais <button> (accès clavier) */
    font-size:var(--t-sm); font-weight:600;
    padding:6px 12px;
    border-radius:9999px;
    border:1px solid var(--line);
    background:transparent;
    color:var(--parchment-dim);
    cursor:pointer; user-select:none;
    transition:background var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe), border-color var(--d-normale) var(--courbe);
  }
  .ff-chip svg{flex:0 0 auto; pointer-events:none;}
  @media (hover:hover) and (pointer:fine){
    .ff-chip:hover{border-color:var(--parchment-dim); color:var(--parchment); background:var(--hover);}
  }
  .ff-chip.on{background:var(--action); border-color:var(--action); color:#000; font-weight:700;}
  /* Le bouton « Filtres » est TOUJOURS en 700 (31/08/2026, relevé par Éric) :
     .ff-chip.on le faisait passer de 600 à 700, il gagnait 2 px de large et
     poussait le compteur d'aliments à sa gauche. Un état change la couleur, pas
     la taille — sinon la ligne bouge sous le doigt. */
  .dock-filters-btn{font-weight:700;}
  .ff-chip.ff-clear{display:none; border-style:dashed;}
  .ff-chip.ff-clear.visible{display:inline-flex;}
  /* Coche vert fluo du filtre « Découverts » (plus pétant que l'emoji ✔) */
  .ff-chip[data-ff="discovered"]::before{content:"✔"; color:#3EF66E; font-weight:900; margin-right:5px;}
  body.theme-light .ff-chip[data-ff="discovered"]::before{color:#0bbf4d;}
  /* Point d'interrogation doré du filtre « À découvrir » (même principe que le ✔) */
  .ff-chip[data-ff="undiscovered"]::before{content:"?"; color:var(--action); font-weight:900; margin-right:5px;}
  .ff-chip[data-ff="undiscovered"].on::before{color:#000;}

  /* Champ pays de l'accueil */
  /* Le pays se lit en une ligne — « Saisons calées sur : France [changer] » —
     au lieu d'une liste déroulante de 185 pays posée d'emblée. On ne fait pas
     chercher une réponse qu'on connaît déjà : la liste ne sort qu'au besoin. */
  .onboard-country{
    margin:2px 0 10px 30px;
    display:flex; align-items:center; gap:10px; flex-wrap:wrap;
    font-size:var(--t-md); color:var(--parchment-dim);
  }
  /* --- Historique « Mes notes » (bas du Journal) ---
     Refonte du 30/08/2026 (audit d'Éric). Trois défauts, tous corrigés ici :
       - TROP DE TRAITS : un filet sous chaque ligne, PLUS un filet au-dessus de
         chaque intertitre de journée — donc deux traits parallèles à neuf
         pixels d'écart à chaque changement de jour. Il ne reste qu'un trait par
         JOURNÉE : c'est la seule frontière qui veuille dire quelque chose. Les
         lignes se séparent par leur espacement et par le survol.
       - LE DÉTAIL ÉTAIT ÉCRIT DEUX FOIS : sur la ligne (coupé par une ellipse
         une fois sur deux) et à l'identique dans le dépliage. Il n'est plus que
         dans le dépliage — ce que le commentaire de renderHistoryLog annonçait
         déjà, mais que la ligne n'avait jamais cessé de contredire.
       - LE DÉPLIAGE FLOTTAIT sous une ligne à laquelle rien ne le rattachait.
         Ligne ouverte et panneau partagent maintenant un fond et un arrondi :
         un seul bloc, pas deux morceaux. */
  .hist-count{font-size:var(--t-sm); font-weight:700; color:var(--parchment-dim); margin-left:6px; font-variant-numeric:tabular-nums;}
  /* La ligne ne porte que le nom et le chevron. Le débord de -10 px sert au fond
     du survol et de l'ouverture : le texte, lui, reste aligné sur le bord de la
     carte comme tout le reste de la colonne. */
  .hist-row{
    position:relative; display:flex; align-items:center; gap:10px;
    padding:7px 10px; margin:0 -10px;
    border-radius:var(--r-sm);
    font-size:var(--t-md); line-height:1.35; cursor:pointer;
    transition:background var(--d-vite) var(--courbe);
  }
  .hist-name{flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--parchment);}
  /* Le chevron reste visible, en retrait : c'est la seule chose qui dise que la
     ligne s'ouvre. Il n'apparaissait qu'au survol — donc jamais avant d'avoir
     déjà pointé au bon endroit. */
  .hist-row .chev{color:var(--parchment-dim); margin-left:auto; opacity:0.4;}
  .hist-row:hover .chev, .hist-row:focus-visible .chev, .hist-row.open .chev{opacity:1;}
  @media (hover:hover) and (pointer:fine){
    .hist-row:hover{background:var(--hover);}
  }
  .hist-row.open{background:var(--hover); border-radius:var(--r-sm) var(--r-sm) 0 0;}
  /* Le dépliage : ce que la note a coché, pourquoi, et les deux actions. */
  .hist-detail{
    background:var(--hover);
    border-radius:0 0 var(--r-sm) var(--r-sm);
    margin:0 -10px 4px; padding:2px 12px 12px;
    display:flex; flex-direction:column; gap:11px;
  }
  /* Ce que la note a coché, en deux lignes alignées sur une colonne
     d'intitulés — au lieu d'une bouillie « gris · vert » où il fallait deviner
     que la couleur distinguait les catégories des plantes. */
  .hist-quoi{
    display:grid; grid-template-columns:auto 1fr; gap:6px 14px;
    margin:2px 0 0; font-size:var(--t-sm); line-height:1.5;
  }
  .hist-quoi dt{
    font-size:var(--t-xs); font-weight:700; text-transform:uppercase; letter-spacing:0.8px;
    color:var(--parchment-dim); padding-top:2px; white-space:nowrap;
  }
  .hist-quoi dd{margin:0; color:var(--parchment);}
  /* Les plantes gardent leur vert : ici il confirme l'intitulé au lieu de le
     remplacer. Recalibré par les thèmes clair et doux, rien d'autre à prévoir. */
  .hist-quoi dd.hist-plants{color:var(--moss-bright);}
  .hist-neutral{color:var(--parchment-dim); font-style:italic; font-size:var(--t-sm); line-height:1.5;}
  .hist-detail .why-panel{margin:0;}
  .hist-actions{display:flex; flex-wrap:wrap; gap:8px; margin-top:1px;}
  .hist-end{
    margin-top:14px; padding-top:11px;
    border-top:1px solid var(--line);
    font-size:var(--t-xs); color:var(--parchment-dim); text-align:center;
  }
  /* Intertitre de journée : la date ne se répète plus à l'identique sur chaque
     ligne (dix fois « 30/08/26 » d'affilée sur la capture du 30/08), et c'est
     désormais le SEUL filet de la liste. */
  .hist-jour{
    font-size:var(--t-xs); font-weight:700; text-transform:uppercase; letter-spacing:0.8px;
    color:var(--parchment-dim);
    margin:16px 0 5px; padding-top:11px;
    border-top:1px solid var(--line);
  }
  .hist-jour:first-of-type{margin-top:6px; padding-top:0; border-top:none;}
  /* Le champ date est invisible : le bouton 📅 ouvre son calendrier (showPicker). */
  .hist-date{position:absolute; right:34px; bottom:0; width:1px; height:1px; opacity:0; pointer-events:none; color-scheme:dark;}
  body.theme-light .hist-date{color-scheme:light;}
  /* « pourquoi ? » : n'apparaît que sur les notes dont le comptage n'est pas
     évident. Plus de border-bottom — une boîte arrondie avec un seul trait sous
     elle, c'était le trait de trop, et il ne fermait rien. Le fond, lui, passe
     de 4 % à 7 % : à 4 % il était invisible et le texte flottait à nu. */
  .why-panel{background:rgba(245,184,46,0.07); border-radius:var(--r-sm); padding:11px 13px; margin:0 0 6px; font-size:var(--t-sm); color:var(--parchment-dim); line-height:1.55;}
  .why-panel .why-line{color:var(--parchment); margin-bottom:6px;}
  .why-panel b{color:var(--action); font-weight:700;}
  .why-panel .why-line b{color:var(--parchment); font-weight:700;}
  #histMore{margin-top:12px;}
  /* Le reste à afficher, en retrait : c'est une précision, pas l'action. */
  .hist-reste{color:var(--parchment-dim); font-weight:400;}

  /* --- Réglages : rythme des catégories --- */
  .freq-row{display:flex; justify-content:space-between; align-items:center; gap:10px; padding:7px 0; border-bottom:1px solid var(--line); font-size:var(--t-sm); color:var(--parchment);}
  .freq-row:last-child{border-bottom:none;}
  .freq-ctrl{display:flex; align-items:center; gap:8px; flex:0 0 auto;}
  .freq-val{font-variant-numeric:tabular-nums; min-width:36px; text-align:center;}
  .freq-custom{color:var(--wheat); font-size:var(--t-xs); vertical-align:2px;}

  /* --- Réglages : taille du texte et animations réduites ---
     Le zoom s'applique au corps de page, mais les éléments FIXES (barres de
     navigation, dock, volets) se calent sur la fenêtre réelle : zoomés, ils
     débordaient de 12 % à droite en « Grand ». On leur applique le zoom
     inverse pour qu'ils gardent exactement la taille de la fenêtre. */
  body.text-small{zoom:0.92;}
  body.text-large{zoom:1.12;}
  body.text-small .bottom-nav, body.text-small .foods-dock, body.text-small .side-nav,
  body.text-small .side-widgets{zoom:1.087;}
  body.text-large .bottom-nav, body.text-large .foods-dock, body.text-large .side-nav,
  body.text-large .side-widgets{zoom:0.8929;}
  /* #panelSettings et #panelInfos ne sont des volets fixes QUE sur téléphone
     (voir plus bas) ; sur grand écran ce sont des pages normales, qui doivent
     garder le zoom du corps. */
  @media (max-width:859px){
    body.text-small #panelSettings, body.text-small #panelInfos{zoom:1.087;}
    body.text-large #panelSettings, body.text-large #panelInfos{zoom:0.8929;}
  }
  body.reduce-motion *, body.reduce-motion *::before, body.reduce-motion *::after{
    transition:none !important; animation:none !important;
  }
  /* Le média système n'est PLUS branché en direct : il est lu par
     animationsReduites() dans app.js, qui pose body.reduce-motion — et que le
     réglage « Garder les animations » peut contredire. Branché ici, il coupait
     tout sans aucun recours depuis l'appli. */

  /* --- Réglages : exclusions --- */
  .hide-intro{font-size:var(--t-md); color:var(--parchment-dim); margin:0 0 8px; line-height:1.5;}
  .hide-body{margin-top:14px;}
  .hide-groups{
    display:grid;
    grid-template-columns:repeat(auto-fill, minmax(230px, 1fr));
    gap:10px 14px;
    margin-bottom:16px;
    align-items:start;
  }
  .hide-group-block{background:var(--soil-700); border-radius:var(--r-md); padding:10px 12px;}
  .hide-group-item{display:flex; align-items:center; gap:8px; font-size:var(--t-sm); color:var(--parchment); cursor:pointer;}
  .hide-group-item input{margin:0; accent-color:var(--action); flex:0 0 auto; width:16px; height:16px;}
  .hide-group-exceptions{
    margin-top:8px; padding-top:8px;
    border-top:1px solid var(--line);
    display:flex; flex-direction:column; gap:6px;
  }
  .hide-exception-item{display:flex; align-items:center; gap:7px; font-size:var(--t-sm); color:var(--parchment-dim); cursor:pointer;}
  .hide-exception-item input{margin:0; accent-color:var(--moss-bright); flex:0 0 auto;}
  .hide-search-row{position:relative; margin-bottom:16px;}
  .hide-search-row input{width:100%; border-radius:9999px;}
  .hide-search-results{
    position:relative; margin-top:6px; display:none;
    border:1px solid var(--line); border-radius:var(--r-md); overflow:hidden;
  }
  .hide-search-result{
    display:flex; justify-content:space-between; align-items:center;
    padding:10px 12px; font-size:var(--t-sm);
    background:var(--soil-700);
    border-bottom:1px solid var(--line);
    cursor:pointer;
  }
  .hide-search-result:last-child{border-bottom:none;}
  @media (hover:hover) and (pointer:fine){
    .hide-search-result:hover{background:var(--hover);}
  }
  .hide-add{font-size:var(--t-xs); font-weight:700; color:var(--action); text-transform:uppercase; letter-spacing:0.5px;}
  .hide-current-label{
    font-size:var(--t-xs); font-weight:700;
    text-transform:uppercase; letter-spacing:1px;
    color:var(--parchment-dim);
    margin:12px 0 6px;
  }
  .hide-current-row{
    display:flex; justify-content:space-between; align-items:center; gap:10px;
    padding:8px 0;
    border-bottom:1px solid var(--line);
    font-size:var(--t-sm);
  }
  .hide-current-row:last-child{border-bottom:none;}
  .hide-exception-note{color:var(--parchment-dim); font-size:var(--t-sm); font-style:italic;}
  .hide-current-empty{font-size:var(--t-sm); color:var(--parchment-dim); opacity:0.7; margin-top:10px;}

  /* --- Réglages : sauvegarde --- */
  .btn-ghost{
    background:transparent;
    color:var(--parchment);
    border:1px solid var(--line);
    border-radius:9999px;
    padding:9px 16px;
    font-size:var(--t-sm); font-weight:600;
    cursor:pointer;
    transition:background var(--d-normale) var(--courbe), border-color var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe);
  }
  .btn-ghost:hover{border-color:var(--action); color:var(--action); background:rgba(245,184,46,0.06);}
  .btn-ghost.btn-disabled{
    background-image:repeating-linear-gradient(45deg, rgba(231,233,234,0.05) 0, rgba(231,233,234,0.05) 6px, transparent 6px, transparent 12px);
    opacity:0.4; cursor:not-allowed;
  }
  .btn-ghost.btn-disabled:hover{border-color:var(--line); color:var(--parchment); background:transparent;}
    width:22px; height:22px; border-radius:50%;
    border:1px solid var(--parchment-dim);
    color:var(--parchment-dim);
    background:none; font-size:var(--t-xs); font-weight:700; font-style:italic;
    display:inline-flex; align-items:center; justify-content:center;
    cursor:pointer;
  }
  .info-text{font-size:var(--t-sm); color:var(--parchment-dim); margin-top:10px;}
  /* Badge « Bientôt » (fonctions annoncées mais pas encore branchées) */
  .soon-badge{
    display:inline-block;
    font-size:var(--t-xs); font-weight:800;
    text-transform:uppercase; letter-spacing:0.6px;
    color:var(--action);
    background:rgba(245,184,46,0.12);
    border:1px solid rgba(245,184,46,0.35);
    border-radius:9999px;
    padding:2px 8px;
    margin-left:6px;
    vertical-align:1px;
  }

  footer{
    text-align:center;
    font-size:var(--t-sm);
    color:var(--parchment-dim);
    margin-top:24px;
    opacity:0.7;
  }
  /* .reset-link a disparu : le bouton de remise a zero est un .btn-mini danger
     dans la section Compte depuis le 31/08/2026. */


  /* --- Tiroir d'informations --- */
  .drawer-overlay{
    position:fixed; inset:0;
    background:rgba(0,0,0,0.65);
    z-index:90;
    opacity:0; pointer-events:none;
    transition:opacity var(--d-ample) var(--courbe);
  }
  /* Informations : page normale sur grand écran (comme le Calendrier), volet
     coulissant de droite sur téléphone — exactement la mécanique de
     #panelSettings, côté opposé. */
  @media (max-width:859px){
    #panelInfos{
      display:block; /* toujours dans la page, mais rangé hors de l'écran */
      position:fixed; top:0; right:0; bottom:0;
      width:min(420px, 92vw);
      background:var(--soil-800);
      border-left:1px solid var(--line);
      z-index:100;
      transform:translateX(105%);
      /* visibility:hidden quand il est rangé : sans ça, ses ~60 boutons et textes
         restaient dans l'ordre de tabulation et lus par les lecteurs d'écran
         alors qu'ils sont hors écran. Même mécanique que #panelSettings. */
      visibility:hidden;
      transition:transform var(--d-ample) var(--courbe), visibility var(--d-vite) linear .25s;
      overflow-y:auto;
      padding:0 22px calc(40px + env(safe-area-inset-bottom, 0px)); /* pas de padding haut : l'en-tête collant occupe le bord supérieur */
      animation:none; /* pas de fondu d'onglet : ce n'est pas une page ici */
    }
    body.drawer-open #panelInfos{transform:none; visibility:visible; transition:transform var(--d-ample) var(--courbe), visibility var(--d-vite) var(--courbe);}
  }
  @media (min-width:860px){
    /* En mode page, l'en-tête du volet perd son fond collant et son bouton
       Fermer, mais GARDE son titre (C-3 de l'audit du 30/08/2026) : sur ces
       deux écrans l'entête à trois onglets disparaît — c'est voulu — et rien ne
       la remplaçait. La page commençait à 30 px du haut par une ligne de menu,
       sans nom. On arrivait quelque part et l'appli ne disait pas où. */
    /* `.deux-volets .drawer-head` et non `.settings-head` (corrigé le
       31/08/2026, relevé par Éric : « tu as laissé une ligne horizontale entre
       le titre Paramètres et la zone de recherche »). `.drawer-head` est
       déclaré PLUS BAS dans le fichier avec la même spécificité (0,1,0) et
       gagnait donc : Paramètres gardait son filet et son fond collant, alors
       qu'Informations passait par `#panelInfos .drawer-head` (0,1,1) et n'en
       avait pas. Les deux panneaux portent `.deux-volets`, ce qui donne (0,2,0)
       et règle le cas pour de bon. */
    .deux-volets .drawer-head{
      display:flex; position:static; z-index:auto;
      background:none; border-bottom:none;
      margin:0; padding:2px 0 16px;
    }
    #panelInfos .drawer-close, #panelSettings .drawer-close{display:none;}
  }
  body.drawer-open .drawer-overlay{opacity:1; pointer-events:auto;}
  .drawer-head{
    /* En-tête fixé en haut de la zone pendant le défilement, sans interstice.
       safe-area-inset-top : en appli installée sur iPhone (plein écran), le
       titre et le bouton Fermer passaient sous l'encoche. */
    position:sticky; top:0; z-index:5;
    background:var(--soil-800);
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    margin:0 -22px 0; padding:calc(16px + env(safe-area-inset-top, 0px)) 22px 12px;
    border-bottom:1px solid var(--line);
  }
  body.theme-light .drawer-head{background:#fff;}
  /* Un titre, c'est .log-title : 17 px, minuscules, encre pleine (règle du
     30/08/2026). Il était en or, capitales, interlettré — le seul titre de
     l'appli dans cette couleur, alors que l'or y signale partout ailleurs une
     action ou une réussite. */
  .drawer-title{font-size:var(--t-lg); font-weight:600; letter-spacing:-0.01em; color:var(--parchment);}
  .drawer-close{
    display:inline-flex; align-items:center; gap:6px;
    background:none;
    border:1px solid var(--line);
    border-radius:9999px;
    color:var(--parchment-dim);
    font-size:var(--t-sm); font-weight:600;
    padding:6px 12px;
    cursor:pointer;
  }
  .drawer-close:hover{color:var(--parchment); background:var(--hover);}

  /* --- Paramètres en volet latéral gauche (téléphone), façon profil de X ---
     Sur grand écran, Paramètres reste une page normale : tout ce bloc ne
     s'applique qu'en dessous de 860 px. */
  .settings-head{margin:0 -16px 0; padding:calc(16px + env(safe-area-inset-top, 0px)) 16px 12px;}
  @media (max-width:859px){
    #panelSettings{
      display:block; /* toujours dans la page, mais rangé hors de l'écran */
      position:fixed; top:0; left:0; bottom:0;
      width:min(420px, 92vw);
      background:var(--soil-800);
      border-right:1px solid var(--line);
      z-index:100;
      padding:0 16px calc(40px + env(safe-area-inset-bottom, 0px));
      overflow-y:auto;
      transform:translateX(-105%);
      visibility:hidden;
      transition:transform var(--d-ample) var(--courbe), visibility var(--d-vite) linear .25s;
      animation:none; /* pas de fondu d'onglet : ce n'est plus une page */
    }
    body.settings-open #panelSettings{
      transform:none;
      visibility:visible;
      transition:transform var(--d-ample) var(--courbe), visibility var(--d-vite) var(--courbe);
    }
    body.settings-open .drawer-overlay{opacity:1; pointer-events:auto;}
  }
  /* Pendant qu'un volet suit le doigt, aucune transition : il colle au geste. */
  body.drawer-dragging #panelSettings,
  body.drawer-dragging #panelInfos,
  body.drawer-dragging .drawer-overlay{transition:none;}
  /* scroll-margin-top : quand un « i » fait défiler jusqu'à une section, elle
     s'arrête SOUS l'en-tête collant du tiroir au lieu d'être recouverte par lui.
     env(safe-area-inset-top) est INDISPENSABLE (corrigé le 31/08/2026) : l'en-tête
     est haute de 16px + safe-area + titre + 12px, elle grandit donc de l'encoche
     — jusqu'à 47 px sur un iPhone en appli installée — alors que la marge était
     figée à 72. Le cadre doré de la section visée passait d'autant sous le titre
     « Informations ». Invisible au banc : Chrome sans tête renvoie 0 pour toutes
     les safe-area, c'est un défaut qui ne se voit que sur l'appareil.
     84 et non 72 : 12 px d'air ne se voyaient pas, la section semblait collée. */
  .info-section{margin-top:18px; padding-top:14px;}
  .info-section h3{margin:0 0 8px;}
  /* Le titre de la section est un simple <h3> depuis le 31/08/2026 : il n était
     un <button> que pour déplier, et il n y a plus rien à déplier — une seule
     section s affiche à la fois, choisie dans le menu. Sont partis avec :
     .info-head, son chevron ::after, .collapsed et le masquage de .info-body. */
  .info-section h3.info-h3{margin:0 0 10px;}
  .info-section p{font-size:var(--t-md); line-height:1.55; color:var(--parchment); margin:0 0 8px;}
  /* Sous-titres internes : les règles de saisie ont besoin d'être découpées. */
  .info-section h4{
    margin:16px 0 6px;
    font-size:var(--t-sm); font-weight:800;
    color:var(--action);
    letter-spacing:-0.1px;
  }
  .info-section ul{margin:0 0 8px 18px; padding:0; font-size:var(--t-md); line-height:1.55; color:var(--parchment);}
  .info-section li{margin-bottom:4px;}
  /* Le surlignage doré .info-target a été SUPPRIMÉ le 31/08/2026 : il restait
     allumé après avoir quitté la page et après avoir refermé le volet (signalé
     par Éric). Il ne sert plus à rien non plus — une seule section s affiche. */
  .info-note{margin:0 0 8px; font-size:var(--t-md); line-height:1.55; color:var(--parchment);}
  .score-i{font-style:italic; font-weight:800; font-size:var(--t-md);}

  /* --- Onboarding --- */
  .onboard-card{border-color:var(--action-dim);}
  .onboard-step{display:flex; gap:12px; align-items:flex-start; margin-bottom:10px; font-size:var(--t-md); line-height:1.5;}
  .onboard-num{
    flex:0 0 auto; width:24px; height:24px;
    display:inline-flex; align-items:center; justify-content:center;
    background:var(--action); color:#000;
    border-radius:50%; font-size:var(--t-sm); font-weight:800;
  }
  .onboard-go{margin-top:4px; border-color:var(--action); color:var(--action); font-weight:700;}

  /* --- Récap du jour : extension de la carte Journal --- */
  .recap-chips{display:flex; flex-wrap:wrap; gap:6px;}
  #todayRecap{margin-top:14px; padding-top:12px; border-top:1px solid var(--line);}

  /* --- Défi hebdo --- */
  /* La ligne du defi garde 15 px : c est l enonce du defi, pas son commentaire. */
  /* 13 px et non 15 : l enonce du defi est du corps de texte comme le reste de
     la colonne. Le chiffre a droite reste en 700 encre — c est lui qu on lit. */
  .challenge-row{display:flex; justify-content:space-between; align-items:baseline; gap:10px; font-size:var(--t-sm); color:var(--parchment-dim); margin-bottom:8px;}
  .challenge-row b{color:var(--parchment);}
  .challenge-row b{font-variant-numeric:tabular-nums;}
  .challenge-done{margin-top:8px; font-size:var(--t-sm); font-weight:700; color:var(--moss-bright);}
  .challenge-history{margin-top:6px; font-size:var(--t-sm); color:var(--parchment-dim);}

  /* --- Ressenti du jour --- */
  .feel-row{display:flex; gap:8px; margin-bottom:8px;}
  .feel-btn{
    flex:0 0 auto; width:46px; height:46px;
    font-size:24px; line-height:1;
    background:var(--soil-700);
    border:1px solid transparent;
    border-radius:var(--r-md);
    cursor:pointer;
    transition:transform var(--d-vite) var(--courbe), border-color var(--d-normale) var(--courbe), background var(--d-normale) var(--courbe);
    filter:grayscale(0.6) brightness(0.85);
  }
  .feel-btn:hover{transform:scale(1.06); filter:none;}
  .feel-btn.on{border-color:var(--action); background:rgba(245,184,46,0.12); filter:none;}

  /* --- Echelle de Bristol (Calendrier) ---
     Sept pastilles numerotees plutot que des emojis : c'est une echelle clinique,
     pas une humeur. Les types 3 et 4 (la zone ideale) sont marques d'un lisere vert
     en permanence, pour que le reperage se fasse sans rien lire.
     Le mot-repere sous le chiffre a ete retire le 2026-08-30 : sept mots dans sept
     boutons larges de ~37 px tombaient a 8 px, illisibles sur telephone COMME sur
     grand ecran. Le repere est descendu d'un cran, en UNE ligne de 13 px sous la
     rangee : elle nomme le type choisi en toutes lettres et dit ce qu'il raconte
     du transit. Un chiffre reste un chiffre, mais on sait desormais ce qu'il
     designe sans avoir a s'en souvenir. */
  .bristol-label{margin-top:14px;}
  .bristol-row{display:flex; gap:5px; margin-bottom:6px;}
  .bristol-btn{
    flex:1 1 0; min-width:0; height:48px; padding:0;
    display:inline-flex; align-items:center; justify-content:center;
    font-family:inherit; font-size:var(--t-lg); font-weight:800; line-height:1;
    color:var(--parchment-dim);
    background:var(--soil-700);
    border:1px solid transparent;
    border-radius:var(--r-md);
    cursor:pointer;
    transition:transform var(--d-vite) var(--courbe), border-color var(--d-normale) var(--courbe), background var(--d-normale) var(--courbe), color var(--d-normale) var(--courbe);
  }
  .bristol-btn:hover{transform:scale(1.06); color:var(--parchment);}
  .bristol-btn.ideal{box-shadow:inset 0 -3px 0 0 var(--moss-bright);}
  .bristol-btn.on{border-color:var(--action); background:rgba(245,184,46,0.14); color:var(--parchment);}
  /* Reperes des deux bouts : on voit de quel cote est le dur sans toucher a rien. */
  .bristol-scale{display:flex; justify-content:space-between; font-size:var(--t-sm); color:var(--parchment-dim); opacity:0.85; margin-bottom:8px;}
  /* Hauteur minimale : passer de l'invite a la description ne doit pas faire
     sauter le champ de note qui suit. */
  .bristol-desc{font-size:var(--t-sm); line-height:1.5; color:var(--parchment-dim); min-height:40px; margin-bottom:10px;}
  .bristol-desc b{color:var(--parchment); font-weight:700;}
  .bristol-desc .bristol-meaning{display:block; opacity:0.85;}
  .bristol-desc.ideal .bristol-meaning{color:var(--moss-bright); opacity:1;}

  /* --- Pistes personnelles (Stats) ---
     Le seul endroit de l'appli qui croise le ressenti avec le journal. Le ton doit
     rester celui d'une hypothese : d'ou l'avertissement final, non repliable. */
  .piste-intro{font-size:var(--t-sm); line-height:1.55; color:var(--parchment-dim); margin-top:2px;}
  .piste-row{display:flex; gap:8px; align-items:flex-start; margin-top:10px;}
  .piste-ico{flex:0 0 auto; font-size:var(--t-sm); line-height:1.6;}
  .piste-bad b{color:var(--rust);}
  .piste-good b{color:var(--moss-bright);}
  .piste-loose{color:var(--parchment-dim);}
  .piste-warn{
    margin-top:14px; padding-top:10px;
    border-top:1px solid var(--line);
    font-size:var(--t-sm); line-height:1.5; color:var(--parchment-dim);
  }

  /* --- Calendrier --- */
  .cal-head{display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:12px;}
  /* flex:1 + centrage : le mois reste centré entre ses flèches, même quand le
     bouton retour (téléphone) occupe le bord gauche de la rangée. */
  .cal-month{flex:1; text-align:center; font-size:var(--t-md); font-weight:800; text-transform:capitalize;}
  .cal-grid{display:grid; grid-template-columns:repeat(7, 1fr); gap:5px;}
  .cal-dow{
    text-align:center; font-size:var(--t-xs); font-weight:700;
    color:var(--parchment-dim); padding-bottom:2px;
  }
  .cal-cell{
    position:relative;
    aspect-ratio:1;
    display:flex; align-items:center; justify-content:center;
    background:var(--soil-700);
    border:1px solid transparent;
    border-radius:var(--r-sm);
    color:var(--parchment-dim);
    font-size:var(--t-sm); font-weight:600; font-variant-numeric:tabular-nums;
    cursor:pointer;
    transition:border-color var(--d-normale) var(--courbe);
  }
  .cal-cell.empty{background:transparent; cursor:default;}
  .cal-cell.lvl1{background:rgba(0,186,124,0.18); color:var(--parchment);}
  .cal-cell.lvl2{background:rgba(0,186,124,0.42); color:#fff;}
  .cal-cell.lvl3{background:rgba(0,214,143,0.75); color:#00281c;}
  /* Même bug que .dex-month.now : le liseré vert du jour disparaissait sur
     une case bien remplie, qui est verte elle aussi (lvl2 et lvl3). */
  .cal-cell.today{box-shadow:var(--marqueur);}
  .cal-cell.sel{outline:2px solid var(--action);}
  .cal-cell:hover{border-color:var(--parchment-dim);}
  /* DANS la case, pas dessus (corrigé le 30/08/2026, B-2 de l'audit). Elle
     était en top:-7px/right:-5px : chaque frimousse sortait de sa case de la
     moitié de sa taille, chevauchait la case du dessus, et sur la première
     ligne la barre des jours de la semaine — trente débordements, un mois qui
     avait l'air couvert d'autocollants. L'ombre portée servait à la détacher de
     ce qu'elle recouvrait : elle n'a plus rien à recouvrir. */
  .cal-feel{position:absolute; top:1px; right:2px; font-size:var(--t-sm); line-height:1;}
  .cal-legend{margin-top:10px; font-size:var(--t-sm); color:var(--parchment-dim);}
  /* Onze pilules bordées pour lister onze mots (C-9 de l'audit du 30/08/2026) :
     ce sont des noms, pas des boutons — ils n'ont besoin ni de bord ni de fond.
     Le panier du composeur garde les siennes : là, on peut les retirer. */
  .cal-noms{font-size:var(--t-md); line-height:1.7; color:var(--parchment);}
  /* Deux phrases entières en capitales grises interlettrées (C-7) : c'est le
     style de l'intitulé DISCRET, et il portait les titres les plus longs de
     l'écran. Ce sont des titres de bloc, ils prennent .log-title ; « facultatif »
     redescend au rang de mention, ce qu'il est. */
  .cal-block-title{margin-bottom:8px;}
  .cal-opt{
    font-size:var(--t-sm); font-weight:400; letter-spacing:0;
    color:var(--parchment-dim); margin-left:9px;
  }
  .cal-detail{margin-top:14px; padding-top:12px; border-top:1px solid var(--line);}
  .cal-feel-block{margin-top:14px; padding-top:12px; border-top:1px solid var(--line);}
  .cal-feel-block .fs-label{margin-bottom:8px;}
  #calFeelNote{width:100%; margin-top:2px;}

  /* --- Stats --- */
  .st-grid{grid-template-columns:repeat(2, 1fr); margin-top:4px;}
  .st-badges{margin-top:12px;}
  .st-badge{cursor:default; display:inline-flex; margin-top:6px;}
  .st-bar-row{display:flex; align-items:center; gap:10px; margin-top:7px; font-size:var(--t-sm);}
  .st-bar-name{flex:0 0 44%; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
  .st-bar-track{flex:1 1 auto; height:8px; background:var(--soil-700); border-radius:var(--r-full); overflow:hidden;}
  .st-bar-fill{display:block; height:100%; background:var(--action); border-radius:var(--r-full);}
  .st-bar-val{flex:0 0 auto; min-width:26px; text-align:right; color:var(--parchment-dim); font-variant-numeric:tabular-nums;}

  /* ===== Paramètres : liste de réglages (refonte du 2026-08-29) =====
     Avant : cinq cartes empilées aux styles différents, des libellés à rallonge
     qui tenaient sur trois lignes sur téléphone et écrasaient la liste
     déroulante en face. Désormais une seule mécanique, la même sur téléphone et
     sur grand écran : un titre de section discret, puis des lignes « libellé +
     explication à gauche, contrôle à droite », séparées par un filet fin.
     Le contrôle a une largeur fixe : c'est ce qui aligne toute la colonne de
     droite, quel que soit la longueur des libellés. */
  .set-group{
    background:var(--soil-800);
    border:1px solid var(--line);
    border-radius:var(--radius);
    padding:4px 16px 12px;
    margin-bottom:12px;
  }
  .set-title{margin:18px 0 6px;}
  /* Menu des sections, façon X : une ligne par section, chevron de navigation à
     droite. La vue est portée par data-vue sur le panneau : « menu » (les lignes,
     le pied de page) ou « section » (un seul groupe + retour). Les groupes ne
     sont jamais retirés du DOM : leurs ids restent trouvables. */
  /* PARAMÈTRES ET INFORMATIONS PARTAGENT CETTE MÉCANIQUE (31/08/2026, demandé
     par Éric : « donne à la page Informations la même architecture et le même
     style que la page Paramètres »). Les deux panneaux portent .deux-volets,
     leurs listes .volet-menu, leurs sections .volet-section, et la section
     affichée .volet-actif. Une seule règle sert les deux : c'est ce qui les
     empêche de diverger au premier réglage ajouté d'un seul côté. */
  .deux-volets[data-vue="menu"] .volet-section{display:none;}
  .deux-volets[data-vue="section"] .volet-menu{display:none;}
  .deux-volets[data-vue="section"] .set-search{display:none;}
  .deux-volets[data-vue="section"] .volet-section{display:none;}
  .deux-volets[data-vue="section"] .volet-section.volet-actif{display:block;}
  .deux-volets[data-vue="section"] footer{display:none;}
  /* padding-left 0 : le filet commençait 8 px avant le texte qu'il souligne.
     Un filet en retrait est une bonne idée — encore faut-il qu'il se cale SUR
     le texte, sinon il ne souligne rien, il flotte. */
  .set-menu-row{
    display:flex; align-items:center; justify-content:space-between; gap:12px;
    width:100%; min-height:52px; padding:6px 0;
    background:none; border:none; border-bottom:1px solid var(--line);
    font-family:var(--font); font-size:var(--t-md); font-weight:600;
    color:var(--parchment); text-align:left; cursor:pointer;
    transition:background var(--d-vite) var(--courbe);
  }
  .set-menu-row:last-child{border-bottom:none;}
  .set-menu-row .chev{color:var(--parchment-dim);}
  @media (hover:hover) and (pointer:fine){
    .set-menu-row:hover{background:var(--hover);}
  }
  /* Recherche dans les réglages, façon X : un champ en pilule, la loupe à
     gauche, la croix seulement quand il y a quelque chose à effacer. */
  .set-search{position:relative; display:flex; align-items:center; margin:10px 0 6px;}
  .set-search-ico{
    position:absolute; left:14px; color:var(--parchment-dim);
    pointer-events:none; flex:0 0 auto;
  }
  .set-search input{
    width:100%; flex:1 1 auto;
    padding:10px 36px 10px 38px;
    border-radius:var(--r-full);
    font-size:var(--t-md);
  }
  .set-search-clear{
    position:absolute; right:10px;
    display:inline-flex; align-items:center; justify-content:center;
    width:22px; height:22px; padding:0;
    background:var(--soil-700); border:none; border-radius:var(--r-full);
    color:var(--parchment-dim); cursor:pointer;
  }
  .set-search-clear:hover{color:var(--parchment);}
  .set-search-clear[hidden]{display:none;}
  .set-search-vide{
    margin:14px 0 0; font-size:var(--t-sm); color:var(--parchment-dim);
  }
  .set-search-vide[hidden]{display:none;}
  /* Badges des paliers de découverte (31/08/2026). Ils remplacent le 🏅 unique.
     vertical-align:-2px les assied sur la ligne de base du texte à côté ; les
     tailles sont en pixels et non en jetons, comme toutes les icônes. */
  .badge-palier{flex:0 0 auto; vertical-align:-2px;}
  .badge-palier.verrouille{opacity:0.75;}
  .badge-ligne{display:flex; align-items:center; gap:8px;}
  /* Une puce de succès qui porte un badge dessiné : le badge déborderait de la
     hauteur de la pilule, on lui rend la place et on aligne au centre. */
  .st-badge.a-badge{display:inline-flex; align-items:center; gap:6px; padding-top:3px; padding-bottom:3px;}
  /* Le 31/08 une puce à badge ne prenait PAS le fond (« le badge dit déjà s'il
     est décroché ») ; depuis que le fond d'action est VERT et non plus doré, la
     différence se lisait comme une puce restée grise au milieu des vertes.
     Tranché par Éric le 05/09/2026 : même fond que les autres succès. */
  .set-menu-row[hidden]{display:none;}
  .set-back{
    display:inline-flex; align-items:center; gap:9px;
    background:none; border:none; padding:12px 4px 4px;
    font-family:var(--font); font-size:var(--t-md); font-weight:700;
    color:var(--parchment); cursor:pointer;
  }
  .set-back[hidden]{display:none;}
  /* --- Paramètres à DEUX VOLETS sur grand écran (30/08/2026, demandé par Éric
     « comme X ») --- Sur X, les réglages ne sont pas un menu qu'on ouvre puis
     qu'on referme : la liste des sections reste à gauche, en permanence, et la
     section choisie s'affiche à droite. On ne perd jamais de vue où l'on est,
     et changer de section est UN clic au lieu de deux.
     Mécanique : une troisième valeur de data-vue, « deux », posée par le JS
     quand SET_DEUX_MQ correspond (1260 px, le même seuil que le rail large).
     Les groupes ne sont toujours jamais retirés du DOM, seulement masqués :
     tous les ids restent trouvables par verifier-appli.js et par les
     gestionnaires. Sous 1260 px, rien ne change — le menu puis la section. */
  @media (min-width:1260px){
    /* .active est INDISPENSABLE ici (corrigé le 31/08/2026). Sans lui, la règle
       s'écrivait « #panelSettings{display:grid} » : un sélecteur d'ID (1,0,0)
       l'emporte sur « .tab-panel{display:none} » (0,1,0), donc au-delà de
       1260 px les Paramètres s'affichaient EN PERMANENCE, par-dessus toutes les
       autres pages, même sans y être jamais allé. Toute règle qui donne un
       display à un panneau par son id doit porter .active. */
    .deux-volets.active{
      display:grid;
      grid-template-columns:236px minmax(0, 1fr);
      column-gap:28px;
      align-items:start;
      /* align-content:start est INDISPENSABLE avec le min-height posé plus bas
         (pour que le filet descende jusqu'en bas de l'écran) : sans lui, la
         valeur par défaut « stretch » répartit la hauteur en trop ENTRE les
         rangées, et le titre, la recherche, le menu et le pied de page se
         retrouvaient séparés par de grands vides. */
      align-content:start;
    }
    /* LE FILET VA JUSQU'EN HAUT (31/08/2026, Éric : « va voir les lignes de
       délimitation chez X »). Il était porté par #settingsMenu, qui commence à
       la 2e rangée de la grille : il démarrait donc SOUS le titre « Paramètres »
       et s'arrêtait sous la dernière section, en flottant. Chez X, la colonne de
       gauche est séparée par un trait qui court sur toute la hauteur. Un
       pseudo-élément sur le panneau le fait sans toucher au flux — il est posé à
       236 px, la largeur exacte de la première colonne. */
    .deux-volets.active{position:relative; min-height:calc(100vh - 40px);}
    .deux-volets.active::before{
      content:""; position:absolute; top:0; bottom:0; left:236px;
      width:1px; background:var(--line); pointer-events:none;
    }
    /* Le volet de droite est un PANNEAU, pas une carte (31/08/2026). Chez X la
       partie déployée n'a ni fond, ni bordure, ni arrondi : c'est le filet
       vertical qui la sépare, et rien d'autre. Une carte posée à côté d'une
       liste sans carte donnait deux dialectes dans le même écran. Le
       column-gap de 28 px tient lieu de marge intérieure gauche. */
    .deux-volets .volet-section{background:none; border:none; border-radius:0; padding:0;}
    .deux-volets .volet-section .set-title,
    .deux-volets .volet-section .info-h3{margin-top:0;}
    /* La colonne de gauche est UN SEUL element de grille (.volet-gauche) depuis
       le 31/08/2026. Avant, ses cinq blocs occupaient cinq rangees et la section
       de droite s'etendait sur les cinq (grid-row:1/span 5) : une section haute
       — Rythme des categories, 881 px — etirait donc les rangees et poussait le
       PIED DE PAGE hors de l'ecran. Bug signale par Eric. Une grille a une seule
       rangee ne peut plus produire ca. */
    .deux-volets .volet-gauche{grid-column:1; display:flex; flex-direction:column; min-width:0;}
    .deux-volets .set-search{margin:0 20px 14px 0;}
    /* padding-right:0 sur le menu, et le retrait passe DANS les lignes : c'est
       ce qui met la barre dorée de la ligne active au ras du filet. Avec 20 px
       de marge sur le menu, elle s'arrêtait 20 px avant le bord — le décalage
       qu'Éric a relevé. */
    .deux-volets .volet-menu{padding-right:0;}
    /* Le fond de la ligne active et les filets partent du BORD GAUCHE de la
       colonne — le filet vertical de .wrap — et non du début du texte
       (31/08/2026, demandé par Éric). .wrap porte 16 px de marge intérieure :
       la ligne les reprend en marge négative et les rend en rembourrage, donc
       la boîte s'étend jusqu'au bord pendant que le texte reste aligné. */
    .deux-volets .volet-menu .set-menu-row{
      padding-right:14px;
      margin-left:-16px;
      padding-left:16px;
      width:calc(100% + 16px);
    }
    .deux-volets .set-search-vide{padding-right:20px;}
    .deux-volets footer{text-align:left; padding-right:20px;}
    /* Toutes les sections occupent la MÊME cellule : une seule est visible.
       span 5 depuis l'ajout de la recherche et du message « aucun réglage ». */
    .deux-volets .volet-section{grid-column:2; grid-row:1; margin-bottom:0; margin-top:0; padding-top:0; border-top:none;}
    .deux-volets .set-back{display:none;}
    /* Le plafond à 55 % est calculé pour une ligne pleine largeur ; dans le
       volet de droite (342 px), il ramenait le contrôle à 169 px et rognait
       « Garder les animations » d'un caractère. 60 % laisse les 190 px prévus. */
    #panelSettings .set-ctrl, #panelSettings select.set-ctrl{max-width:60%;}
    .deux-volets[data-vue="deux"] .volet-section{display:none;}
    .deux-volets[data-vue="deux"] .volet-section.volet-actif{display:block;}
    /* La ligne du menu qui correspond au volet de droite. Le repère est à
       DROITE de la ligne, contre le filet : c'est le bord que l'œil suit pour
       passer d'un volet à l'autre. */
    /* La barre dorée est COLLÉE au filet de séparation : la ligne s'étend
       maintenant jusqu'au bord de la colonne (padding-right:0 sur le menu), le
       inset -3px tombe donc exactement sur le filet, comme sur X. Elle
       s'arrêtait 20 px avant — le décalage relevé par Éric le 31/08/2026.
       Le padding-right reste dans la ligne : c'est le TEXTE qui est en retrait,
       pas la boîte. */
    /* Pas d'arrondi (31/08/2026, relevé par Éric). Il avait un sens tant que la
       ligne flottait à l'intérieur de la colonne ; depuis qu'elle va d'un bord
       à l'autre, un coin arrondi contre le filet vertical laisse un croissant
       de vide. Une bande qui touche ses deux bords est carrée. */
    .set-menu-row.set-menu-actif{
      background:var(--hover);
      box-shadow:inset -3px 0 0 var(--action);
      border-radius:0;
    }
  }
  /* PARAMÈTRES OCCUPE TOUTE LA DROITE, façon X (31/08/2026, demandé par Éric :
     « le volet ouvert couvre complètement la droite de la page, donc masquer le
     panneau de droite »). La colonne de suggestions reste sur toutes les AUTRES
     pages — c'est la demande de la veille, elle tient toujours ; c'est seulement
     sur Paramètres qu'elle s'efface.
     Géométrie mesurée, pas devinée. Le rail fait 250 px et commence à
     50% - 594px + var(--dec) : son bord droit est donc à 50% - 207px entre 1260
     et 1519 (--dec 137) et à 50% - 379px au-delà (--dec -35). En laissant 24 px
     de gouttière de chaque côté :
       - 1260 à 1519 : la place vaut 50% + 159px, toujours < 988 -> on la prend
         toute, collée au rail (margin-left 50% - 183px) ;
       - 1520 et plus : la place vaut 50% + 331px, toujours > 988 -> on plafonne
         à 988 (la largeur de X) et on CENTRE dans le reste : 75% - 683.5px.
     Refaire margin-left EN MÊME TEMPS que max-width : la règle générale est
     margin-left:calc(50% - 320px + var(--dec)), où 320 est la moitié de 640 —
     elle ne suit pas un changement de largeur toute seule. */
  @media (min-width:1260px){
    body.tab-settings .wrap, body.tab-infos .wrap{max-width:calc(50% + 159px); margin-left:calc(50% - 183px);}
  }
  @media (min-width:1520px){
    body.tab-settings .side-widgets, body.tab-infos .side-widgets{display:none;}
    /* ALIGNÉES SUR LES AUTRES PAGES (31/08/2026, relevé par Éric). Elles étaient
       CENTRÉES dans l'espace libéré par la colonne de droite : leur bord gauche
       tombait 47 px plus à droite que celui du Journal à 1520, 67 à 1600, 147 à
       1920 — la seule chose de l'appli qui ne partait pas du même bord.
       Elles reprennent donc le margin-left de .wrap (50% - 320 + var(--dec), soit
       50% - 355 puisque --dec vaut -35 ici) et s'étendent jusqu'à la gouttière
       de 24 px à droite : 50% + 331. Bénéfice au passage, c'est plus large que
       les 988 px de X — d'où une colonne de menu à 340 px, où « Règles de saisie
       — comment ça compte ? » tient enfin sur une ligne. */
    body.tab-settings .wrap, body.tab-infos .wrap{
      max-width:calc(50% + 331px);
      margin-left:calc(50% - 355px);
    }
    .deux-volets.active{grid-template-columns:340px minmax(0, 1fr);}
    .deux-volets.active::before{left:340px;}
  }
  .set-back .chev{color:var(--parchment-dim);}
  /* EN-TÊTE D'UNE SECTION DÉPLIÉE, façon X (31/08/2026, demandé par Éric) :
     un gros titre, un blanc, puis une ligne de description en gris. Vaut pour
     Paramètres ET Informations — c'est le même volet de droite.
     `.volet-sous` et `.set-intro` se ressemblent parce qu'ils font la même
     chose : `.set-intro` existait déjà dans quatre sections de Paramètres, on
     ne l'a pas remplacé pour ne pas réécrire des textes qui vont bien. */
  .volet-section .set-title,
  .volet-section .info-h3{
    font-size:var(--t-xl);
    margin:0 0 10px;   /* l'espace entre le titre et le sous-titre */
  }
  .volet-sous,
  .set-intro{
    font-size:var(--t-sm); line-height:1.5; color:var(--parchment-dim);
    margin:0 0 10px;
  }
  /* Le blanc qui sépare l'en-tête du contenu : c'est lui qui fait lire les deux
     premières lignes comme un titre de page et non comme une première ligne. */
  .volet-section .volet-sous,
  .volet-section .set-intro{margin-bottom:22px;}
  .set-row{
    display:flex; align-items:center; gap:14px;
    padding:11px 0;
    border-top:1px solid var(--line);
  }
  .set-row:first-of-type{border-top:none;}
  .set-main{flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:2px;}
  .set-label{font-size:var(--t-md); color:var(--parchment); line-height:1.3;}
  .set-hint{font-size:var(--t-sm); color:var(--parchment-dim); line-height:1.35;}
  .set-hint:empty{display:none;}
  /* 190 px : la plus longue option (« 20 — en douceur », 115 px de texte) plus
     le rembourrage et la flèche. La part maximale est à 55 % pour que ce calcul
     tienne aussi sur un écran de téléphone, où 45 % tronquait le texte. */
  .set-ctrl{flex:0 0 auto; width:190px; max-width:55%;}
  select.set-ctrl{width:190px; max-width:55%;}
  button.set-ctrl{width:auto; max-width:60%;}
  .set-actions{display:flex; flex-wrap:wrap; gap:8px; margin-top:12px;}
  /* Une ligne cliquable réagit comme dans les réglages de X. */
  @media (hover:hover) and (pointer:fine){
    .set-row:hover .set-label{color:var(--action);}
  }
  /* Téléphone étroit : le contrôle passe sous son libellé plutôt que de
     l'écraser, mais garde son alignement à gauche. */
  @media (max-width:400px){
    .set-row{flex-direction:column; align-items:stretch; gap:8px;}
    .set-ctrl, select.set-ctrl, button.set-ctrl{width:100%; max-width:none;}
    /* Sauf une LIGNE D ACTION : un bouton « Supprimer » etale sur toute la
       largeur, sous son libelle, se lit comme l action principale de l ecran.
       Il reste a droite de ce qu il supprime, quelle que soit la largeur. */
    .set-row.set-row-action{flex-direction:row; align-items:center; gap:14px;}
    .set-row.set-row-action .set-ctrl{width:auto; max-width:50%;}
  }

  /* --- Tri des catégories --- */
  .cat-sort-row{margin:0 2px 10px;}

  /* --- Fiches : navigation précédente/suivante, empilée autour du numéro --- */
  .dex-num-col{display:flex; flex-direction:column; align-items:center; gap:3px; flex:0 0 auto;}
  .dex-nav-btn{width:28px; height:19px; border-radius:var(--r-sm); background:var(--soil-800); color:var(--parchment-dim);
    border:1px solid var(--arc-track); cursor:pointer; font-size:var(--t-xs); line-height:1;
    display:inline-flex; align-items:center; justify-content:center; padding:0;}
  .dex-nav-btn:hover{border-color:var(--action); color:var(--action);}

  /* --- Fiches : bouton d'action --- */

  /* ============================================================
     Thème clair (body.theme-light) : une apparence à part entière,
     pas une simple inversion — surfaces blanches sur fond gris-vert
     doux, or profond lisible, ombres légères, teintes recalibrées.
     ============================================================ */
  body.theme-light{
    --soil-900:#eef1ef;        /* fond de page gris-vert doux (jamais blanc pur) */
    --soil-800:#ffffff;        /* cartes */
    --soil-700:#e6eae8;        /* champs, chips, cellules */
    --line:#d3dad6;
    --parchment:#111714;
    --parchment-dim:#46524c; /* gris foncé : le texte secondaire doit rester lisible sur blanc */
    --wheat:#8f6400;           /* or profond, lisible sur blanc */
    --wheat-dim:#8f6400;
    --action:#00795a;          /* vert profond, lisible sur blanc */
    --action-dim:#00795a;
    --moss:#00795a;
    --moss-bright:#00795a;
    --rust:#c81e2e;
    --rust-dim:#c81e2e;   /* déjà à 5,70:1 avec du blanc : rien à assombrir */
    --clay:#8a7a66;
    --hover:rgba(17,23,20,0.05);
    --arc-track:#dde3e0;
  }
  body.theme-light ::selection{background:rgba(143,100,0,0.2);}
  /* La classe de thème est posée sur <html> aussi (voir applyPrefs) : c'est bien
     html.theme-light qu'il faut cibler — body.theme-light html ne matche jamais. */
  html.theme-light{scrollbar-color:#c2cbc7 transparent;}

  /* Surfaces flottantes : blanches, ombres douces */
  body.theme-light .topbar{background:rgba(238,241,239,0.85);}
  body.theme-light .bottom-nav{background:rgba(255,255,255,0.97); box-shadow:0 -1px 8px rgba(17,23,20,0.05);}
  /* Verre depoli en clair : blanc translucide, le flou vient de la regle generale. */
  body.theme-light .foods-dock{background:rgba(255,255,255,0.92); box-shadow:0 8px 26px rgba(17,23,20,0.12);}
  body.theme-light .action-menu{background:#fff; box-shadow:0 4px 12px rgba(17,23,20,0.1), 0 12px 40px rgba(17,23,20,0.18);}
  body.theme-light .toast{background:#fff; box-shadow:0 8px 30px rgba(17,23,20,0.16);}
  body.theme-light .ac-results{background:#fff; box-shadow:0 12px 40px rgba(17,23,20,0.16);}
  @media (max-width:859px){
    body.theme-light #panelInfos{background:#fff;}
  }
  body.theme-light .log-panel, body.theme-light .score-card, body.theme-light .suggest-panel,
  body.theme-light .hide-panel, body.theme-light .cat,
  body.theme-light .fs-tile{
    box-shadow:0 1px 3px rgba(17,23,20,0.05);
  }

  /* Bouton principal : pilule sombre façon X en clair (l'or bascule en accent secondaire) */
  body.theme-light .log-row > button{background:#111714; color:#fff;}
  body.theme-light .log-row > button:hover{filter:none; background:#2a332e;}
  body.theme-light .ff-chip.on{background:#111714; border-color:#111714; color:#fff;}
  body.theme-light .onboard-num{background:#111714; color:#fff;}
  body.theme-light .fs-bar-fill{background:#111714;}
  body.theme-light .st-bar-fill{background:#111714;}

  /* Champs : blancs bordés (les fonds gris passent mal dans les cartes blanches) */
  body.theme-light select, body.theme-light input[type=date], body.theme-light input[type=text]{
    background:#fff; border-color:var(--line);
  }
  body.theme-light select:focus, body.theme-light input:focus{border-color:var(--action); background:#fff;}

  /* Teintes de statut recalibrées pour fond blanc */
  body.theme-light .cat.good .cat-head{background:rgba(0,121,90,0.06);}
  body.theme-light .cat.warn .cat-head{background:rgba(143,100,0,0.07);}
  body.theme-light .cat.overdue .cat-head{background:rgba(200,30,46,0.05);}
  body.theme-light .item.row-discovered{background:rgba(0,121,90,0.05);}
  body.theme-light .item.row-undiscovered{background:rgba(17,23,20,0.015);}
  /* Même garde que le thème sombre (voir plus haut) : sans elle, sur écran
     tactile la couleur de survol restait « collée » à la dernière carte touchée. */
  @media (hover:hover) and (pointer:fine){
    body.theme-light .cat.good .cat-head:hover{background:rgba(0,121,90,0.1);}
    body.theme-light .cat.warn .cat-head:hover{background:rgba(143,100,0,0.11);}
    body.theme-light .cat.overdue .cat-head:hover{background:rgba(200,30,46,0.09);}
    body.theme-light .item.row-discovered:hover{background:rgba(0,121,90,0.09);}
    body.theme-light .item.row-undiscovered:hover{background:var(--hover);}
  }

  /* Accents or translucides recalibrés */
  body.theme-light .streak-chip{background:rgba(143,100,0,0.08); border-color:rgba(143,100,0,0.3);}
  body.theme-light .dex-row.dex-why{background:rgba(143,100,0,0.07);}
  body.theme-light .cat-dex{background:rgba(143,100,0,0.04);}
  body.theme-light .why-panel{background:rgba(143,100,0,0.05);}
  body.theme-light .basket-why.open{background:rgba(143,100,0,0.08);}
  body.theme-light .basket-why-panel{background:rgba(143,100,0,0.07);}
  body.theme-light .feel-btn.on{background:rgba(143,100,0,0.08);}
  body.theme-light .bristol-btn.on{background:rgba(143,100,0,0.08);}
  body.theme-light .toast-undo:hover{background:rgba(143,100,0,0.08);}
  body.theme-light .btn-mini:hover{background:rgba(143,100,0,0.06);}
  body.theme-light .btn-ghost:hover{background:rgba(143,100,0,0.06);}

  /* Calendrier : verts lisibles sur clair */
  body.theme-light .cal-cell.lvl1{background:rgba(0,121,90,0.13); color:var(--parchment);}
  body.theme-light .cal-cell.lvl2{background:rgba(0,121,90,0.45); color:#fff;}
  body.theme-light .cal-cell.lvl3{background:#00795a; color:#fff;}
  body.theme-light .cal-feel{filter:drop-shadow(0 1px 2px rgba(17,23,20,0.25));}

  /* Divers */
  body.theme-light .dex-panel, body.theme-light .stats-panel, body.theme-light .edit-panel,
  body.theme-light .item:has(+ .dex-panel), body.theme-light .item:has(+ .stats-panel),
  body.theme-light .item:has(+ .edit-panel){background:#f7f9f7;}
  /* :not(.on) est INDISPENSABLE. « body.theme-light .dex-month » pese (0,2,1)
     et ecrasait donc « .dex-month.on » (0,2,0) : en theme clair, les mois DE
     SAISON perdaient leur fond vert et gardaient leur texte blanc — des lettres
     blanches sur gris clair (1,2:1), donc la saison etait purement et simplement
     illisible. Meme piege que .deux-volets .drawer-head : quand une regle de
     theme vise la classe de base, elle doit exclure les variantes. */
  body.theme-light .dex-month:not(.on){background:var(--soil-700);}
  body.theme-light .history-panel{background:var(--soil-700);}
  body.theme-light .brand-logo{background:var(--soil-700);}
  body.theme-light .feel-btn{filter:grayscale(0.4) brightness(1);}
  body.theme-light .feel-btn:hover, body.theme-light .feel-btn.on{filter:none;}
  /* En clair, le halo devient une ombre douce sombre (un halo clair serait invisible sur blanc) */
  body.theme-light .dex-sprite{filter:drop-shadow(0 0 1px rgba(17,23,20,0.28)) drop-shadow(0 1px 4px rgba(17,23,20,0.18));}
  body.theme-light .dex-sprite.undiscovered{filter:grayscale(1) brightness(0.9) opacity(0.6)
    drop-shadow(0 0 1px rgba(17,23,20,0.2)) drop-shadow(0 1px 3px rgba(17,23,20,0.12));}

  /* Lisibilité : les effets pensés pour le sombre s'ajustent */
  body.theme-light .item .item-name.undiscovered{opacity:0.85;}
  body.theme-light .score-sub-item.locked{opacity:0.8;}
  body.theme-light .btn-mini.ghost{opacity:0.85;}
  body.theme-light footer{opacity:1;}
  body.theme-light .hide-current-empty{opacity:1;}
  body.theme-light .cat-dex-row span, body.theme-light .dex-row{color:var(--parchment-dim);}
  body.theme-light .btn-ghost.btn-disabled{
    background-image:repeating-linear-gradient(45deg, rgba(17,23,20,0.05) 0, rgba(17,23,20,0.05) 6px, transparent 6px, transparent 12px);
  }
  /* Badges de types de fiches : petits libellés blancs sur couleurs — on fonce
     légèrement le fond pour garder le contraste sur page claire */
  body.theme-light .dex-type{filter:brightness(0.82) saturate(1.1);}
  /* Tuiles de stats dans la carte Journal : cellules gris clair sur carte blanche */

  /* ============================================================
     Thème « Sombre doux » (body.theme-wa) : l'entre-deux entre le
     Black out et le Clair — surfaces gris-bleu profond inspirées
     de WhatsApp (mode sombre), avec de très légers motifs dessinés
     en fond de page (petits végétaux, à peine visibles).
     L'accent doré et les couleurs de statut (vert = à jour,
     doré = bientôt, rouge = en retard) sont conservés pour garder
     les mêmes repères que dans les autres thèmes.
     ============================================================ */
  body.theme-wa{
    --soil-900:#0b141a;        /* fond de page (bleu-gris nuit WhatsApp) */
    --soil-800:#111b21;        /* cartes / surfaces */
    --soil-700:#202c33;        /* champs, chips */
    --line:#233138;            /* filets */
    --parchment:#e9edef;
    --parchment-dim:#8696a0;
    /* Les couleurs d'état gardent leur sens, mais se recalibrent : les cartes
       de ce thème (#111b21) sont plus claires que celles du thème sombre
       (#0b0e0d), et le même rouge y tombait à 4,24:1 — sous le seuil (mesuré
       le 04/09/2026 sur les délais « en retard » des Molécules et des Stats).
       Même chose pour l'or sombre du numéro de fiche, à 4,08:1. */
    --rust:#f83b46;
    --rust-dim:#dd353e;
    --wheat-dim:#b58f2e;
    --hover:rgba(233,237,239,0.05);
    --arc-track:#2a373f;
    /* Motifs doodle très discrets, façon fond de discussion WhatsApp */
    background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180' viewBox='0 0 180 180'%3E%3Cg fill='none' stroke='%23e9edef' stroke-opacity='0.045' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 38c0-10 8-18 18-18 0 10-8 18-18 18z'/%3E%3Cpath d='M22 38c7-7 12-13 14-18'/%3E%3Ccircle cx='128' cy='32' r='12'/%3E%3Cpath d='M128 20c-1-4 2-7 5-8'/%3E%3Cpath d='M124 30c2-3 6-3 8 0'/%3E%3Cpath d='M28 122c0 8 6 14 14 14s14-6 14-14z'/%3E%3Cpath d='M42 136v10'/%3E%3Cpath d='M130 110v40'/%3E%3Cpath d='M130 120l-9-9M130 120l9-9M130 131l-9-9M130 131l9-9M130 142l-9-9M130 142l9-9'/%3E%3Ccircle cx='88' cy='80' r='3'/%3E%3Ccircle cx='70' cy='168' r='2.4'/%3E%3Ccircle cx='170' cy='84' r='2.4'/%3E%3C/g%3E%3C/svg%3E") repeat #0b141a;
  }
  body.theme-wa ::selection{background:rgba(245,184,46,0.3);}
  html.theme-wa{scrollbar-color:#37444d transparent;}
  /* Surfaces flottantes recalées sur la palette */
  body.theme-wa .topbar{background:rgba(11,20,26,0.82);}
  body.theme-wa .bottom-nav{background:rgba(17,27,33,0.97);}
  body.theme-wa .foods-dock{background:rgba(17,27,33,0.92);}
  body.theme-wa .action-menu{background:#111b21; box-shadow:0 0 15px rgba(233,237,239,0.06), 0 10px 34px rgba(0,0,0,0.7);}
  body.theme-wa .toast{background:#202c33;}
  body.theme-wa .ac-results{background:#111b21;}
  @media (max-width:859px){
    body.theme-wa #panelInfos{background:#111b21;}
  }
  body.theme-wa .drawer-head{background:#111b21;}
  /* Les cartes restent unies : les motifs ne vivent qu'en fond de page */
  body.theme-wa .log-panel, body.theme-wa .score-card, body.theme-wa .suggest-panel,
  body.theme-wa .hide-panel, body.theme-wa .cat,
  body.theme-wa .fs-tile{background:var(--soil-800);}

  /* ============================================================
     GRAND ÉCRAN (PC) — mise en page façon X version web.
     TOUT ce qui suit est enfermé dans des media queries min-width :
     en dessous de 860 px (téléphone, petite fenêtre), rien ne change.
     Trois paliers, comme sur X :
       ≥ 860 px : menu latéral gauche en icônes seules (rail),
                   la barre du bas disparaît ;
       ≥ 1260 px : le menu s'élargit (icônes + libellés + bouton doré) ;
       ≥ 1520 px : colonne de droite (raccourcis vers les infos).
     Le menu latéral et la colonne de droite sont positionnés par
     rapport au CENTRE de l'écran : la colonne de 640 px reste
     exactement où elle est, comme sur X.
     ============================================================ */
  .side-nav{display:none;}
  .side-widgets{display:none;}

  /* 860 px et non 1020 (revu le 30/08/2026) : entre 700 et 1019 px, la SEULE
     chose qui changeait dans tout ce fichier etait deux filets verticaux — on
     avait donc la mise en page telephone avec 130 px de vide de chaque cote sur
     un ecran de 900 px. Le rail (50% - 412 px, 68 px de large) degage la colonne
     de 640 px avec 24 px d'air des 844 px : 860 laisse une marge. */
  @media (min-width:860px){
    /* La barre du bas cède la place au menu latéral */
    .bottom-nav{display:none;}
    /* Les deux boutons de coin (microbe → Paramètres, i → Infos) sont des
       commandes de téléphone : le menu latéral fait leur travail ici. */
    #topSettingsBtn{display:none;}
    #topInfoBtn{display:none;}
    .wrap{padding-bottom:48px;}
    /* La barre du haut ne s'étale plus sur tout l'écran : elle épouse la
       colonne centrale, comme l'en-tête de colonne de X. */
    /* margin-left calculé plutôt que « auto » : c'est ce qui applique --dec sans
       transform — .topbar en porte déjà un (elle glisse hors de l'écran au
       défilement) et .wrap contient des éléments en position:fixed. */
    :root{--dec:46px;}
    .topbar{max-width:640px; margin-left:calc(50% - 320px + var(--dec)); margin-right:0;}
    .wrap{margin-left:calc(50% - 320px + var(--dec)); margin-right:0;}
    /* Plus de barre basse : le dock de recherche et les toasts descendent */
    .foods-dock{bottom:24px;}
    .toast-stack{bottom:24px;}

    /* --- Menu latéral : rail d'icônes --- */
    .side-nav{
      display:block;
      position:fixed; top:0; bottom:0;
      left:max(10px, calc(50% - 412px + var(--dec)));
      width:68px;
      z-index:80;
      padding:6px 0 16px;
    }
    .side-nav-inner{display:flex; flex-direction:column; align-items:center; gap:2px; height:100%;}
    .side-brand{
      width:50px; height:50px; flex:0 0 auto;
      display:flex; align-items:center; justify-content:center;
      font-size:27px; margin-bottom:2px;
      border-radius:50%;
      user-select:none;
    }
    .side-brand-name{display:none;}
    /* Logo de l'appli (l'artichaut du manifest) à la place de l'ancien microbe. */
    .side-brand-img{width:34px; height:34px; border-radius:50%; display:block;}
    /* Boutons : mêmes classes que la barre du bas (le JS les branche),
       mais restylés en pilules horizontales façon X. */
    .side-nav .side-btn{
      /* flex:0 0 auto : annule le flex:1 hérité de .nav-btn (barre du bas),
         qui étirait chaque bouton sur toute la hauteur de l'écran. */
      display:flex; flex:0 0 auto; flex-direction:row; align-items:center; justify-content:center;
      gap:0; width:50px; height:50px; padding:0;
      background:none; border:none; border-radius:9999px;
      color:var(--parchment);
      font-family:var(--font); font-size:var(--t-lg); font-weight:500;
      cursor:pointer;
      transition:background var(--d-normale) var(--courbe);
    }
    /* LA PILULE DOIT SE VOIR (31/08/2026, demandé par Éric : « que les boutons
       soient englobés par un rectangle aux coins complètement arrondis comme
       X »). Elle existait déjà — border-radius:9999px et un fond au survol —
       mais ce fond était `--hover`, soit 4 % d'opacité : à peine 2 % de
       contraste sur le noir, on ne le voyait pas. 10 % au survol, et la page
       ACTIVE garde sa pilule en permanence : sur X on repère l'onglet courant à
       l'icône pleine et au gras, ce qui suppose de les connaître ; un fond
       le dit sans rien demander. */
    .side-nav .side-btn:hover{background:rgba(231,233,234,0.10); color:var(--parchment);}
    .side-nav .side-btn:active{background:rgba(231,233,234,0.16);}
    .side-nav .side-btn.active{background:rgba(231,233,234,0.07);}
    .side-nav .side-btn.active:hover{background:rgba(231,233,234,0.13);}
    body.theme-light .side-nav .side-btn:hover{background:rgba(17,23,20,0.07);}
    body.theme-light .side-nav .side-btn.active{background:rgba(17,23,20,0.05);}
    .side-btn .side-lbl{display:none;}
    .side-ico{display:flex; flex:0 0 auto;}
    .side-ico svg{display:block; width:26px; height:26px;}
    /* Actif façon X : l'icône passe en version pleine (voir .ico-fill plus
       haut) et le libellé en gras. */
    .side-nav .side-btn.active{color:var(--parchment); font-weight:800;}
    /* Bouton d'action doré, façon « Poster » : rond « + » en mode rail */
    .side-compose{
      margin-top:14px;
      width:50px; height:50px; flex:0 0 auto;
      display:flex; align-items:center; justify-content:center;
      background:var(--action); color:#000;
      border:none; border-radius:9999px;
      font-family:var(--font); font-size:28px; font-weight:800; line-height:1;
      cursor:pointer;
      box-shadow:0 4px 14px rgba(0,0,0,0.35);
      transition:filter var(--d-normale) var(--courbe), transform var(--d-vite) var(--courbe);
    }
    .side-compose:hover{filter:brightness(1.1);}
    .side-compose:active{transform:scale(0.97);}
    .side-compose .side-lbl{display:none;}
    .side-compose .side-plus{display:block; margin-top:-2px;}
    /* Thème clair : pilule sombre, comme le bouton Enregistrer */
    body.theme-light .side-compose{background:#111714; color:#fff; box-shadow:0 4px 14px rgba(17,23,20,0.2);}
    body.theme-light .side-compose:hover{filter:none; background:#2a332e;}
  }

  @media (min-width:1260px){
    /* --- Menu latéral élargi : icônes + libellés --- */
    :root{--dec:137px;}
    .side-nav{width:250px; left:max(10px, calc(50% - 594px + var(--dec))); padding:6px 10px 16px;}
    .side-nav-inner{align-items:stretch;}
    .side-brand{
      width:auto; height:auto; align-self:flex-start;
      display:flex; align-items:center; gap:10px;
      padding:10px 14px; margin-bottom:4px;
      font-size:26px; border-radius:9999px;
    }
    .side-brand-name{display:inline; font-size:var(--t-lg); font-weight:800; letter-spacing:-0.2px; color:var(--parchment);}
    .side-nav .side-btn{
      width:auto; height:auto; align-self:flex-start;
      justify-content:flex-start; gap:16px;
      padding:11px 22px 11px 14px;
    }
    .side-btn .side-lbl{display:inline;}
    .side-compose{
      width:auto; height:auto; align-self:stretch;
      padding:14px 20px;
      font-size:var(--t-md);
    }
    .side-compose .side-plus{display:none;}
    .side-compose .side-lbl{display:inline;}
  }

  @media (min-width:1520px){
    :root{--dec:-35px;}
    /* --- Colonne de droite, façon « Tendances » de X --- */
    .side-widgets{
      display:block;
      position:fixed; top:14px;
      left:calc(50% + 344px + var(--dec));
      width:320px;
      z-index:40;
      /* Elle accueille desormais le secondaire deplie (jusqu a cinq cartes) :
         sur un ecran peu haut, elle defile plutot que de deborder. */
      max-height:calc(100vh - 28px);
      overflow-y:auto;
      /* Barre de defilement masquee (30/08/2026). Sur un portable — moins de
         ~750 px de hauteur utile — les cartes debordent et Windows collait une
         barre grise permanente contre le bord du panneau, visible en
         permanence alors qu'elle ne sert qu'a quelques dizaines de pixels. Le
         defilement reste entier (molette, clavier, pave tactile) : c'est la
         barre qui part, pas le mouvement. overscroll-behavior evite que la
         page entiere se mette a defiler quand la colonne arrive au bout. */
      scrollbar-width:none;
      -ms-overflow-style:none;
      overscroll-behavior:contain;
    }
    .side-widgets::-webkit-scrollbar{width:0; height:0;}
    /* La date du jour et la série 🔥 vivent en tête de cette colonne,
       plus dans la barre du haut. */
    .topbar-date{display:none;}
    .topbar .streak-chip{display:none;}
    .widget-head-row{display:flex; align-items:center; justify-content:space-between; gap:10px;}
    .widget-date{font-size:var(--t-sm); color:var(--parchment-dim); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
    .widget-streak{
      font-size:var(--t-sm); font-weight:700;
      color:var(--action);
      background:rgba(245,184,46,0.12);
      border:1px solid rgba(245,184,46,0.3);
      border-radius:9999px;
      padding:4px 10px;
      white-space:nowrap;
      flex:0 0 auto;
    }
    .widget-card{
      background:var(--soil-800);
      border:1px solid var(--line);
      border-radius:var(--r-md);
      padding:14px 16px;
      margin-bottom:12px;
    }
    body.theme-light .widget-card{box-shadow:0 1px 3px rgba(17,23,20,0.05);}
    /* 16 px, comme la marge intérieure des cartes au-dessus : à 6 px, la
       dernière ligne de la colonne dépassait de 10 px et le bord n'avait plus
       l'air droit. */
    .widget-foot{font-size:var(--t-sm); color:var(--parchment-dim); opacity:0.75; padding:0 16px; line-height:1.5;}
    /* Le secondaire du Journal, déplié ici (décision B du 30/08/2026) : le JS
       déplace #journalSecondary dans cette colonne au-delà de 1520 px, ses
       cartes reprennent alors l'habillage de la colonne et gardent leur titre.
       Les règles .widget-row et .kf-* ont disparu avec les deux widgets
       qu'elles habillaient — voir index.html. */
    #journalSecondary.sec-colonne > *{
      background:var(--soil-800);
      border:1px solid var(--line);
      border-radius:var(--r-md);
      padding:14px 16px;
      margin-bottom:12px;
    }
    #journalSecondary.sec-colonne > *:empty{display:none;}
    /* La colonne reste GARNIE sur toutes les pages (31/08/2026, demandé par
       Éric). Le C-11 du 30/08 la faisait taire hors du Journal — au motif que
       « Défi de la semaine » à côté d'une liste de réglages fait deux
       conversations — mais le résultat était pire : une colonne vide de 320 px
       qui donnait l'impression que la page avait perdu la moitié de son
       contenu. C'est aussi ce que fait X, dont la colonne de droite ne change
       pas selon l'onglet. Le conteneur n'est ni recopié ni reconstruit, il est
       seulement déplacé : les gestionnaires posés sur ses cartes survivent. */
    body.theme-light #journalSecondary.sec-colonne > *{box-shadow:0 1px 3px rgba(17,23,20,0.05);}
    #journalSecondary.sec-colonne .log-title,
    #journalSecondary.sec-colonne .app-tip-head{margin-bottom:8px;}
    /* Plus de reglage de taille ici : le secondaire a desormais UN corps de
       texte, defini une seule fois pres de .suggest-row. */
  }

  /* ============================================================
     CIBLES TACTILES (constat 07 de l'audit du 30/08/2026)
     Le bouton le plus courant de l'appli (.btn-mini) faisait 26 px de haut,
     les lignes de liste 29, la croix d'effacement du champ 21 — quand le
     minimum tenable, chez Apple comme chez Google, est de 44. L'echelle de
     Bristol illisible n'etait pas un accident isole : c'etait le meme reglage,
     vu sous un autre angle.
     TOUT est ici sous @media (pointer:coarse), c'est-a-dire au DOIGT : a la
     souris, 26 px se cliquent tres bien et forcer 44 partout gonflerait les
     listes du PC pour rien. Consequence assumee : sur telephone, les lignes de
     la page Categories repassent de 29 a 44 px — c'est la seule regle de cette
     page qui ait desormais une variante, et c'est par le pointeur, pas par la
     taille d'ecran.
     Deux techniques, selon le voisinage :
       - un bouton isole GRANDIT vraiment (min-height) ;
       - un bouton serre dans une ligne recoit une zone etendue invisible
         (::before en position absolue), qui ne change rien a la mise en page.
     Ne jamais etendre une zone au-dela de la moitie de l'espace qui separe
     deux boutons voisins : ils se voleraient les touchers.
     ============================================================ */
  @media (pointer:coarse){
    /* --- 1. Ce qui peut vraiment grandir --- */
    .btn-mini, .btn-ghost, .ff-chip, .drawer-close,
    .log-row > button, .recipe-chip button, .hide-add{min-height:44px;}
    .dex-nav-btn{min-width:44px; min-height:44px;}
    select, input[type=text], input[type=date]{min-height:44px;}
    .icon-btn{width:44px; height:44px;}
    .basket-chip{min-height:44px;}
    .basket-chip .basket-remove{min-width:40px; min-height:40px; padding:4px 12px;}

    /* --- 2. Les lignes de liste : la hauteur EST la cible ---
       Un bouton plus haut que sa ligne deborderait sur la ligne voisine et lui
       volerait ses touchers : c'est la ligne qui doit grandir, pas le bouton. */
    .item{min-height:44px;}
    .item .stats-btn, .item .fav-btn, .item .menu-btn{
      width:44px; height:44px; margin:0 -2px; /* -2 px de chaque cote : la moitie du vide de 8 px reste libre */
    }
    .wa-row, .hist-row, .freq-row, .set-row{min-height:44px;}
    .hist-row{min-height:44px;}

    /* --- 3. Zone etendue sans toucher a la mise en page ---
       La croix du champ de recherche n'a aucun voisin : elle peut s'etendre
       largement. Les liens-textes s'etendent peu horizontalement, pour ne pas
       mordre sur le titre a cote d'eux. */
    .search-clear::before{content:""; position:absolute; inset:-12px;}
    .undo-link, .when-count{position:relative;}
    .undo-link::before{
      content:""; position:absolute; inset:-12px -4px;
    }
    /* Le compteur du jour fait 19 px de haut : seul sur sa ligne, il peut
       s'étendre largement sans marcher sur rien. */
    .when-count::before{
      content:""; position:absolute; inset:-13px -8px;
    }
    /* Le retour « ‹ Paramètres » mesurait 60 x 35 px au doigt : il est seul sur
       sa ligne, il peut simplement grandir. */
    .set-back{min-height:44px;}
    /* LE BOUTON CODE-BARRES : 27 x 27 px au doigt, le seul de l'appli sous les
       44 px (mesuré point par point le 04/09/2026, pas calculé). Il vit DANS le
       champ, à 3 px de la croix d'effacement : impossible de l'étendre sans lui
       voler ses touchers. On écarte donc d'abord la croix — le champ a la place
       —, puis on étend la zone en restant sous la moitié du vide rendu (15 px
       de vide, 7 px pris). Aucun pixel visible ne bouge. */
    .ac-wrap .search-clear{right:52px;}
    .scan-btn::before{
      content:""; position:absolute; inset:-9px -9px -9px -7px;
    }
  }

/* ============================================================
   SCANNER DE CODE-BARRES (02/09/2026)
   Le bouton vit DANS le champ de saisie, comme la croix d'effacement : la ligne
   n'a de la place que pour deux commandes (mesuré : à 320 px, le champ et
   « Enregistrer » occupent déjà 250 des 254 px utiles), et un troisième bouton
   dans le flux la repliait sur deux lignes sur tous les téléphones.
   Le panneau, lui, est un dialogue plein écran : il n'appartient à aucun onglet,
   se ferme sur le voile, et ses six états sont pilotés par data-etat — même
   mécanique que data-vue pour Paramètres et Informations.
   ============================================================ */
.scan-btn{
  position:absolute; right:10px; top:50%; transform:translateY(-50%);
  background:none; border:none; color:var(--parchment-dim); cursor:pointer;
  padding:4px; line-height:1; display:block;
  transition:color var(--d-vite) var(--courbe);
}
.scan-btn svg{display:block;}
.scan-btn:hover{color:var(--action);}
/* La croix se range à gauche du scanner quand elle apparaît. */
.ac-wrap .search-clear{right:40px;}

.scan-panel{
  position:fixed; inset:0; z-index:120; display:none;
  background:rgba(0,0,0,0.72); backdrop-filter:blur(6px);
  align-items:flex-end; justify-content:center;
}
.scan-panel.show{display:flex;}
.scan-boite{
  width:100%; max-width:560px; max-height:92vh; overflow-y:auto;
  background:var(--soil-800); border:1px solid var(--line);
  border-radius:var(--r-md) var(--r-md) 0 0;
  padding:16px 16px calc(16px + env(safe-area-inset-bottom, 0px));
  animation:panelIn var(--d-ample) var(--courbe);
}
@media (min-width:700px){
  .scan-panel{align-items:center;}
  .scan-boite{border-radius:var(--r-md); max-height:86vh;}
}
.scan-head{display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:12px;}
.scan-close{
  background:none; border:none; color:var(--parchment-dim); cursor:pointer;
  padding:6px; line-height:1; border-radius:var(--r-full);
}
.scan-close:hover{color:var(--parchment); background:var(--hover);}

.scan-cam{position:relative; border-radius:var(--r-sm); overflow:hidden; background:#000; display:none;}
.scan-cam video{width:100%; max-height:46vh; display:block; object-fit:cover;}
.scan-cadre{
  position:absolute; left:12%; right:12%; top:30%; bottom:30%;
  border:2px solid var(--action); border-radius:var(--r-sm); pointer-events:none;
  box-shadow:0 0 0 100vmax rgba(0,0,0,0.35);
}
.scan-aide{
  position:absolute; left:0; right:0; bottom:10px; text-align:center;
  font-size:var(--t-sm); color:#fff; text-shadow:0 1px 3px rgba(0,0,0,0.8); pointer-events:none;
}
.scan-saisie{display:none; margin:4px 0 8px;}
.scan-saisie label{display:block; font-size:var(--t-sm); color:var(--parchment-dim); margin-bottom:6px;}
.scan-saisie-row{display:flex; gap:8px;}
.scan-saisie-row input{flex:1 1 auto; min-width:0;}
.scan-attente{display:none; padding:22px 4px; text-align:center; color:var(--parchment-dim); font-size:var(--t-sm);}
.scan-corps{display:none;}
.scan-corps p{font-size:var(--t-sm); color:var(--parchment-dim); line-height:1.55; margin:8px 0;}
.scan-code{font-variant-numeric:tabular-nums; color:var(--parchment);}
.scan-marque{font-size:var(--t-sm); color:var(--parchment-dim); margin:-6px 0 10px;}

.scan-portion{font-size:var(--t-sm); color:var(--parchment-dim); margin:10px 0 12px;}
.scan-portion input{
  width:82px; padding:7px 9px; font-size:var(--t-sm);
  background:var(--soil-700); color:var(--parchment);
  border:1px solid var(--line); border-radius:var(--r-sm);
}
/* Les cases suivent la couleur de l appli, pas le bleu du systeme. */
.scan-ligne input[type=checkbox]{accent-color:var(--action); width:17px; height:17px;}
.scan-defaut{font-size:var(--t-xs);}

/* Une ligne par ingrédient : ce qu'on lit sur l'étiquette, ce que l'appli en
   fait, et combien il y en a. Ce qui ne compte pas reste VISIBLE, en gris :
   c'est ce qui permet de vérifier que l'appli n'a rien inventé. */
.scan-lignes{border-top:1px solid var(--line);}
.scan-ligne{
  display:flex; align-items:flex-start; gap:10px;
  padding:9px 2px; border-bottom:1px solid var(--line);
}
.scan-ligne input[type=checkbox]{margin-top:3px; flex:0 0 auto;}
.scan-ligne label{flex:1 1 auto; min-width:0; cursor:pointer; display:block;}
.scan-puce{flex:0 0 auto; width:13px; text-align:center; color:var(--parchment-dim);}
.scan-nom{display:block; font-size:var(--t-sm); color:var(--parchment);}
.scan-sort{display:block; font-size:var(--t-xs); color:var(--parchment-dim); margin-top:2px; line-height:1.45;}
.scan-pct{
  flex:0 0 auto; font-size:var(--t-xs); color:var(--parchment-dim);
  font-variant-numeric:tabular-nums; padding-top:2px;
}
.scan-hors .scan-nom{color:var(--parchment-dim);}
.scan-bilan{margin-top:12px; font-size:var(--t-sm); color:var(--moss-bright);}

/* Les deux boutons qui font AVANCER reprennent le doré d Enregistrer : c est le
   meme geste, il doit avoir la meme tete. Les autres restent des .btn-mini. */
.scan-saisie-row button, #scanValiderBtn{
  flex:0 0 auto; background:var(--action); color:#000; border:none;
  border-radius:var(--r-full); padding:11px 20px;
  font-size:var(--t-md); font-weight:800; cursor:pointer;
  transition:filter var(--d-normale) var(--courbe), transform var(--d-vite) var(--courbe);
}
.scan-saisie-row button:hover, #scanValiderBtn:hover{filter:brightness(1.1);}
.scan-saisie-row button:active, #scanValiderBtn:active{transform:scale(0.98);}

.scan-actions{display:flex; flex-wrap:wrap; gap:8px; margin-top:14px; align-items:center;}
.scan-actions button{display:none;}
.scan-source{
  margin-top:14px; padding-top:10px; border-top:1px solid var(--line);
  font-size:var(--t-xs); color:var(--parchment-dim); line-height:1.5;
}

/* Un seul état visible à la fois. */
.scan-panel[data-etat="depart"] .scan-cam,
.scan-panel[data-etat="camera"] .scan-cam{display:block;}
.scan-panel[data-etat="depart"] #scanManuelBtn,
.scan-panel[data-etat="camera"] #scanManuelBtn{display:inline-block;}
.scan-panel[data-etat="saisie"] .scan-saisie{display:block;}
.scan-panel[data-etat="saisie"] #scanCameraBtn{display:inline-block;}
.scan-panel[data-etat="attente"] .scan-attente{display:block;}
.scan-panel[data-etat="resultat"] .scan-corps,
.scan-panel[data-etat="erreur"] .scan-corps,
.scan-panel[data-etat="connu"] .scan-corps{display:block;}
.scan-panel[data-etat="resultat"] #scanValiderBtn,
.scan-panel[data-etat="connu"] #scanValiderBtn{display:inline-block;}
.scan-panel[data-etat="resultat"] #scanRetourBtn,
.scan-panel[data-etat="erreur"] #scanRetourBtn,
.scan-panel[data-etat="connu"] #scanRetourBtn{display:inline-block;}
.scan-panel[data-etat="erreur"] #scanManuelBtn{display:inline-block;}


/* ============================================================
   ESPACE MOLÉCULES (03/09/2026)
   Aucun dialecte nouveau : la pastille de statut, le chevron, la carte, le filet
   entre les lignes et l'intitulé discret sont ceux du reste de l'appli. Ce qui
   est propre à cette page, c'est l'ordre : LES MANQUES D'ABORD, la taxonomie
   ensuite — c'est le manque qu'on vient chercher.
   ============================================================ */
.mol-count{
  flex:0 0 auto;
  font-size:var(--t-sm); font-weight:600; color:var(--parchment-dim);
  font-variant-numeric:tabular-nums;
}
.mol-vide, .mol-reste, .mol-neuves{
  font-size:var(--t-sm); line-height:1.55; color:var(--parchment-dim); margin:0;
}
.mol-reste{margin-top:10px;}
/* « Pas encore découvertes » n'est PAS un manque : on ne peut pas être en retard
   sur ce qu'on n'a jamais commencé (même règle que la ligne d'action du
   Journal). D'où le filet qui l'isole du bloc des retards. */
.mol-neuves{margin-top:12px; padding-top:10px; border-top:1px solid var(--line);}

/* Un manque : le nom et le délai sur la première ligne, ce qu'il faut manger
   dessous. Le « quoi manger » est la moitié utile — un manque sans réponse
   n'est qu'un reproche. */
.mol-manque{
  display:grid; grid-template-columns:1fr auto; gap:2px 10px;
  padding:9px 0; border-bottom:1px solid var(--line); cursor:pointer;
  transition:background var(--d-vite) var(--courbe);
}
.mol-manque:last-child{border-bottom:none;}
@media (hover:hover) and (pointer:fine){
  .mol-manque:hover{background:var(--hover);}
}
.mol-manque-nom{font-size:var(--t-sm); font-weight:700; color:var(--parchment);}
.mol-manque-delai{
  font-size:var(--t-sm); font-weight:600; color:var(--rust);
  text-align:right; white-space:nowrap; font-variant-numeric:tabular-nums;
}
.mol-manque-quoi{
  grid-column:1 / -1;
  font-size:var(--t-sm); line-height:1.45; color:var(--parchment-dim);
}

/* Une ligne de molécule dans sa famille. */
.mol-row{
  display:flex; align-items:center; gap:10px;
  padding:7px 0; border-bottom:1px solid var(--line); cursor:pointer;
  color:var(--parchment-dim);
  transition:background var(--d-vite) var(--courbe);
}
.mol-famille .mol-row:last-of-type{border-bottom:none;}
@media (hover:hover) and (pointer:fine){
  .mol-row:hover{background:var(--hover);}
}
/* Ligne ouverte et fiche forment UN bloc, comme l'historique du Journal : même
   fond, arrondi en haut pour l'une, en bas pour l'autre, et le fond déborde de
   10 px pour que le texte reste aligné sur le bord de la carte. */
.mol-row.open{
  background:var(--hover); border-bottom-color:transparent;
  border-radius:var(--r-sm) var(--r-sm) 0 0;
  box-shadow:-10px 0 0 var(--hover), 10px 0 0 var(--hover);
}
.mol-dot{width:9px; height:9px; border-radius:var(--r-full); flex:0 0 auto;}
.mol-name{
  flex:1 1 auto; min-width:0;
  font-size:var(--t-md); color:var(--parchment);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.mol-delai{
  flex:0 0 auto; font-size:var(--t-sm); white-space:nowrap;
  color:var(--parchment-dim); font-variant-numeric:tabular-nums;
}
.mol-delai.mol-retard{color:var(--rust);}
.mol-delai.mol-warn{color:var(--wheat);}
/* Complément déclaré à un rythme plus espacé que la cible : même signal que
   « warn » — la pastille (molCouleur) était dorée, le texte restait gris. */
.mol-delai.mol-complement-espace{color:var(--wheat);}
.mol-delai.mol-regime-partiel{color:var(--wheat);}

/* Mes compléments (05/09/2026) : recherche + pastilles des jours. Les pastilles
   prennent les couleurs des puces de préparation, déjà validées au banc des
   couleurs (encre noire sur le vert d'action). */
.compl-search{margin-top:6px;}
.compl-search .ac-results{position:absolute; top:calc(100% + 6px);}
.compl-fam{display:block; font-size:var(--t-xs); color:var(--parchment-dim);}
.compl-choix{margin-top:12px;}
.compl-choisi{margin-bottom:8px; font-size:var(--t-md);}
.jours-pills{display:flex; flex-wrap:wrap; gap:6px; margin:6px 0 10px;}
.jour-pill{
  width:36px; height:36px; border-radius:50%;
  border:1px solid var(--line); background:none;
  color:var(--parchment-dim); font-family:var(--font); font-size:var(--t-sm); font-weight:700;
  cursor:pointer; transition:background var(--d-vite) var(--courbe), color var(--d-vite) var(--courbe), border-color var(--d-vite) var(--courbe);
}
.jour-pill[aria-pressed="true"]{background:var(--action); border-color:var(--action); color:#000;}
@media (pointer:coarse){ .jour-pill{width:44px; height:44px;} }

/* ---------- Listes de choix maison (05/09/2026) ----------
   Le <select> natif reste dans la page pour porter la valeur ; il est
   soustrait à l'œil et au doigt, jamais retiré du DOM. */
select.choix-natif{position:absolute !important; width:1px; height:1px; opacity:0; pointer-events:none; margin:0; padding:0; border:0; overflow:hidden; clip:rect(0 0 0 0);}
.choix{position:relative; display:inline-block; vertical-align:middle;}
.choix-btn{
  width:100%; display:inline-flex; align-items:center; justify-content:space-between; gap:8px;
  background:var(--soil-800); color:var(--parchment);
  border:1px solid var(--line); border-radius:var(--r-sm);
  padding:8px 12px; min-height:38px;
  font-family:var(--font); font-size:var(--t-sm); text-align:left; cursor:pointer;
  transition:border-color var(--d-vite) var(--courbe), background var(--d-vite) var(--courbe);
}
.choix-btn:hover, .choix.open .choix-btn{border-color:var(--action);}
.choix-btn:disabled{opacity:.5; cursor:default;}
.choix-val{flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.choix-btn .chev{flex:0 0 auto;}
/* Le menu, au dessin de la liste de saisie du Journal. */
.choix-panel{
  position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:60;
  min-width:100%;
  display:flex; flex-direction:column; max-height:min(360px, 60vh);
  background:var(--soil-800); border:1px solid var(--line); border-radius:var(--r-md);
  box-shadow:0 12px 40px rgba(0,0,0,0.7);
  animation:popIn var(--d-vite) var(--courbe); transform-origin:top center;
}
.choix-panel[hidden]{display:none;}
.choix-filtre{flex:0 0 auto; margin:8px 8px 4px; width:auto;}
.choix-liste{overflow-y:auto; padding:4px 0; overscroll-behavior:contain;}
.choix-grp{padding:8px 14px 2px; font-size:var(--t-xs); font-weight:700; text-transform:uppercase; letter-spacing:0.8px; color:var(--parchment-dim);}
.choix-opt{padding:9px 14px; font-size:var(--t-md); cursor:pointer; display:flex; align-items:center; gap:10px; outline:none; transition:background var(--d-vite) var(--courbe);}
.choix-opt:hover, .choix-opt:focus{background:var(--hover);}
.choix-opt.on{color:var(--action); font-weight:700;}
.choix-opt.on::after{content:"✓"; margin-left:auto;}
.choix-opt.off{opacity:.45; cursor:default;}
/* Sur téléphone : une feuille au bas de l'écran, sous un voile. */
.choix-panel.feuille{
  position:fixed; left:0; right:0; bottom:0; top:auto; z-index:130;
  max-height:70vh; border-radius:var(--r-md) var(--r-md) 0 0; border-bottom:none;
  animation:none; padding-bottom:env(safe-area-inset-bottom);
}
.choix-panel.feuille .choix-opt{padding:13px 18px;}
.choix-voile{position:fixed; inset:0; background:rgba(0,0,0,0.55); z-index:129;}
.choix-voile[hidden]{display:none;}
body.choix-ouvert{overflow:hidden;}

.mol-fiche{
  background:var(--hover);
  border-radius:0 0 var(--r-sm) var(--r-sm);
  box-shadow:-10px 0 0 var(--hover), 10px 0 0 var(--hover);
  padding:2px 0 12px;
  margin-bottom:8px;
}
.mol-fiche p{margin:0 0 8px; font-size:var(--t-sm); line-height:1.55; color:var(--parchment-dim);}
.mol-fiche p:last-child{margin-bottom:0;}
.mol-role{color:var(--parchment) !important;}
.mol-cible{font-variant-numeric:tabular-nums;}
.mol-fiche b{color:var(--parchment); font-weight:600;}
.mol-sources .fs-label{display:inline-block; margin-bottom:3px;}
/* Les sources sont des NOMS, pas des boutons : du texte séparé par des points
   médians, comme le détail du Calendrier depuis le 30/08. Pas de pilules. */
.mol-src{color:var(--parchment);}
.mol-sec .mol-src{color:var(--parchment-dim);}

/* 44 px au doigt seulement (règle du 30/08) : à la souris, 30 px se cliquent
   très bien, et forcer 44 partout étirerait une page de 55 lignes pour rien. */
@media (pointer:coarse){
  .mol-row{min-height:44px;}
  .mol-manque{min-height:44px; align-content:center;}
}

/* Les anti-nutriments (03/09/2026). Ils se comptent à l'envers des autres — on
   ne cherche pas à en avoir, on regarde s'ils sont là trop souvent — et ils se
   signalent en DORÉ, jamais en rouge : le rouge dit « tu es en retard », et
   personne n'est en retard sur des phytates. L'or dit « regarde par ici ».
   Chaque ligne porte son remède, en gris, à la place du « quoi manger » des
   manques : c'est ce qui fait la différence entre une consigne de cuisine et
   un reproche. */
.mol-charge .mol-manque-delai{color:var(--wheat);}
.mol-charges .mol-count{color:var(--wheat);}


/* Le sélecteur de préparation du panier (03/09/2026). Même famille visuelle que
   le bouton de date juste à côté : discret tant qu'il n'est pas renseigné, encre
   pleine une fois répondu. Il n'apparaît que sur les entrées où la réponse change
   ce qui est compté — 452 sur 1292 au 04/09/2026 (le chiffre suit le catalogue). */
/* (gabarit commun : voir .basket-pill) */
/* Tant qu'il attend une réponse, le bouton se voit — pointillé et vert
   d'action (05/09/2026, demandé par Éric) : c'est l'état qui réclame un geste.
   Répondu, il redevient sobre : la réponse est dans son libellé. */
.basket-prep:not(.set){border-style:dashed; border-color:var(--action); color:var(--action);}
.basket-prep.set{color:var(--parchment); border-color:var(--parchment-dim);}
/* L'aide sous les puces de cuisson : le seuil unique de 10 minutes. */
.prep-aide{font-size:var(--t-xs); color:var(--parchment-dim); margin:5px 0 0; line-height:1.45;}
@media (hover:hover) and (pointer:fine){
  .basket-prep:hover{color:var(--parchment); border-color:var(--parchment-dim);}
}
.basket-prep-panel{padding-top:10px;}
.prep-intro{margin:0 0 10px; font-size:var(--t-sm); line-height:1.5; color:var(--parchment-dim);}
.prep-axe{margin-bottom:10px;}
.prep-axe:last-child{margin-bottom:0;}
.prep-chips{display:flex; flex-wrap:wrap; gap:6px; margin-top:2px;}
/* Une puce, pas une case à cocher : on retouche la réponse au doigt, souvent une
   seule fois par aliment puisqu'elle est mémorisée ensuite. */
.prep-chip{
  background:none; border:1px solid var(--line); border-radius:var(--r-full);
  padding:5px 11px;
  font-family:var(--font); font-size:var(--t-sm); font-weight:600;
  color:var(--parchment-dim); cursor:pointer;
  transition:background var(--d-vite) var(--courbe), color var(--d-vite) var(--courbe), border-color var(--d-vite) var(--courbe);
}
.prep-chip.on{background:var(--action); border-color:var(--action); color:#000;}
@media (hover:hover) and (pointer:fine){
  .prep-chip:not(.on):hover{color:var(--parchment); border-color:var(--parchment-dim);}
}
@media (pointer:coarse){
  .prep-chip{min-height:36px;}
  /* Au doigt, les trois pilules grandissent ENSEMBLE — c'est tout l'intérêt du
     gabarit commun : une seule ligne à changer, jamais trois hauteurs. */
  .basket-pill{min-height:32px;}
}

/* Le repli de la ligne du panier a été retiré le 04/09/2026 : les commandes ne
   partagent plus la rangée du nom (voir .basket-actions), il n'y a donc plus
   rien à replier. Le nom occupe toute la largeur moins la croix. */
