/* ===================================================================
   POPOTAM SUR TELEPHONE
   ===================================================================
   Cette feuille ne contient QUE des regles sous `@media (max-width: 600px)`.
   Sur un ecran large elle ne pose rien : ouvrir ce fichier n'a aucun effet sur
   le bureau, et c'est ce qui la rend sure a modifier.

   CE QU'ELLE CORRIGE. Jusqu'ici la version telephone etait la version bureau
   avec les blocs empiles : meme densite, meme hierarchie, memes boutons de meme
   poids, sur un ecran qu'on tient d'une main en marchant. Il fallait defiler un
   ecran entier de chrome avant de voir un repas, chaque carte proposait quatre
   boutons a egalite, et le geste qu'on repete cinquante fois par liste de
   courses (cocher) etait le plus petit element de son ecran.

   LES CINQ REGLES QUI FONT SYSTEME, et qui valent pour tout ecran ajoute apres
   celui-ci :

   1. UN SEUL GESTE PAR ELEMENT, et c'est le plus frequent. Toucher une carte
      repas ouvre la recette. Toucher une ligne d'article la coche. Rien d'autre
      n'est visible au meme niveau.
   2. LE « ··· » EST LA MEME GRAMMAIRE PARTOUT. Tout ce qui n'est pas le geste
      principal vit derriere lui, dans une feuille par le bas POSEE SUR L'OBJET
      CONCERNE, jamais en haut de l'ecran.
   3. CHAQUE ITEM DE FEUILLE DIT SA CONSEQUENCE, pas son nom technique. C'est ce
      qui permet d'agir sans demander confirmation.
   4. 44 px MINIMUM POUR TOUT CE QUI SE TOUCHE, sans exception. Quand un controle
      doit rester petit visuellement, on agrandit la CIBLE sans grossir le dessin.
   5. DEUX PORTEES, DEUX CONTROLES, ET ON NE LES MELANGE PAS. Le menu gouttes en
      haut a droite porte l'application et l'espace, identique sur tous les
      ecrans. Le « ··· » porte l'objet touche. La puce d'espace a gauche change
      de planning. Ce qui n'a aucune de ces trois portees (imprimer la semaine
      affichee) sort des menus et devient un bloc dans le contenu.

   Les couleurs viennent des jetons de `styles.css` (`--bg`, `--surface`,
   `--primary`, `--gold`...) et JAMAIS d'une valeur ecrite en dur : les deux
   ambiances (carnet, tournesol) doivent continuer de fonctionner toutes les
   deux, et une teinte recopiee ici cesserait de suivre celle qu'on change.

   Handoff : `Refontes/design_handoff_mobile`.
   =================================================================== */

@media (max-width: 600px) {

  /* ================= CHASSIS =================
     On garde le defilement de la PAGE, et non un `flex` a hauteur fixe avec une
     colonne qui defile a l'interieur comme dans les maquettes : tout l'existant
     en depend (`hautDePage`, les barres recollees, la remontee apres un
     changement d'ecran), et le resultat visuel est le meme avec
     `position: sticky`. Deux modeles de defilement dans la meme application
     seraient un bug a venir, pas une amelioration. */
  .app-wrap { padding: 0 0 calc(86px + env(safe-area-inset-bottom)); }
  /* LA GOUTTIERE VIT SUR `#view`, PAS SUR `.app-wrap`, et c'est ce qui permet
     aux deux modeles de cohabiter. Les quatre ecrans refaits pour le telephone
     ont besoin de TOUTE la largeur : leurs barres collantes, leurs en-tetes de
     rayon et leurs listes touchent les bords, et ils reposent leur propre marge
     a l'interieur. Les autres (historique, preferences, parametrage, etats
     vides) sont ecrits pour une colonne avec une marge : sans elle, leur texte
     colle aux bords de l'ecran.
     `.ph-plein` est posee par `render()` d'apres ce qui a REELLEMENT ete
     dessine, pas d'apres une liste d'onglets : un ecran refait qui retombe sur
     son etat vide garde ainsi sa marge, sans qu'on ait a y penser. */
  #view { padding: 0 12px; }
  #view.ph-plein { padding: 0; }
  /* Le bouton flottant occupe 76 a 128 px au-dessus du bord : sans ce
     supplement il recouvre le dernier bloc du flux, et sur le planning c'est
     le bloc d'impression, donc deux boutons devenus intouchables. Pose sur
     `body` par `phFabMaj()`, pour ne pas creuser un vide de 60 px en bas des
     ecrans qui n'ont pas de bouton flottant. */
  body.ph-fab-on .app-wrap { padding-bottom: calc(148px + env(safe-area-inset-bottom)); }

  /* La barre du haut reste a l'ecran : elle porte le nom du planning ouvert et
     le menu gouttes, c'est-a-dire OU L'ON EST et CE QU'ON PEUT FAIRE. Les deux
     questions se posent en cours de lecture, pas seulement en haut de page. */
  .topbar {
    position: sticky; top: 0; z-index: 40;
    padding: calc(4px + env(safe-area-inset-top)) 12px 8px;
    background: var(--bg);
  }
  /* LE MENU GOUTTES REPASSE AU-DESSUS DE SON PROPRE VOILE.
     ------------------------------------------------------------------
     `.gt` porte `z-index: 100`, mais il vit DANS la barre du haut, et rendre
     celle-ci collante avec un z-index en a fait un CONTEXTE D'EMPILEMENT : le
     100 des gouttes n'a plus de sens que la-dedans, et la barre entiere est
     plafonnee a 40 dans la page. Son voile (`.gt-scrim`, z-index 95) passait
     donc PAR-DESSUS les gouttes, qui se retrouvaient floutees par ce qu'elles
     avaient ouvert, et le bouton flottant (45) leur passait devant aussi.
     La barre ne monte que pendant l'ouverture : le reste du temps elle reste a
     40, sous les modales et sous les feuilles. */
  body.gt-ouvert .topbar { z-index: 96; }

  /* ET LE BOUTON FLOTTANT S'EFFACE PENDANT CE TEMPS.
     ------------------------------------------------------------------
     Mesure du 22 septembre 2026, menu ouvert : voile a 95, bouton a 45, et
     pourtant c'est le bouton qui recevait le clic. Plutot que de courir apres
     un contexte d'empilement qui se reformera au prochain changement de mise
     en page, on retire le bouton : un menu ouvert est une question posee, et
     rien d'autre ne doit y repondre. Le geste est de toute facon le bon, le
     bouton n'a aucune raison de rester vif sous un voile. */
  body.gt-ouvert .ph-fab { opacity: 0; pointer-events: none; transform: scale(.9); }
  /* Sans ce filet, la barre et le contenu qui passe dessous sont de la meme
     creme : rien ne dit que l'un glisse sous l'autre. Il n'apparait qu'une fois
     qu'on a commence a defiler, sinon il souligne un titre pour rien. */
  .topbar::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
    background: var(--line); opacity: 0; transition: opacity .2s ease;
  }
  body.ph-defile .topbar::after { opacity: 1; }

  /* Les titres de page ne sont pas MASQUES sur les ecrans refaits : ils ne sont
     pas EMIS (cf. `renderAccueil`, `renderCoursesView`, `renderFavoris`,
     `renderData`). Une regle qui cache du markup produit pour rien laisse deux
     verites dans le code, et c'est la feuille de style qui perd toujours. */

  /* ================= BARRE D'ONGLETS =================
     CINQ onglets, pas six. Android recommande trois a cinq destinations, mais la
     vraie raison est qu'une barre permanente ne doit porter que ce qu'on ouvre
     souvent : le sixieme ecran se replie ailleurs.

     C'EST « HISTORIQUE » QUI SE REPLIE, ET PAS « PREFERENCES ». L'inverse a tenu
     du 18 au 22 septembre 2026, et c'etait le mauvais arbitrage : Preferences
     change ce que Popotam COMPOSE (gouts, aliments exclus, budget, nombre de
     personnes), donc on y retourne des qu'un menu ne convient pas ; Historique
     ne fait que LISTER des plats deja faits, on le consulte par curiosite.
     Replier l'ecran qui agit pour garder celui qui raconte revenait a ranger
     l'outil et exposer le souvenir.

     Historique se rejoint par le menu gouttes, ou il est la premiere goutte :
     jamais rognee par le plafond de barreaux, puisque c'est son seul chemin. */
  .tabs {
    grid-template-columns: repeat(5, 1fr);
    gap: 0; padding: 5px 4px calc(6px + env(safe-area-inset-bottom));
    background: var(--surface);
  }
  #tab-historique { display: none; }
  .tab {
    flex-direction: column; gap: 2px; padding: 3px 0 0;
    font-size: 10.5px; line-height: 1.15; border-radius: 12px;
  }
  .tab:hover { background: none; }
  /* L'ACTIF PORTE UNE PASTILLE, IL NE DEVIENT PAS UN PAVE ORANGE. Un onglet
     plein sur toute sa surface, repete en bas de chaque ecran, pese autant que
     le bouton principal du contenu : sur un telephone c'est alors la chose la
     plus voyante de l'ecran, et elle ne fait rien d'autre que dire ou l'on est.
     La pastille derriere l'icone le dit aussi bien. */
  .tab.active { background: none; box-shadow: none; color: var(--primary-ink); }
  .tab-ib {
    width: 34px; height: 30px; border-radius: var(--pill);
    display: grid; place-items: center;
    transition: background .22s cubic-bezier(.3, 1.5, .4, 1);
  }
  .tab.active .tab-ib { background: var(--primary-bg); }
  .tab span:not(.tab-badge) { text-align: center; }
  /* LA PASTILLE DU PANIER NE SORT PLUS DE L'ECRAN. A `margin-right: -26px` elle
     se posait au-dela du bord droit de son onglet, et sur le dernier onglet de
     la rangee la barre elle-meme la rognait. Elle revient sur l'icone, bordee de
     la couleur de la barre pour se detacher du dessin. */
  .tab .tab-badge {
    position: absolute; top: 0; right: 50%; margin-right: -21px;
    min-width: 18px; height: 18px; padding: 0 5px;
    display: grid; place-items: center;
    background: var(--primary); color: #fff;
    font-size: 10.5px; line-height: 1;
    border: 2px solid var(--surface);
  }
  .tab.active .tab-badge { background: var(--primary); color: #fff; }

  /* ================= LE BOUTON FLOTTANT =================
     Au-dessus de la barre d'onglets, du cote du pouce. Il ne porte QUE la
     generation : c'est la fonction qui fait l'application, et la seule qui
     merite d'etre atteignable sans rien viser. */
  .ph-fab {
    position: fixed; right: 14px; z-index: 45;
    bottom: calc(76px + env(safe-area-inset-bottom));
    display: flex; align-items: center; gap: 9px;
    /* 8 px a gauche : c'est le disque de la frimousse qui tient la marge de ce
       cote, et 20 px l'auraient decolle du bord. */
    min-height: 54px; padding: 0 20px 0 8px;
    border: 0; border-radius: var(--pill);
    background: var(--primary); color: #fff; cursor: pointer;
    font-family: var(--font-display); font-weight: 800; font-size: 15px;
    box-shadow: 0 10px 24px -8px color-mix(in srgb, var(--primary) 75%, transparent);
    transition: transform .22s cubic-bezier(.3, 1.5, .4, 1), opacity .2s ease;
  }
  .ph-fab[hidden] { display: none; }
  /* Sur les courses, un pictogramme de partage a la place de la frimousse : il n'y a
     plus de disque pour tenir la marge de gauche. */
  .ph-fab.ph-fab-envoi { padding: 0 20px 0 18px; }
  .ph-fab:active { transform: scale(.95); }
  /* LA FRIMOUSSE, DANS SON DISQUE BLANC. C'est Popotam lui-meme qui porte le
     bouton, pas un pictogramme : la generation est la fonction qui FAIT
     l'application. Le SVG est le corps entier (`popotam()`), cadre sur la tete
     par la mise a l'echelle et le recentrage, comme dans la maquette : la toque
     deborde legerement du disque, et c'est voulu.
     IL NE S'EFFACE PAS AU DEFILEMENT. Il l'a fait un moment, pour ne pas se
     poser sur le dernier article lu ; mais un bouton qui part quand on descend
     est un bouton qu'il faut aller rechercher en remontant, et c'est le seul de
     l'ecran. Le flux lui reserve sa place en bas (`body.ph-fab-on`), donc il ne
     recouvre rien de ce qui compte. */
  .ph-fab-pop {
    width: 38px; height: 38px; flex: none; border-radius: 50%;
    background: #fff; overflow: hidden; position: relative;
  }
  .ph-fab-pop svg {
    width: 38px; height: 38px; position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -44%) scale(1.5); transform-origin: 50% 38%;
  }

  /* ================= LA FEUILLE PAR LE BAS =================
     Elle remplace, sur telephone, les trois boutons secondaires de chaque carte
     repas et les deux de chaque article de courses. Posee par le bas, donc
     atteignable au pouce, et chaque ligne dit sa CONSEQUENCE. */
  .ph-scrim {
    position: fixed; inset: 0; z-index: 400;
    background: rgba(40, 25, 12, .42);
    opacity: 0; transition: opacity .26s ease;
  }
  .ph-scrim[hidden] { display: none; }
  .ph-scrim.is-on { opacity: 1; }
  .ph-sheet {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 401;
    background: var(--surface);
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    padding: 8px 0 calc(12px + env(safe-area-inset-bottom));
    max-height: 82vh; overflow-y: auto; overscroll-behavior: contain;
    transform: translateY(110%);
    transition: transform .34s cubic-bezier(.22, 1, .3, 1);
    box-shadow: 0 -12px 40px -14px rgba(60, 35, 10, .5);
  }
  .ph-sheet[hidden] { display: none; }
  .ph-sheet.is-on { transform: translateY(0); }
  .ph-grab { display: block; width: 38px; height: 4px; border-radius: 2px; background: var(--line); margin: 2px auto 10px; }
  .ph-sh { padding: 0 20px 12px; }
  .ph-sh b { display: block; font-family: var(--font-display); font-weight: 800; font-size: 18px; color: var(--ink); line-height: 1.25; }
  .ph-sh s { display: block; text-decoration: none; font-size: 13px; color: var(--muted); margin-top: 3px; line-height: 1.4; }
  .ph-items { padding: 4px 8px 0; }
  .ph-item {
    display: flex; align-items: center; gap: 14px; width: 100%;
    border: 0; background: none; font: inherit; cursor: pointer;
    padding: 12px; border-radius: var(--radius); text-align: left;
    min-height: 56px; transition: background .16s;
  }
  .ph-item:active { background: var(--surface-2); }
  .ph-item .ph-ib {
    width: 38px; height: 38px; flex: none; border-radius: 12px;
    display: grid; place-items: center;
    background: var(--surface-2); color: var(--ink-soft);
  }
  .ph-item .ph-ib.g { background: var(--green-bg); color: var(--green); }
  .ph-item .ph-ib.o { background: var(--primary-bg); color: var(--primary-ink); }
  .ph-item .ph-ib.s { background: var(--gold-bg); color: var(--gold-ink); }
  .ph-item .ph-tx { flex: 1; min-width: 0; }
  .ph-item .ph-tx b { display: block; font-family: var(--font-display); font-weight: 700; font-size: 15px; color: var(--ink); line-height: 1.25; }
  .ph-item .ph-tx s { display: block; text-decoration: none; font-size: 12.5px; color: var(--muted); margin-top: 1px; line-height: 1.35; }
  .ph-item.est-danger .ph-ib { background: var(--primary-bg); color: var(--danger, #C2410C); }
  .ph-item.est-danger .ph-tx b { color: var(--danger, #C2410C); }
  /* Un item indisponible reste LISIBLE et dit pourquoi dans son sous-titre : le
     retirer ferait croire que la fonction n'existe pas. */
  .ph-item[disabled] { cursor: default; opacity: .5; }

  /* Le « ··· » d'un objet. 44 px de cible pour trois points de 3 px. */
  .ph-more {
    flex: none; width: 44px; height: 44px;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--surface); color: var(--ink-soft); cursor: pointer;
    display: grid; place-items: center; transition: background .16s;
  }
  .ph-more:active { background: var(--surface-2); }
  .ph-more:focus-visible { outline: none; box-shadow: var(--ring); }

  /* ================= L'INTERTITRE DE SECTION =================
     Plus de numeros 1-2-3 ni de sous-titres editoriaux : c'etait une page de
     documentation, pas un ecran d'application. */
  .ph-st {
    font-family: var(--font-display); font-weight: 700; font-size: 11.5px;
    letter-spacing: .13em; text-transform: uppercase;
    color: var(--muted); padding: 10px 4px 0; margin: 0;
  }

  /* ================= LE BLOC DE FIN DE FLUX =================
     Ni carte repas, ni ligne de liste, ni entree de menu : un objet a part.
     Fond creme quand les listes sont blanches, mot manuscrit, boutons nommes.
     Il se lit comme un terminus, pas comme une entree de plus a parcourir.
     C'est la qu'atterrit ce qui ne porte ni sur l'application (le menu gouttes)
     ni sur un objet (le « ··· ») mais sur LA SEMAINE AFFICHEE : imprimer. */
  .ph-paper {
    margin: 14px 12px 0; padding: 15px 16px 16px;
    background: var(--surface-2); border-radius: var(--radius-xl);
    box-shadow: inset 0 0 0 1px var(--line);
  }
  .ph-paper .ph-p-top { display: flex; gap: 13px; align-items: center; margin-bottom: 13px; }
  /* `popotamFace()` porte deja un viewBox serre sur la tete : il n'y a rien a
     recadrer, et la mise a l'echelle heritee du handoff (pensee pour un autre
     dessin) la faisait deborder de 22 px dans les quatre directions. */
  .ph-paper .ph-p-face {
    width: 52px; height: 52px; flex: none; border-radius: 16px;
    background: var(--surface); overflow: hidden;
    display: grid; place-items: center;
  }
  .ph-paper .ph-p-face svg { width: 46px; height: 46px; display: block; }
  .ph-paper .ph-p-tx { min-width: 0; }
  .ph-paper .ph-p-tx i {
    display: block; font-style: normal; font-family: "Caveat", var(--font-body), cursive;
    font-weight: 700; font-size: 16px; color: var(--primary-ink); line-height: 1; margin-bottom: 2px;
  }
  .ph-paper .ph-p-tx b { display: block; font-family: var(--font-display); font-weight: 800; font-size: 16.5px; color: var(--ink); line-height: 1.2; }
  .ph-paper .ph-p-tx s { display: block; text-decoration: none; font-size: 12.5px; color: var(--ink-soft); margin-top: 3px; line-height: 1.4; }
  .ph-paper .ph-p-go { display: flex; gap: 9px; }
  .ph-paper .ph-p-go button {
    flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: 46px; border-radius: var(--radius); cursor: pointer;
    font-family: var(--font-display); font-weight: 800; font-size: 14px;
    transition: transform .18s cubic-bezier(.3, 1.5, .4, 1);
  }
  .ph-paper .ph-p-go button:active { transform: scale(.97); }
  .ph-paper .ph-p-go .a { border: 0; background: var(--ink); color: var(--bg); }
  .ph-paper .ph-p-go .b { border: 1px solid var(--line); background: var(--surface); color: var(--ink); }
}

@media (max-width: 600px) {

  /* ================= LE RUBAN DES JOURS =================
     Il remplace sept blocs : le sur-titre, le titre, la date, les deux boutons
     d'en-tete, la bascule des semaines et « Planifier le mois ». Environ mille
     pixels de chrome avant le premier repas, contre quatre-vingt-dix.

     Il est COLLANT sous la barre du haut : « quel jour je regarde » est la
     question qu'on se repose en parcourant la suite de la semaine. `top` vaut
     la hauteur de la barre du haut, encoche comprise ; les deux valeurs doivent
     rester d'accord (cf. `.topbar` plus haut : 4 + 8 de rembourrage autour d'un
     declencheur de 46 px). */
  /* `--ph-top` est la hauteur reelle de la barre du haut, mesuree a chaque
     rendu par `phHaut()` (app.js). Ecrite en dur elle derivait au premier
     changement du selecteur d'espaces, et le ruban se glissait SOUS la barre
     sans que rien ne le signale : 58 px ecrits pour 70 px mesures, mesure du
     22 septembre 2026. Le repli couvre le cas ou le JS n'a pas encore tourne. */
  .ph-week {
    position: sticky; top: var(--ph-top, 70px); z-index: 30;
    background: var(--bg); padding: 2px 0 8px;
    box-shadow: 0 1px 0 var(--line);
  }
  /* Les deux commandes aux EXTREMITES, le nom de la semaine au milieu : sinon
     la place du bouton depend de la longueur de la date, et le « + » se lit
     comme s'il appartenait au texte. */
  .ph-whead { display: flex; align-items: center; gap: 4px; padding: 0 8px 2px; }
  .ph-whead b {
    flex: 1; min-width: 0;
    font-family: var(--font-display); font-weight: 700; font-size: 12.5px;
    color: var(--ink-soft); text-align: center;
  }
  .ph-nav {
    flex: none; width: 44px; height: 44px; border: 0; border-radius: 50%;
    background: none; cursor: pointer; display: grid; place-items: center;
    color: var(--muted); padding: 0;
  }
  .ph-nav:active { background: var(--surface-2); }
  .ph-nav:focus-visible { outline: none; box-shadow: var(--ring); }
  /* Au bout de la chaine, la case reste VIDE : les fleches ne parcourent que
     les semaines qui existent, et completer le mois est une LIGNE NOMMEE dans
     la feuille du bouton flottant. Un « + » muet a cette place serait le
     defaut qu'on a deja corrige une fois : son sens n'existerait que pour une
     souris, et 85 % du trafic est sur un telephone. */
  .ph-nav-vide { pointer-events: none; }
  .ph-chev-g { transform: rotate(180deg); }

  .ph-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; padding: 0 6px; }
  .ph-day {
    border: 0; background: none; cursor: pointer; padding: 3px 0 4px;
    border-radius: 14px; font: inherit;
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    position: relative; transition: background .18s;
    /* 44 px de cible pour un chiffre de 16 : sept jours sur 390 px font
       55 px de large chacun, la hauteur est ce qui restait a garantir. */
    min-height: 44px;
  }
  .ph-day s {
    text-decoration: none; font-size: 10px; font-weight: 700; color: var(--muted);
    text-transform: uppercase; letter-spacing: .04em;
  }
  .ph-day b {
    font-family: var(--font-display); font-weight: 800; font-size: 16px; color: var(--ink);
    line-height: 1; width: 30px; height: 30px; border-radius: 50%;
    display: grid; place-items: center;
    transition: background .2s cubic-bezier(.3, 1.5, .4, 1), color .2s, transform .2s cubic-bezier(.3, 1.5, .4, 1);
  }
  /* LES PASTILLES SONT LE VRAI APPORT DU RUBAN : elles rendent la semaine
     lisible d'un coup d'oeil, ce que la liste ne faisait pas. Or pour ce qui est
     prevu, vert pour ce qui est fait, gris pour un repas annule (ni l'un ni
     l'autre : il est ecarte). */
  .ph-day .ph-pips { display: flex; gap: 3px; height: 5px; align-items: center; }
  .ph-pip { display: block; width: 5px; height: 5px; border-radius: 50%; background: var(--line); }
  .ph-pip.est-prevu { background: var(--gold); }
  .ph-pip.est-fait { background: var(--green); }
  /* Aujourd'hui porte un anneau, le jour REGARDE porte un disque plein : deux
     informations differentes, et elles se superposent souvent. */
  .ph-day.est-auj b { box-shadow: inset 0 0 0 2px var(--primary-bg); }
  .ph-day.is-on b { background: var(--primary); color: #fff; transform: scale(1.06); }
  .ph-day.is-on s { color: var(--primary-ink); }
  .ph-day.est-vide b { color: var(--muted); }

  /* ================= LE FLUX DU PLANNING ================= */
  .ph-feed { padding: 12px 12px 6px; display: flex; flex-direction: column; gap: 12px; }
  /* Sans ceci les cartes sont ECRASEES a 0 px de haut : `overflow: hidden` sur
     une carte annule son `min-height: auto` d'element flex, et une colonne qui
     deborde la reduit a rien. Ne pas retirer. */
  .ph-feed > * { flex: none; }
  .ph-dhead { display: flex; align-items: baseline; gap: 8px; padding: 2px 2px 0; }
  .ph-dhead h2 { font-family: var(--font-display); font-weight: 800; font-size: 22px; color: var(--ink); margin: 0; }
  .ph-dhead span { font-size: 13px; color: var(--muted); }

  /* ---------- La carte repas ----------
     UNE SEULE ACTION VISIBLE, et le corps entier ouvre la recette. Avant :
     quatre boutons de meme taille, donc aucun n'etait l'action principale, et
     « Voir la recette » etait noye parmi eux. */
  .ph-meal {
    position: relative; background: var(--surface); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm), 0 10px 24px -18px rgba(150, 90, 30, .5);
    overflow: hidden; transition: opacity .3s ease;
  }
  .ph-m-body {
    display: block; width: 100%; border: 0; background: none; text-align: left;
    font: inherit; cursor: pointer; padding: 12px 14px 10px;
    transition: background .16s;
  }
  .ph-m-body:active { background: var(--surface-2); }
  .ph-m-body:focus-visible { outline: none; box-shadow: var(--ring); }
  .ph-m-r1 { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
  .ph-slot {
    display: inline-flex; align-items: center; gap: 5px;
    border-radius: var(--pill); padding: 4px 10px 4px 8px;
    font-family: var(--font-display); font-weight: 800; font-size: 10.5px;
    letter-spacing: .08em; text-transform: uppercase;
  }
  .ph-slot.midi { background: var(--gold-bg); color: var(--gold-ink); }
  .ph-slot.soir { background: var(--primary-bg); color: var(--primary-ink); }
  .ph-slot.plaisir { background: var(--plaisir-bg); color: var(--plaisir); }
  .ph-slot svg { flex: none; }
  .ph-m-body h3 {
    font-family: var(--font-display); font-weight: 800; font-size: 17px;
    line-height: 1.24; color: var(--ink); margin: 0; padding-right: 38px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .ph-m-meta {
    display: flex; align-items: center; gap: 12px; margin-top: 7px;
    font-size: 12.5px; color: var(--muted); font-weight: 600;
  }
  .ph-m-meta > span { display: inline-flex; align-items: center; gap: 4px; }
  .ph-m-meta svg { flex: none; }
  /* L'etoile garde 44 px de cible pour un dessin de 19 : elle est posee sur le
     coin, la ou l'oeil la trouve sans la chercher. */
  /* L'ETOILE EST NUE SUR LA CARTE. Ailleurs elle vit dans un disque creme
     borde ; ici le handoff la pose seule dans le coin, et c'est juste : la carte
     porte deja un cadre, un second cercle a l'interieur fait deux objets la ou
     il n'y a qu'un signe.
     Sa CIBLE passe a 44 px alors que le dessin en fait 20. Elle mesurait 30 px,
     dessin compris, soit sous le minimum tactile du depot, et personne ne
     l'avait releve parce qu'on la touche rarement. */
  .ph-meal .fav {
    position: absolute; top: 2px; right: 2px; z-index: 2;
    width: 44px; height: 44px;
    background: none; border: 0; box-shadow: none;
  }
  .ph-meal .fav .star { width: 20px; height: 20px; }
  .ph-meal .fav .glow { inset: -6px; }
  .ph-meal .fav:hover { background: none; border: 0; transform: none; }
  /* Gardee meme allumee : c'est le remplissage dore de l'etoile qui dit
     « dans mon livre », le disque n'y ajoutait rien. */
  .ph-meal .fav.is-on { background: none; border: 0; box-shadow: none; }

  .ph-m-foot { display: flex; gap: 8px; padding: 0 12px 12px; align-items: center; }
  /* LA RECETTE EST L'ACTION PRINCIPALE, donc elle prend la largeur et la couleur
     de la marque. Orange plein et non pale : c'est le seul bouton de la carte
     qui emmene ailleurs. */
  .ph-recette {
    flex: 1; min-width: 0;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 44px; padding: 0 12px;
    border: 0; border-radius: var(--radius);
    background: var(--primary); color: #fff; cursor: pointer;
    font-family: var(--font-display); font-weight: 800; font-size: 14.5px;
    transition: transform .18s cubic-bezier(.3, 1.5, .4, 1), filter .18s;
  }
  .ph-recette svg { flex: none; }
  .ph-recette:active { transform: scale(.97); }
  .ph-recette:focus-visible { outline: none; box-shadow: var(--ring); }
  .ph-done {
    flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: 44px; border: 0; border-radius: var(--radius);
    background: var(--green-bg); color: var(--green); cursor: pointer;
    font-family: var(--font-display); font-weight: 800; font-size: 14.5px;
    transition: transform .18s cubic-bezier(.3, 1.5, .4, 1), background .18s;
  }
  .ph-done svg { flex: none; }
  .ph-done:active { transform: scale(.97); }
  .ph-done.is-on { background: var(--green); color: #fff; }
  /* Une semaine pas encore vecue n'a rien a marquer : le geste qui PREPARE
     (ouvrir la recette) prend la place, et il est orange parce qu'il fait
     travailler Popotam. */
  /* Gardee pour le LIVRE : sur une fiche de favori, « Voir la recette » est le
     seul bouton, il occupe la barre et se teinte en orange pale. La carte repas,
     elle, a son propre `.ph-recette` en orange plein depuis le 23 septembre. */
  .ph-done.est-prep { background: var(--primary-bg); color: var(--primary-ink); }
  /* « Marquer realise » se reduit a un carre : il reste a portee de pouce sans
     conduire la carte. Les 44 px sont conserves, c'est le LIBELLE qui part, pas
     la cible ; `aria-label` le porte pour qui ne voit pas l'icone. */
  .ph-done.est-carre { flex: none; width: 44px; padding: 0; gap: 0; }
  .ph-meal.est-fait { opacity: .66; }
  .ph-meal.est-fait .ph-m-body h3 { text-decoration: line-through; text-decoration-color: var(--muted); }
  .ph-meal.est-annule { opacity: .6; }
  .ph-meal.est-annule .ph-m-body h3 { text-decoration: line-through; text-decoration-color: var(--muted); }

  /* ---------- La suite de la semaine, en lignes ----------
     Cinq jours a l'ecran au lieu de deux repas. */
  .ph-rest { margin-top: 4px; }
  .ph-rh {
    font-family: var(--font-display); font-weight: 700; font-size: 11.5px;
    letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
    padding: 0 4px 8px;
  }
  .ph-rday { margin-bottom: 10px; }
  .ph-rdt { display: flex; align-items: baseline; gap: 7px; padding: 0 4px 6px; }
  .ph-rdt b { font-family: var(--font-display); font-weight: 800; font-size: 14px; color: var(--ink); }
  .ph-rdt s { text-decoration: none; font-size: 11.5px; color: var(--muted); }
  .ph-rows { background: var(--surface); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm); }
  /* LA RANGEE N'EST PLUS UN BOUTON, elle en contient trois : la zone qui ouvre
     la recette, le carre de recette, et le « ··· ». Un bouton dans un bouton
     n'est pas du HTML valide et le navigateur casse le plus interieur. */
  .ph-rrow {
    display: flex; align-items: center; gap: 6px; width: 100%;
    padding: 5px 6px 5px 12px; min-height: 56px;
  }
  .ph-rrow + .ph-rrow { box-shadow: inset 0 1px 0 var(--line); }
  .ph-rmain {
    flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
    border: 0; background: none; font: inherit; cursor: pointer;
    padding: 4px 0; text-align: left; min-height: 44px;
    transition: opacity .16s;
  }
  .ph-rmain:active { opacity: .55; }
  .ph-rmain:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius); }
  /* LE CARRE DE RECETTE, ET SA COULEUR EST L'INFORMATION : orange tant qu'il
     faut l'ecrire (un geste qui fait travailler Popotam et prend quelques
     secondes), vert quand elle est la et s'ouvre sans attendre. On sait avant de
     toucher si on va lire ou faire ecrire.
     La CIBLE fait 44 px, le dessin 38 : on agrandit la zone sans grossir le
     carre, comme partout ailleurs. */
  .ph-rrec {
    position: relative; flex: none; width: 44px; height: 44px;
    border: 0; background: none; padding: 0; cursor: pointer;
    display: grid; place-items: center; color: var(--primary-ink);
  }
  .ph-rrec::before {
    content: ""; position: absolute; left: 3px; top: 3px; width: 38px; height: 38px;
    border-radius: 12px; background: var(--primary-bg); transition: background .18s;
  }
  .ph-rrec svg { position: relative; z-index: 1; }
  .ph-rrec.est-prete { color: var(--green); }
  .ph-rrec.est-prete::before { background: var(--green-bg); }
  .ph-rrec:active { transform: scale(.94); }
  .ph-rrec:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 12px; }
  /* Sur une rangee, le « ··· » est nu : la carte lui donne un cadre parce
     qu'il y voisine deux boutons pleins, ici il en suivrait un seul et ferait
     deux cadres pour deux gestes de rang different. */
  .ph-more-nu { border: 0; background: none; }
  .ph-more-nu:active { background: none; opacity: .55; }
  .ph-rt { flex: none; width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center; }
  .ph-rt.midi { background: var(--gold-bg); color: var(--gold-ink); }
  .ph-rt.soir { background: var(--primary-bg); color: var(--primary-ink); }
  .ph-rt.plaisir { background: var(--plaisir-bg); color: var(--plaisir); }
  .ph-rx { flex: 1; min-width: 0; }
  .ph-rx b {
    display: block; font-weight: 700; font-size: 14px; color: var(--ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.3;
  }
  .ph-rx s { text-decoration: none; font-size: 11.5px; color: var(--muted); }
  .ph-rrow.est-fait .ph-rx b, .ph-rrow.est-annule .ph-rx b { color: var(--muted); text-decoration: line-through; }

  /* LES BANDEAUX RENTRENT DANS LA GOUTTIERE. Ils gardent leur dessin, mais ils
     etaient ecrits pour une colonne de 1120 px qui portait sa propre marge :
     sur un ecran refait, `#view` n'en a plus, et ils arrivaient colles aux deux
     bords. Les noms sont ceux des racines reelles (`.actu`, `.reminder-card`,
     `.mois-wait`) : les deviner depuis la classe d'un enfant ne pose rien du
     tout, et en silence.
     `.demo-bar` et `.offline-bar` vivent HORS de `#view`, donc hors de la
     gouttiere quel que soit l'ecran : leur regle n'est pas conditionnee. */
  .demo-bar, .offline-bar { margin-left: 12px; margin-right: 12px; }
  .ph-plein .actu, .ph-plein .reminder-card, .ph-plein .mois-wait,
  .ph-plein .restart-line, .ph-plein .tip-bar,
  .ph-plein .soutien-carte, .ph-plein .ai-wait-bloc {
    margin-left: 12px; margin-right: 12px;
    /* LE HAUT AUSSI, et c'est ce qui manquait. Sur un ecran large ces bandeaux
       suivent un titre de page qui porte sa marge basse ; sur telephone le
       titre n'existe plus, et ils se retrouvaient colles au ruban des jours,
       sans respiration entre les dates et le premier message. */
    margin-top: 14px;
  }
}

@media (max-width: 600px) {

  /* ================= LA LISTE DE COURSES =================
     Trois barres se collent en haut, dans cet ordre : la barre d'application,
     l'avancement, les puces de rayon. Les en-tetes de rayon se collent sous les
     trois, a `--ph-barres`, mesure par `phBarres()` : deux de ces barres sont
     conditionnelles (la bascule des semaines, les puces), donc leur hauteur
     totale n'est pas une valeur qu'on puisse ecrire ici. */

  /* La bascule des semaines garde sa place : elle NOMME ce qu'on regarde, et
     elle n'apparait qu'a partir de deux semaines. Elle defile avec le contenu :
     on la touche au debut d'une seance de courses, pas au milieu. */
  .courses-week-toggle { padding: 10px 12px 4px; margin: 0; overflow-x: auto; scrollbar-width: none; }
  .courses-week-toggle::-webkit-scrollbar { display: none; }

  /* ---------- l'avancement ---------- */
  .ph-prog {
    position: sticky; top: var(--ph-top, 70px); z-index: 30;
    background: var(--bg); padding: 4px 12px 8px;
  }
  /* LE RAIL DOIT SE VOIR A 0 %, et c'est la qu'on ouvre l'ecran. La teinte de
     fond de l'application sur elle-meme donne un contraste de 1,07:1, donc rien.
     D'ou une teinte plus soutenue, plus un filet interieur. */
  .ph-bar {
    height: 6px; border-radius: var(--pill); background: var(--bg-tint);
    overflow: hidden; margin-bottom: 7px;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gold) 34%, transparent);
  }
  .ph-bar i {
    display: block; height: 100%; border-radius: var(--pill); background: var(--green);
    transition: width .45s cubic-bezier(.2, .9, .28, 1);
  }
  .ph-prow { display: flex; align-items: center; gap: 8px; }
  .ph-cnt { flex: 1; min-width: 0; font-family: var(--font-display); font-weight: 800; font-size: 13.5px; color: var(--ink); }
  .ph-cnt s { text-decoration: none; color: var(--muted); font-weight: 700; }
  .ph-budget {
    flex: none; display: inline-flex; align-items: center; gap: 6px;
    border: 0; border-radius: var(--pill); min-height: 44px; padding: 0 14px;
    background: var(--green-bg); color: var(--green); cursor: pointer;
    font-family: var(--font-display); font-weight: 800; font-size: 13.5px; white-space: nowrap;
  }
  .ph-budget svg { flex: none; }
  .ph-budget:active { background: color-mix(in srgb, var(--green) 18%, var(--surface)); }
  .ph-budget:focus-visible { outline: none; box-shadow: var(--ring); }

  /* ---------- les puces de rayon ----------
     L'outil d'orientation : sauter au rayon devant lequel on se trouve, sans
     traverser vingt-et-un fruits. Un rayon fini passe au vert et se coche, donc
     la barre dit aussi ce qu'il reste. */
  /* ================= LA RANGÉE DE PÉRIODE =================
     ELLE S'APPELLE `.ph-cal` ET NON `.ph-per`, ET CE N'EST PAS UN GOÛT.
     `.ph-per` existait déjà, plus bas dans ce fichier : c'est la rangée de
     périodes des STATISTIQUES, avec un `.ph-per button` qui pose un rayon en
     pastille, 44 px de haut et un `overflow-x: auto`. Écrite d'abord sous ce
     nom, la rangée de courses héritait donc d'un `display: flex` qui écrasait sa
     grille, d'une marge et d'une ombre qu'elle n'avait pas demandées, et d'un
     défilement horizontal qui change la hauteur mesurée par `phBarres()`. Elle
     ne ressemblait plus du tout au handoff, et les barres collantes en dessous
     s'en trouvaient décalées. `src/test/mobile.test.ts` refuse désormais qu'un
     nom de classe soit déclaré deux fois dans cette feuille.
     Handoff « courses » du 22 septembre 2026. Elle remplace trois grosses
     pastilles qui passaient sur deux lignes : une centaine de pixels pour un
     choix, et aucune place pour les semaines trois et quatre.

     Une case par semaine, puis le mois, côte à côte comme une rangée de
     calendrier : toutes les options visibles d'un coup, rien à faire défiler.
     Les colonnes sont posées en ligne par le rendu (`repeat(N,1fr) 1.08fr`),
     parce que N dépend du planning : écrite à quatre ici, une personne qui n'a
     que deux semaines verrait deux trous à droite.

     62 px de haut : au-dessus des 44 px minimum, et il en faut, la case empile
     trois informations. */
  /* Centree, et c'est ce qui rend la rangee juste a une ou deux semaines : les
     colonnes portent une largeur maximale (posee au rendu, elle depend du nombre
     de semaines), donc la rangee est souvent plus courte que la place. Etiree,
     elle donnait des cases de 120 px qui ne ressemblaient plus au handoff. */
  .ph-cal { display: grid; gap: 5px; margin: 0 12px 10px; justify-content: center; }
  .ph-cal-c {
    position: relative; min-width: 0; min-height: 62px; padding: 5px 2px 6px;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 0; line-height: 1.1; cursor: pointer;
    background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
    transition: background .18s, border-color .18s, transform .12s;
  }
  .ph-cal-c:active { transform: scale(.95); }
  /* LES DATES SONT L'INFORMATION PRINCIPALE : on pense « la semaine du 6 », pas
     « dans deux semaines ». D'où leur taille, et le mois en second. */
  .ph-cal-c b {
    font-family: var(--font-display); font-weight: 800; font-size: 13.5px;
    color: var(--ink); white-space: nowrap;
  }
  .ph-cal-c s {
    text-decoration: none; font-size: 10px; font-weight: 600; color: var(--muted);
    white-space: nowrap; margin-top: 1px;
  }
  /* Le repère « aujourd'hui », de la main de Popotam. Les cases qui n'en ont pas
     portent une insécable : sans elle, la première aurait une ligne de plus et
     les dates ne s'aligneraient plus d'une case à l'autre. */
  .ph-cal-c s.ph-cal-tg {
    font-family: "Caveat", var(--font-body), cursive; font-weight: 700; font-size: 13.5px;
    color: var(--primary-ink); margin: 0 0 1px; line-height: 1;
  }
  /* Le compte dit ce qu'il y a derrière AVANT qu'on touche. */
  .ph-cal-c em {
    font-style: normal; margin-top: 4px; padding: 1px 7px; border-radius: var(--pill);
    font-family: var(--font-display); font-weight: 800; font-size: 10.5px;
    background: var(--surface-2); color: var(--ink-soft);
  }
  .ph-cal-c.is-on { background: var(--primary-bg); border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
  .ph-cal-c.is-on b { color: var(--primary-ink); }
  .ph-cal-c.is-on em { background: var(--primary); color: #fff; }
  /* EN VUE MOIS, LES SEMAINES S'ALLUMENT ENSEMBLE, en pâle. C'est ce qui explique
     la case « Mois » sans un mot : on VOIT que le mois, c'est elles réunies. Ne
     pas retirer cet état, il porte tout le sens de la rangée. */
  .ph-cal-c.est-dedans { background: var(--primary-bg); border-color: #F6C3AC; }
  .ph-cal-c.est-dedans em { background: #F9D2C0; color: var(--primary-ink); }
  /* La case mois est dessinée à part : ce n'est pas une semaine de plus, c'est
     une autre façon de regarder. Pointillé et fond crème le disent sans texte. */
  /* Le creme du handoff, pas le beige de `--bg-tint` : la case doit se distinguer
     du blanc des semaines en restant chaude, sinon elle se lit comme une case
     grisee, donc desactivee. Sa pastille repasse en blanc, faute de quoi elle
     disparaitrait dans son propre fond. */
  .ph-cal-m { background: var(--surface-2); border-style: dashed; border-color: var(--line); }
  .ph-cal-m em { background: var(--surface); }
  .ph-cal-m.is-on {
    background: var(--primary); border-color: var(--primary); border-style: solid; box-shadow: none;
  }
  .ph-cal-m.is-on b, .ph-cal-m.is-on s { color: #fff; }
  .ph-cal-m.is-on em { background: #fff; color: var(--primary-ink); }
  @media (prefers-reduced-motion: reduce) { .ph-cal-c:active { transform: none; } }

  .ph-aisles {
    position: sticky; top: var(--ph-sous-prog, 139px); z-index: 29;
    display: flex; gap: 7px; overflow-x: auto;
    padding: 0 12px 9px; background: var(--bg);
    box-shadow: 0 1px 0 var(--line); scrollbar-width: none;
  }
  .ph-aisles::-webkit-scrollbar { display: none; }
  .ph-achip {
    flex: none; display: inline-flex; align-items: center; gap: 7px;
    border: 1px solid var(--line); border-radius: var(--pill);
    background: var(--surface); cursor: pointer; min-height: 44px; padding: 0 14px;
    font: inherit; font-weight: 700; font-size: 13px; color: var(--ink-soft);
    white-space: nowrap; transition: background .18s, border-color .18s, color .18s;
  }
  .ph-achip svg { flex: none; color: var(--muted); }
  .ph-achip b { font-family: var(--font-display); font-weight: 800; font-size: 11.5px; color: var(--muted); }
  .ph-achip.est-fini { background: var(--green-bg); border-color: color-mix(in srgb, var(--green) 28%, var(--line)); color: var(--green); }
  .ph-achip.est-fini svg { color: var(--green); }
  .ph-achip:focus-visible { outline: none; box-shadow: var(--ring); }

  /* ---------- l'astuce, une ligne, une fois ----------
     Elle remplace quatre lignes repetees en haut d'un ecran qu'on ouvre
     cinquante fois par semaine. Elle dit ce que fait le « ··· », puis s'en va
     pour de bon. */
  .ph-hint {
    display: flex; align-items: center; gap: 9px;
    margin: 10px 12px 0; padding: 8px 6px 8px 12px;
    background: var(--gold-bg); border-radius: var(--radius);
    font-size: 12.5px; color: var(--ink-soft); line-height: 1.35;
  }
  .ph-hint > svg { flex: none; color: var(--gold-ink); }
  .ph-hint > div { flex: 1; min-width: 0; }
  /* L'icone est MONTREE dans la phrase, a cote de ce qu'elle fait : c'est ce qui
     remplace les libelles qu'on a retires des rangees. */
  .ph-hi { vertical-align: -2px; color: var(--ink); }
  .ph-hint button {
    flex: none; width: 44px; height: 44px; border: 0; border-radius: 50%;
    background: none; cursor: pointer; color: var(--gold-ink);
    display: grid; place-items: center;
  }

  /* ---------- l'en-tete de rayon, collant ---------- */
  .ph-rayon { margin-top: 2px; }
  .ph-ah {
    position: sticky; top: var(--ph-barres, 170px); z-index: 20;
    display: flex; align-items: center; gap: 10px;
    padding: 9px 12px 8px; background: var(--bg);
    box-shadow: 0 1px 0 var(--line);
  }
  .ph-ai {
    width: 32px; height: 32px; flex: none; border-radius: 10px;
    display: grid; place-items: center; background: var(--gold-bg); color: var(--gold-ink);
  }
  .ph-atx { flex: 1; min-width: 0; }
  .ph-atx b {
    display: block; font-family: var(--font-display); font-weight: 800; font-size: 15.5px;
    color: var(--ink); line-height: 1.2;
  }
  .ph-atx s { text-decoration: none; font-size: 12px; color: var(--muted); white-space: nowrap; }
  .ph-all {
    flex: none; min-height: 44px; border: 1px solid var(--line);
    border-radius: var(--pill); background: var(--surface); cursor: pointer;
    padding: 0 12px; font-family: var(--font-display); font-weight: 800; font-size: 12.5px;
    color: var(--ink-soft); display: inline-flex; align-items: center; gap: 5px;
  }
  .ph-all svg { flex: none; }
  .ph-all:active { background: var(--surface-2); }
  .ph-ah.est-fini .ph-ai { background: var(--green-bg); color: var(--green); }

  /* ---------- la rangee article ----------
     60 px, et TOUTE la rangee est la cible du geste qu'on repete cinquante fois.
     Avant : une carte de 230 px, ramenee a 123 px en juin, dont le geste
     principal etait le plus petit element de l'ecran. */
  .ph-items-l { background: var(--surface); }
  .ph-it {
    display: flex; align-items: center; gap: 11px; width: 100%;
    padding: 9px 6px 9px 12px; min-height: 60px;
    cursor: pointer; transition: background .16s, opacity .3s;
  }
  .ph-it + .ph-it { box-shadow: inset 0 1px 0 var(--line); }
  .ph-it:active { background: var(--surface-2); }
  .ph-it:focus-visible { outline: none; box-shadow: var(--ring); }
  .ph-box {
    flex: none; width: 25px; height: 25px; border-radius: 8px;
    border: 2px solid var(--line); display: grid; place-items: center;
    color: transparent; transition: background .22s cubic-bezier(.3, 1.5, .4, 1), border-color .22s;
  }
  .ph-itx { flex: 1; min-width: 0; }
  .ph-itx b {
    display: block; font-weight: 700; font-size: 15.5px; color: var(--ink); line-height: 1.25;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .ph-itx s { display: block; text-decoration: none; font-size: 12.5px; color: var(--muted); margin-top: 1px; }
  .ph-itx s em { font-style: normal; font-weight: 700; color: var(--ink-soft); }
  /* PRIS. L'article RESTE A SA PLACE, barre : on doit pouvoir se corriger sans
     le chercher, et l'ordre du rayon est un repere physique puisqu'on vient de
     le parcourir dans cet ordre. */
  .ph-it.is-on .ph-box { background: var(--green); border-color: var(--green); color: #fff; }
  .ph-it.is-on .ph-itx b { color: var(--muted); text-decoration: line-through; text-decoration-thickness: 1.5px; }
  .ph-it.is-on .ph-itx s { opacity: .7; }
  /* DEJA A LA MAISON : hors budget, hors decompte, mais GARDE en liste. Le
     supprimer serait une perte d'information : la semaine prochaine, Popotam
     doit toujours savoir que cette recette a besoin d'huile d'olive. */
  .ph-it.est-stock { opacity: .55; cursor: default; }
  .ph-it.est-stock .ph-box { border-style: dashed; }
  .ph-it.est-stock .ph-itx b { text-decoration: line-through; text-decoration-color: var(--muted); }

  /* ---------- le detail du budget, dans sa feuille ---------- */
  .ph-corps { padding: 0 12px 4px; }
  .ph-bud { display: flex; gap: 8px; }
  .ph-bud > div {
    flex: 1; min-width: 0; background: var(--surface-2); border-radius: var(--radius);
    padding: 11px 12px;
  }
  .ph-bud b { display: block; font-family: var(--font-display); font-weight: 800; font-size: 17px; color: var(--ink); line-height: 1.1; }
  .ph-bud s { display: block; text-decoration: none; font-size: 11.5px; font-weight: 700; color: var(--ink-soft); margin-top: 3px; }
  .ph-bud em { display: block; font-style: normal; font-size: 11px; color: var(--muted); margin-top: 2px; line-height: 1.3; }
  .ph-bud-n {
    display: flex; gap: 7px; align-items: flex-start;
    margin: 10px 2px 0; font-size: 12px; color: var(--muted); line-height: 1.45;
  }
  .ph-bud-n svg { flex: none; margin-top: 2px; }
}

@media (max-width: 600px) {

  /* ================= MON LIVRE DE RECETTES =================
     Un livre se consulte, il ne se defile pas. La recherche et les filtres sont
     donc ce qui ouvre l'ecran, et ils se collent en haut : au-dela d'une dizaine
     de fiches, c'est la seule facon de retrouver « le truc aux courgettes ».
     La recherche porte sur le titre ET les ingredients, parce que
     « qu'est-ce que je fais avec mes courgettes ? » est la vraie question qu'on
     pose a un livre de recettes. */
  .ph-find {
    position: sticky; top: var(--ph-top, 70px); z-index: 30;
    background: var(--bg); padding: 8px 12px 8px;
  }
  .ph-f {
    display: flex; align-items: center; gap: 9px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--pill); padding: 0 2px 0 14px; min-height: 46px;
  }
  .ph-f > svg { flex: none; color: var(--muted); }
  /* 16 px minimum : en dessous, iOS zoome la page en prenant le focus, et on se
     retrouve dans une liste de courses agrandie qu'il faut repincer. */
  .ph-f input {
    flex: 1; min-width: 0; border: 0; outline: none; background: none;
    font: inherit; font-size: 16px; color: var(--ink); padding: 0;
    -webkit-appearance: none; appearance: none;
  }
  .ph-f input::placeholder { color: var(--muted); }
  .ph-f input::-webkit-search-cancel-button { display: none; }
  .ph-clr {
    flex: none; width: 44px; height: 44px; border: 0; border-radius: 50%;
    background: none; cursor: pointer; display: grid; place-items: center; color: var(--muted);
  }

  .ph-fchips {
    position: sticky; top: var(--ph-sous-prog, 132px); z-index: 29;
    display: flex; gap: 7px; overflow-x: auto;
    padding: 0 12px 9px; background: var(--bg);
    box-shadow: 0 1px 0 var(--line); scrollbar-width: none;
  }
  .ph-fchips::-webkit-scrollbar { display: none; }
  /* Chaque filtre porte son COMPTE : on sait avant de toucher s'il y a quelque
     chose derriere, et le compte tient compte de la recherche en cours. */
  .ph-fchip {
    flex: none; display: inline-flex; align-items: center; gap: 6px;
    border: 1px solid var(--line); border-radius: var(--pill);
    background: var(--surface); cursor: pointer; min-height: 44px; padding: 0 14px;
    font: inherit; font-weight: 700; font-size: 13px; color: var(--ink-soft);
    white-space: nowrap; transition: background .18s, border-color .18s, color .18s;
  }
  .ph-fchip b { font-family: var(--font-display); font-weight: 800; font-size: 11.5px; color: var(--muted); }
  .ph-fchip.is-on { background: var(--primary-bg); border-color: color-mix(in srgb, var(--primary) 34%, var(--line)); color: var(--primary-ink); }
  .ph-fchip.is-on b { color: var(--primary-ink); }
  .ph-fchip:focus-visible { outline: none; box-shadow: var(--ring); }

  /* ---------- la fiche ----------
     Les ingredients ne sont plus deplies : en feuilletant on RECONNAIT une
     recette, on ne la cuisine pas. 630 px par fiche contre environ 160, donc
     cinq fiches a l'ecran au lieu d'une. Le detail vit dans la recette. */
  .fav-grid.ph-book { display: flex; flex-direction: column; gap: 12px; padding: 12px; margin: 0; }
  .fav-grid.ph-book > * { flex: none; }
  .ph-rec {
    position: relative; background: var(--surface); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm), 0 10px 24px -18px rgba(150, 90, 30, .5);
    overflow: hidden; padding: 0;
  }
  .ph-r-body {
    display: block; width: 100%; border: 0; background: none; text-align: left;
    font: inherit; cursor: pointer; padding: 12px 14px 10px; transition: background .16s;
  }
  .ph-r-body:active { background: var(--surface-2); }
  .ph-r-body:focus-visible { outline: none; box-shadow: var(--ring); }
  .ph-r-body h3 {
    font-family: var(--font-display); font-weight: 800; font-size: 17px; line-height: 1.24;
    color: var(--ink); margin: 0; padding-right: 42px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .ph-rmeta {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 7px;
    font-size: 12.5px; color: var(--muted); font-weight: 600;
  }
  .ph-rmeta > span { display: inline-flex; align-items: center; gap: 4px; }
  .ph-rmeta svg { flex: none; }
  .ph-rmeta .ph-pr { color: var(--green); font-weight: 700; }
  /* Les créneaux prennent leur PROPRE ligne, sous celle des traits : glissés
     dedans, ils poussaient le prix à la ligne dès qu'un plat était prévu deux
     fois. Ils reprennent la taille de cette ligne, sinon ils passeraient pour
     un titre : le bouton qui les contient porte la police du corps. */
  .ph-plan {
    display: flex; align-items: center; gap: 5px;
    margin-top: 5px; font-size: 12.5px; color: var(--info); font-weight: 700;
  }
  .ph-plan svg { flex: none; }
  /* Pas de pastille « recette ecrite » : le libelle du bouton porte deja l'etat.
     Le dire deux fois sur la meme fiche est du bruit. */
  .ph-ings {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    margin-top: 8px; font-size: 13px; color: var(--ink-soft); line-height: 1.4;
  }
  .ph-ings i { font-style: normal; color: var(--muted); }
  .ph-r-foot { display: flex; gap: 8px; padding: 0 12px 12px; align-items: center; }
  .ph-rec .fav { position: absolute; top: 4px; right: 4px; z-index: 2; }

  /* La pagination garde ses numeros : un livre tient rarement sur plus de six
     pages, et 44 px de cible suffisent a la rendre utilisable au doigt. */
  .fav-pages { padding: 0 12px 4px; flex-wrap: wrap; }
  .fav-pages .fav-page { min-width: 44px; min-height: 44px; }
}

@media (max-width: 600px) {

  /* ================= MON ACCES (ex « Donnees ») ================= */
  .ph-acc { padding: 12px 12px 6px; display: flex; flex-direction: column; gap: 12px; }
  .ph-acc > * { flex: none; }
  .ph-acc .ph-st { padding: 6px 4px 0; }

  /* ---------- la carte d'etat ----------
     LA PIECE CENTRALE, et la seule nouveaute de l'ecran : elle dit en une
     phrase si l'utilisateur peut perdre ses menus. Deux etats, deux couleurs,
     une action. Cette information vivait dans un encadre jaune a 1500 px de
     defilement, intitule « Astuce ». */
  .ph-hp { border-radius: var(--radius-xl); padding: 16px; box-shadow: inset 0 0 0 1px var(--line); }
  .ph-hp.est-risque { background: var(--gold-bg); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gold) 45%, var(--line)); }
  .ph-hp.est-sauf { background: var(--green-bg); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--green) 28%, var(--line)); }
  .ph-hp.est-neutre { background: var(--surface-2); }
  .ph-hp-top { display: flex; gap: 13px; align-items: flex-start; }
  .ph-hp .ph-p-face {
    width: 54px; height: 54px; flex: none; border-radius: 17px;
    background: var(--surface); overflow: hidden; display: grid; place-items: center;
  }
  .ph-hp .ph-p-face svg { width: 48px; height: 48px; display: block; }
  .ph-hp-tx { min-width: 0; flex: 1; }
  .ph-hp-tx i {
    display: block; font-style: normal; font-family: "Caveat", var(--font-body), cursive;
    font-weight: 700; font-size: 16px; line-height: 1; margin-bottom: 3px;
  }
  .ph-hp.est-risque .ph-hp-tx i { color: var(--gold-ink); }
  .ph-hp.est-sauf .ph-hp-tx i { color: var(--green); }
  .ph-hp.est-neutre .ph-hp-tx i { color: var(--muted); }
  .ph-hp-tx b { display: block; font-family: var(--font-display); font-weight: 800; font-size: 18px; color: var(--ink); line-height: 1.2; }
  .ph-hp-tx s { display: block; text-decoration: none; font-size: 13px; color: var(--ink-soft); margin-top: 5px; line-height: 1.45; }
  .ph-hp-tx s b { display: inline; font-family: inherit; font-size: inherit; }
  .ph-hp-go { display: flex; gap: 8px; margin-top: 13px; }
  .ph-hp-go button {
    flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: 46px; border: 0; border-radius: var(--radius); cursor: pointer;
    font-family: var(--font-display); font-weight: 800; font-size: 14px; white-space: nowrap;
    transition: transform .18s cubic-bezier(.3, 1.5, .4, 1);
  }
  .ph-hp-go button:active { transform: scale(.97); }
  .ph-hp-go svg { flex: none; }
  .ph-hp-go .a { background: var(--ink); color: var(--bg); }
  .ph-hp-go .b { background: var(--surface); color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); }
  /* Seule, la puce « Copier » n'a pas a s'etirer sur toute la largeur : un pave
     vide de 350 px pour un mot de six lettres. */
  .ph-hp-go .b:only-child { flex: 0 1 auto; padding: 0 18px; }

  /* ---------- la carte et ses lignes nommees ---------- */
  .ph-carte {
    background: var(--surface); border-radius: var(--radius-lg); overflow: hidden;
    box-shadow: var(--shadow-sm), 0 10px 24px -18px rgba(150, 90, 30, .5);
  }
  .ph-vide { margin: 0; padding: 14px; font-size: 13.5px; color: var(--ink-soft); line-height: 1.5; }
  .ph-lnk { display: flex; align-items: center; gap: 9px; padding: 12px 12px 0; }
  /* ================= LE QR, QUAND C'EST L'AUTRE QUI SCANNE =================
     `.qr-bloc` porte une regle generale qui dit l'inverse : « sur un telephone, ce
     code ne sert a rien, c'est lui qui le scanne ». Vrai de la modale de
     sauvegarde, ou le QR fait passer un planning de l'ordinateur au telephone.

     Faux ici. « Ouvrir sur un autre appareil » part du telephone et s'adresse a
     un SECOND appareil, qui vise le code en face a face : c'est le seul endroit
     ou le code doit etre grand sur un petit ecran. A 116 px il est lisible de
     tres pres et de nulle part ailleurs.

     La regle est donc portee par la carte de la modale, et pas par `.qr-bloc` :
     changer le composant partage casserait l'hypothese des deux autres usages. */
  .qr-card .qr-img { width: 236px; height: 236px; padding: 10px; }
  .qr-card .qr-bloc { gap: 12px; }

  .ph-lnk code {
    flex: 1; min-width: 0; background: var(--surface-2); border-radius: 12px; padding: 11px 12px;
    font-family: "JetBrains Mono", ui-monospace, monospace; font-size: 12.5px; color: var(--ink-soft);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .ph-cp {
    flex: none; min-height: 44px; border: 0; border-radius: 13px;
    background: var(--primary); color: #fff; cursor: pointer; padding: 0 15px;
    font-family: var(--font-display); font-weight: 800; font-size: 13.5px;
    display: inline-flex; align-items: center; gap: 6px;
  }
  .ph-cp svg { flex: none; }
  .ph-rows2 { margin-top: 10px; }
  /* UNE LIGNE NOMMEE, PAS UN BOUTON DE PLUS. « Ton acces » alignait six boutons
     de meme poids, dont deux en orange plein : impossible de deviner lequel
     faisait la chose importante. Le titre dit le geste, le sous-titre dit sa
     consequence. */
  .ph-l2 {
    display: flex; align-items: center; gap: 12px; width: 100%;
    border: 0; background: none; font: inherit; text-align: left; cursor: pointer;
    padding: 10px 12px; min-height: 58px; transition: background .16s;
    color: inherit; text-decoration: none;
  }
  .ph-l2 + .ph-l2 { box-shadow: inset 0 1px 0 var(--line); }
  .ph-l2:active { background: var(--surface-2); }
  .ph-l2:focus-visible { outline: none; box-shadow: var(--ring); }
  .ph-lib {
    width: 36px; height: 36px; flex: none; border-radius: 12px;
    display: grid; place-items: center; background: var(--surface-2); color: var(--ink-soft);
  }
  .ph-lib.g { background: var(--green-bg); color: var(--green); }
  .ph-lib.o { background: var(--primary-bg); color: var(--primary-ink); }
  .ph-lib.s { background: var(--gold-bg); color: var(--gold-ink); }
  .ph-ltx { flex: 1; min-width: 0; }
  .ph-ltx b { display: block; font-family: var(--font-display); font-weight: 700; font-size: 15px; color: var(--ink); line-height: 1.25; }
  .ph-ltx s { display: block; text-decoration: none; font-size: 12.5px; color: var(--muted); margin-top: 1px; line-height: 1.35; }
  .ph-lc { flex: none; color: var(--line); display: grid; place-items: center; }
  .ph-tag {
    flex: none; border-radius: var(--pill); background: var(--surface-2); color: var(--ink-soft);
    font-family: var(--font-display); font-weight: 800; font-size: 11.5px; padding: 4px 10px;
  }
  /* SEPARATEUR NOMME. « Garder pour moi » et « donner ce planning a quelqu'un »
     etaient melanges dans la meme pile de boutons : ce ne sont ni les memes
     gestes, ni les memes consequences. */
  .ph-split {
    padding: 12px 14px 6px; font-size: 12.5px; color: var(--muted); font-weight: 600;
    box-shadow: inset 0 1px 0 var(--line);
  }

  /* ---------- les quatre chiffres ----------
     Pas une grille 2x2 avec un menu deroulant, et pas un tableau de bord : le
     CONTEXTE du bouton juste en dessous. La periode devient trois puces, parce
     qu'un select pour trois choix est du grand ecran. */
  .ph-stats {
    background: var(--surface); border-radius: var(--radius-lg); padding: 13px 6px 11px;
    box-shadow: var(--shadow-sm), 0 10px 24px -18px rgba(150, 90, 30, .5);
  }
  .ph-sg { display: grid; grid-template-columns: repeat(4, 1fr); }
  .ph-sg > div { text-align: center; padding: 0 4px; position: relative; }
  .ph-sg > div + div::before {
    content: ""; position: absolute; left: 0; top: 3px; bottom: 3px; width: 1px; background: var(--line);
  }
  .ph-sg b { display: block; font-family: var(--font-display); font-weight: 800; font-size: 21px; color: var(--ink); line-height: 1.1; }
  .ph-sg b.est-vert { color: var(--green); }
  .ph-sg s { display: block; text-decoration: none; font-size: 10.5px; color: var(--muted); font-weight: 600; line-height: 1.2; margin-top: 3px; }
  .ph-per {
    display: flex; gap: 6px; justify-content: center; margin-top: 12px; padding-top: 11px;
    box-shadow: inset 0 1px 0 var(--line); overflow-x: auto; scrollbar-width: none;
  }
  .ph-per::-webkit-scrollbar { display: none; }
  .ph-per button {
    flex: none; border: 0; border-radius: var(--pill); background: none; cursor: pointer;
    min-height: 44px; padding: 0 14px; font-family: var(--font-display); font-weight: 800;
    font-size: 12.5px; color: var(--muted); white-space: nowrap; transition: background .18s, color .18s;
  }
  .ph-per button.on { background: var(--surface-2); color: var(--ink); }

  /* ---------- la generation, resserree et rien d'autre ---------- */
  .ph-gen .dn-modebar { padding: 12px 12px 0; }
  .ph-gen .dn-pane { padding: 12px; }
  .ph-gen .dn-lead { display: block; }
  .ph-gen .dn-pop { display: none; }   /* la mascotte est deja en tete de l'ecran, dans la carte d'etat */
  .ph-gen .btn-row { flex-direction: column; }
  .ph-gen .btn-row .btn { width: 100%; justify-content: center; min-height: 48px; }
  .ph-gen .dn-steps { padding-left: 0; }

  /* La carte de soutien : sur une colonne de 390 px, son bouton et son texte se
     partagent mal la ligne. Le bouton prend la sienne. */
  .support-card { flex-wrap: wrap; }
  .support-card .btn { flex: 1 1 100%; justify-content: center; min-height: 46px; }

  /* Le repli une colonne du bloc hebdo vit dans une requete a 760 px du
     VIEWPORT : sur un telephone de 390 px elle est deja active, il n'y a rien a
     reprendre. Ce qui manquait, c'est la cible tactile de son interrupteur
     MAITRE : 30 px de haut pour allumer ou eteindre le service entier, et c'est
     le defaut qui est revenu le plus souvent en revue.

     LA CIBLE PASSE A 44 px SANS QUE LE RAIL GROSSISSE : celui-ci est redessine
     en `::before`, et l'element ne sert plus que de zone tactile. L'aspect de
     l'interrupteur ne change donc pas d'un pixel, sur aucun ecran. */
  .dnh-sw { width: 56px; height: 44px; background: none; }
  .dnh-sw[aria-checked="true"] { background: none; }
  .dnh-sw::before {
    content: ""; position: absolute; left: 2px; top: 7px; width: 52px; height: 30px;
    border-radius: var(--pill); background: color-mix(in srgb, var(--muted) 34%, var(--surface-2));
    transition: background .26s ease;
  }
  .dnh-sw[aria-checked="true"]::before { background: var(--green); }
  .dnh-sw::after { top: 10px; left: 5px; }
}

@media (max-width: 600px) {
  /* La porte de sortie des ecrans sans onglet (« Preferences »). Un chevron
     vers la gauche et le NOM de l'ecran d'ou l'on vient : « Retour » seul
     demande de se souvenir par ou on est passe. */
  .ph-retour { padding: 8px 0 2px; }
  .ph-retour button {
    display: inline-flex; align-items: center; gap: 4px;
    min-height: 44px; padding: 0 12px 0 6px;
    border: 0; border-radius: var(--pill); background: none; cursor: pointer;
    font-family: var(--font-display); font-weight: 800; font-size: 14px; color: var(--ink-soft);
  }
  .ph-retour button:active { background: var(--surface-2); }
  .ph-retour svg { flex: none; }
}

@media (max-width: 600px) {
  /* La ligne qui dit CE QU'ON REGARDE et PAR QUOI C'EST TRIE. Sans titre de page
     ni sous-titre sur telephone, c'est elle qui porte le compte. */
  .ph-bhead { display: flex; align-items: center; gap: 8px; padding: 2px 12px 0; }
  .ph-bn { flex: 1; min-width: 0; font-family: var(--font-display); font-weight: 800; font-size: 13.5px; color: var(--ink-soft); }
  .ph-sortb {
    flex: none; border: 0; border-radius: var(--pill); background: var(--surface-2);
    cursor: pointer; min-height: 44px; padding: 0 14px;
    font-family: var(--font-display); font-weight: 800; font-size: 12.5px; color: var(--ink-soft);
    display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  }
  .ph-sortb svg { flex: none; color: var(--muted); }
  .ph-sortb:active { background: var(--bg-tint); }
  .ph-sortb:focus-visible { outline: none; box-shadow: var(--ring); }

  /* La provenance d'un article ajoute a la main, sur la rangee des courses.
     Discrete : elle explique un bouton de plus derriere le « ··· », elle
     n'alerte de rien. */
  .ph-aj {
    font-style: normal; font-weight: 800; font-size: 10.5px;
    color: var(--info); background: var(--info-bg);
    border-radius: var(--pill); padding: 1px 6px;
  }
}

@media (max-width: 600px) {
  /* L'attente rentre dans la gouttiere, comme les bandeaux voisins. */
  .ph-plein .ai-wait-bloc { margin-left: 12px; margin-right: 12px; }
  .ph-plein .ai-wait-bloc .ai-wait { padding: 22px 16px 20px; }
  .ph-plein .ai-wait-bloc .ai-wait-mascot { width: 66px; }
}

@media (max-width: 600px) {
  /* Les deux placements du soutien rentrent dans la gouttiere, comme les
     bandeaux voisins. La ligne de fin de flux suit le bloc terminus. */
  .ph-plein .soutien-carte { margin-left: 12px; margin-right: 12px; }
  .ph-plein .soutien-ligne { margin: 14px 14px 4px; }
}

/* Une feuille qui glisse pendant qu'on cherche le bon item est une feuille
   qu'on rate : le mouvement s'arrete, l'etat reste. */
@media (prefers-reduced-motion: reduce) {
  .ph-sheet, .ph-scrim, .ph-fab, .tab-ib { transition-duration: .01ms; }
}
