:root {
  --fond: #f7f6f2;
  --carte: #ffffff;
  --texte: #1e1e1c;
  --texte-doux: #6a6a63;
  --bord: #e2e0d8;
  --bord-fort: #c9c6ba;
  --accent: #0f6e56;
  --accent-doux: #e1f5ee;
  --alerte: #854f0b;
  --alerte-doux: #faeeda;
  /* Rouge reserve au destructif, distinct de --alerte (ambre) qui signale
     seulement « regarde ca ». */
  --danger: #a32d2d;
  --danger-fonce: #791f1f;
  --danger-doux: #fbe0e0;
  --rayon: 10px;
  /* Bleu de l'ecusson (logo-fourchette-feuille.svg) : mis en commun ici pour
     que l'indice Zone Bleue porte exactement la meme teinte que la marque. */
  --zone-bleue: #3b74b8;
  /* Le fond tres pale de la meme teinte, pour poser un aplat sans crier :
     il sert au jour courant du planning. Pendant du couple accent /
     accent-doux. */
  --zone-bleue-doux: #e4eef9;
  /* Le texte pose SUR un aplat de --zone-bleue (bouton plein). */
  --sur-zone-bleue: #ffffff;

  /* Echelle typographique — 7 paliers, que des entiers, au moins 1px d'ecart
     entre chacun (15/08). Elle remplace 14 tailles dont des demi-pixels
     indiscernables a l'oeil (12/12,5, 13/13,5, 14/14,5). Toute nouvelle
     regle de taille doit piocher ici, jamais ecrire un pixel en dur. */
  --fs-xs: 11px;      /* badges, etiquettes en petites capitales */
  --fs-sm: 12px;      /* aides, legendes, en-tetes de tableau, explications */
  --fs-md: 13px;      /* interface dense : etiquettes de champ, dates */
  --fs-base: 14px;    /* texte courant : boutons, sous-titre, titres de vignette */
  /* 16px et non 15 : en dessous, Safari iOS zoome a chaque fois qu'on touche
     un champ de saisie — a regler avant la PWA, pas apres. */
  --fs-lg: 16px;      /* champs de saisie, titre de plat du planning */
  --fs-xl: 18px;      /* titres de bloc et de modale */
  --fs-2xl: 26px;     /* titre de page */

  /* Interlignes (15/08). Trois valeurs, deux registres : `--lh-icone` n'est
     pas de la typographie mais le centrage d'un glyphe dans un bouton carre,
     et ne doit jamais servir a du texte. */
  --lh-icone: 1;      /* boutons-icones : cadenas, croix, case de presence */
  --lh-titre: 1.3;    /* titres courts, qui peuvent passer sur deux lignes */
  --lh-texte: 1.55;   /* toute prose — valeur heritee du body */
}

@media (prefers-color-scheme: dark) {
  :root {
    --fond: #14140f;
    --carte: #1d1d19;
    --texte: #ececdf;
    --texte-doux: #9d9d92;
    --bord: #33332c;
    --bord-fort: #4a4a41;
    --accent: #5dcaa5;
    --accent-doux: #0f2a22;
    --alerte: #efa027;
    --alerte-doux: #2e2213;
    --danger: #e24b4a;
    --danger-fonce: #f09595;
    --danger-doux: #3a1a1a;
    --zone-bleue: #6fa3e0;
    --zone-bleue-doux: #14253a;
    --sur-zone-bleue: #0b1c2e;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 1.5rem clamp(1rem, 4vw, 3rem) 3rem;
  background: var(--fond);
  color: var(--texte);
  font: 400 16px/1.55 system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* -- en-tete ------------------------------------------------------------- */

.entete {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 1.25rem;
}

h1 { margin: 0; font-size: var(--fs-2xl); font-weight: 500; letter-spacing: -0.01em; }

/* L'ecusson de l'en-tete, a gauche du titre. Ses couleurs sont fixes dans le
   SVG (bleu et vert moyens) : lisibles sur fond clair comme sombre. */
.titre { display: flex; align-items: center; gap: 12px; }
.logo-entete { width: 46px; height: 46px; flex: 0 0 auto; }

.sous-titre { margin: 4px 0 0; color: var(--texte-doux); font-size: var(--fs-base); }

/* Une pastille doit se poser pareil qu'elle soit un <span> ou un <button> :
   « période scolaire » et « à régénérer » se cotoient, et le bouton prenait
   la police du systeme, une taille plus petite et une hauteur a lui
   (Guillaume, 05/09).

   `font: inherit` d'abord — sans lui, un <button> ne prend NI la famille NI
   la graisse du document. Puis une taille et une hauteur de ligne fixees
   ici, les memes pour les deux, et non heritees : le 1,55 du corps de page
   donnait 18,6 px a l'une et 17,1 px a l'autre.

   Plus de `margin-left` : les conteneurs qui alignent des pastilles ont leur
   `gap`, et cette marge decalait la premiere de six pixels — ce qui la
   desalignait du titre juste au-dessus. */
.pastille {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: 999px;
  font: inherit;
  font-size: var(--fs-sm);
  line-height: 1.25;
}
.pastille.scolaire { background: var(--accent-doux); color: var(--accent); }
.pastille.vacances { background: var(--alerte-doux); color: var(--alerte); }

.nav { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.nav form { margin: 0; }

.bouton {
  display: inline-block;
  padding: 7px 14px;
  border: 1px solid var(--bord-fort);
  border-radius: var(--rayon);
  background: var(--carte);
  color: var(--texte);
  font: inherit;
  font-size: var(--fs-base);
  text-decoration: none;
  cursor: pointer;
}
.bouton:hover { border-color: var(--texte-doux); }
.bouton.primaire { background: var(--accent); border-color: var(--accent); color: #fff; }
@media (prefers-color-scheme: dark) {
  .bouton.primaire { color: #06231c; }
}

/* Le bleu de la marque plutot que le vert de l'interface : « Nouvelle
   recette » ouvre le corpus Zone Bleue, c'est la seule commande de l'en-tete
   qui merite la couleur de l'ecusson (Guillaume, 04/09). Reserve a elle —
   les autres boutons pleins restent verts, sinon le bleu ne designe plus
   rien. */
.bouton.bleu {
  background: var(--zone-bleue);
  border-color: var(--zone-bleue);
  color: var(--sur-zone-bleue);
}

.bouton.danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
.bouton.danger:hover { background: var(--danger-fonce); border-color: var(--danger-fonce); }
@media (prefers-color-scheme: dark) {
  .bouton.danger { color: #2a0d0d; }
}

/* -- grille -------------------------------------------------------------- */

.grille {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0 8px;
  table-layout: fixed;
}

.grille thead th {
  padding: 8px 14px 6px;
  text-align: left;
  font-size: var(--fs-sm);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--texte-doux);
  /* Collantes sous la barre de semaine. Le decalage vient de --haut-barre,
     mesuree par panneau.js : la barre se replie sur plusieurs lignes quand le
     panneau retrecit, un `top` fige serait faux. Le repli sur 0 protege le cas
     ou le script ne tourne pas — les entetes collent alors en haut, sous la
     barre plutot que dessous, ce qui reste lisible.
     `th` et non `thead` : Safari ne rend pas `position: sticky` sur `thead`.
     Le fond est indispensable, sinon les cellules defilent au travers. */
  position: sticky;
  top: var(--haut-barre, 0px);
  z-index: 4;      /* sous la barre de semaine (5), qui doit les recouvrir */
  background: var(--carte);
}

.col-jour { width: 130px; }

.grille tbody th.col-jour {
  padding: 14px;
  text-align: left;
  vertical-align: top;
  font-weight: 500;
}
.nom-jour { display: block; text-transform: capitalize; }
.date-jour { display: block; font-size: var(--fs-md); color: var(--texte-doux); font-weight: 400; }

/* Le jour du jour. Le planning s'ouvre dessus (jour-courant.js), mais il
   suffit d'un coup de molette pour le perdre de vue : un lisere sur la
   colonne du jour et la date en gras suffisent a le retrouver. Le liseré est
   pose sur le th et non sur le tr — une bordure de ligne ne se dessine pas
   dans un tableau a `border-collapse: separate`. */
/* Un lisere vert ne se voyait pas assez : le jour courant prend un APLAT
   bleu, celui de la marque, sur toute sa ligne — colonne de date et cellules
   des deux repas (Guillaume, 04/09). Les cellules gardent leur bordure, donc
   la ligne se lit comme une bande de cartes teintees et non comme un bloc. */
.grille tr.aujourdhui th.col-jour,
.grille tr.aujourdhui .cellule {
  background: var(--zone-bleue-doux);
  border-color: var(--zone-bleue);
}
.grille tr.aujourdhui th.col-jour {
  border-left: 3px solid var(--zone-bleue);
  border-radius: var(--rayon) 0 0 var(--rayon);
  padding-left: 8px;
}
.grille tr.aujourdhui .date-jour { color: var(--texte); font-weight: 600; }

.cellule {
  padding: 0;
  background: var(--carte);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  vertical-align: top;
}

/* Le pied etait pousse au bas de la cellule par `height:1px` sur le <td> +
   `height:100%` ici : l'astuce classique des cellules de tableau, qui donne
   une base fiable au pourcentage tant que le <td> resout sa propre hauteur
   AVANT ses enfants — Chrome le fait, Firefox non. Mesure (03/09) : sur deux
   cellules d'une meme ligne, l'une avec un texte long, Firefox donnait aux
   deux la meme hauteur MINUSCULE (3 px) au lieu de la hauteur du contenu, et
   le texte debordait hors de la carte au lieu de l'agrandir. Sans hauteur
   fixee, la cellule grandit avec son contenu — normalement, dans les deux
   moteurs — et le pied suit simplement en flux, juste apres l'annotation :
   il ne colle plus a l'extremite basse d'une ligne ou une cellule voisine
   serait plus haute, mais rien ne deborde plus jamais. */
.cellule-interieur {
  display: flex;
  flex-direction: column;
  padding: 12px 14px 10px;
}
.cellule.type-restes { background: transparent; border-style: dashed; }
/* Dehors : le trait discontinu dit « rien a cuisiner ici », comme les
   restes, mais sans la mise en retrait d'un creneau ou personne n'est la —
   ce repas est voulu. */
.cellule.type-exterieur { background: transparent; border-style: dashed; }

.choix-exterieur { margin: 0 0 12px; }
/* Le champ, son etiquette et le bouton sur une seule ligne en large ; ils
   s'empilent sous 480 px, ou la ligne ne tient plus. */
.choix-dehors { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.choix-dehors .champ { flex: 1 1 200px; min-width: 0; }
.etiquette-note { font-size: var(--fs-md); color: var(--texte-doux); }
.choix-maison { margin-top: 8px; }

.cellule.type-hors_foyer,
.cellule.type-restes_precedente { background: transparent; border-style: dashed; opacity: 0.75; }
.cellule.verrouillee { border-color: var(--accent); border-width: 2px; }

/* Mise en page de la cellule (14/08) : titre en haut avec le cadenas, photo
   au centre avec l'annotation a sa droite, pied avec les temps a gauche et
   les couverts a droite — pied en bas de colonne flex via .cellule-interieur,
   DANS le flux (voir le commentaire de .cellule). */
.cellule-titre {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.cellule-titre form { margin: 0; }

.cellule-corps {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 8px;
}

/* Le meme emplacement reserve que les vignettes de la liste, en format
   timbre : la place est prise des aujourd'hui, aucune bascule de mise en
   page le jour ou les photos arriveront. */
.cellule-photo {
  flex: 0 0 84px;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border: 1px solid var(--bord);
  border-radius: 8px;
  background: var(--fond);
}
.cellule-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.cellule-photo img.sans-photo {
  object-fit: contain;
  padding: 8px;
  opacity: 0.5;
}

.cellule-annotation { flex: 1 1 auto; min-width: 0; }

.cellule-pied {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 8px;
  padding-top: 8px;
}
/* Les temps du pied portent .vignette-temps : memes libelles et memes
   petites capitales que la vignette de la liste des recettes — chacun dans
   un badge au fond gris clair, le style .badge par defaut (14/08). */
.temps-pied { font-size: var(--fs-sm); color: var(--texte-doux); }
.temps-pied.vignette-temps { gap: 4px 6px; }

/* La regle .badge, plus bas dans le fichier, remettrait inline-block et
   casserait l'alignement de la fourchette : la specificite de celle-ci
   l'emporte quel que soit l'ordre. */
.cellule-pied .couverts.badge { display: inline-flex; }

.couverts {
  /* Repere de la pastille de surplus, qui se pose sur son angle. */
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: var(--fs-sm);
  color: var(--texte-doux);
  white-space: nowrap;
}
.couverts svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

/* Le surplus de cuisson, pose sur l'angle du compteur de couverts comme le
   stock l'est sur le frigo : meme dessin, meme facon de dire « ce chiffre
   concerne celui-la ». Sur l'angle de la pastille entiere et non sur la
   fourchette, large de 13 px : la marque l'aurait recouverte. Rouge et non
   bleu — ce n'est pas une reserve acquise mais du travail en plus a la
   cuisson, et du volume en plus dans les courses. */
.surplus-portions {
  position: absolute;
  top: -9px;
  right: -7px;
  min-width: 17px;
  padding: 0 3px;
  border: 2px solid var(--carte);
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: var(--fs-xs);
  line-height: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
@media (prefers-color-scheme: dark) {
  .surplus-portions { color: #2a0d0d; }
}

/* La pastille d'une cuisson a venir ouvre le reglage des portions pour le
   frigo (06/09) : un lien qui garde l'aspect du badge, et se revele au
   survol comme les autres commandes de la cellule. */
/* Les couverts et, a cote, les boites du congelateur (07/10). */
.couverts-groupe { display: inline-flex; align-items: center; gap: 12px; }
.congel-portions {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: var(--fs-sm);
  color: var(--zone-bleue);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.congel-portions svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}
a.cellule-portions.congel-portions,
a.cellule-portions.congel-portions:hover { color: var(--zone-bleue); }

a.cellule-portions {
  text-decoration: none;
  color: var(--texte-doux);
  cursor: pointer;
}
a.cellule-portions:hover,
a.cellule-portions:focus-visible {
  color: var(--texte);
  border-color: var(--texte-doux);
}
a.cellule-portions:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* -- la modale des portions pour le frigo --------------------------------- */

/* « Une petite modale » (Guillaume, 06/09) : la boite commune fait 880 px,
   trop pour une ligne. Elle se resserre quand c'est ce reglage qu'elle
   porte — sur mobile, elle reste plein ecran comme les autres. */
.modale:has(.reglage-portions) { width: min(440px, 100%); }
/* Avec la ligne du congelateur, deux compteurs cote a cote : un peu plus. */
.modale:has(.reglage-congel) { width: min(500px, 100%); }

/* Une ligne : le frigo, un moins, le nombre, un plus. Les touches sont
   larges — c'est au doigt qu'on s'en sert — et le nombre garde une largeur
   fixe pour que les touches ne bougent pas quand il change. */
.reglage-portions {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 8px 0 4px;
}
.reglage-portions .icone-frigo,
.reglage-portions .icone-congelation { margin-left: 0; cursor: default; }
.reglage-portions .icone-frigo svg,
.reglage-portions .icone-congelation svg { width: 28px; height: 28px; }
.reglage-congel { margin-top: 18px; }
.reglage-lien { color: var(--texte-doux); white-space: nowrap; }
/* Au telephone, deux compteurs tiennent sur une ligne en serrant l'ecart
   et les touches : 40 px restent une bonne cible au doigt. */
@media (max-width: 480px) {
  .reglage-congel { gap: 8px; }
  .reglage-congel .reglage-bouton { width: 40px; height: 40px; }
}
.reglage-portions form { display: contents; }
.reglage-bouton {
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--bord);
  border-radius: 50%;
  background: var(--carte);
  color: var(--texte);
  font-size: var(--fs-xl);
  line-height: 1;
  cursor: pointer;
}
.reglage-bouton:hover { border-color: var(--texte-doux); }
.reglage-bouton:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.reglage-bouton:disabled {
  opacity: 0.35;
  cursor: default;
}
.reglage-compte {
  min-width: 2ch;
  text-align: center;
  font-size: var(--fs-xl);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* -- indice Zone Bleue : les feuilles ------------------------------------- */

/* Feuilles bleues (16/08 : les recettes notees sont celles des zones
   bleues, la couleur le rappelle). Les vides restent visibles mais eteintes
   par l'opacite : « 3 sur 5 » se lit par la forme, pas seulement par la
   couleur. cursor: help annonce l'infobulle qui porte le detail du calcul. */
.feuilles {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  color: var(--zone-bleue);
  cursor: help;
  --taille-feuille: var(--fs-md);
}
.icone-feuille {
  width: var(--taille-feuille);
  height: var(--taille-feuille);
  fill: currentColor;
}
.feuille-vide { opacity: 0.25; }

.feuilles-semaine { --taille-feuille: var(--fs-base); }

/* Pied de vignette : l'indice a gauche, le frigo pousse a droite. La marge
   automatique tient la separation quelle que soit la largeur — et le pied
   garde sa place meme quand l'indice manque (recette sans ingredient).
   `min-height` : dans la liste des recettes l'icone est remplacee par un
   bouton pose par-dessus, la ligne doit garder sa hauteur sans elle. */
.vignette-pied { display: flex; align-items: center; gap: 8px; min-height: 18px; }
.icone-frigo {
  display: inline-flex;
  margin-left: auto;
  color: var(--zone-bleue);
  cursor: help;
}
/* Eteinte, l'icone reste lisible sans attirer l'oeil : le gris des textes
   secondaires, pas celui des bordures, qui la ferait disparaitre. La teinte
   seule, sans `opacity` : celle-ci creerait un groupe et palirait AUSSI la
   pastille du stock, qui doit rester franche — elle ne dit pas si la recette
   peut se garder, mais ce qui attend vraiment. */
.icone-frigo.eteint { color: var(--texte-doux); }

/* Le flocon du congelateur, a gauche du frigo (06/10) : c'est lui qui
   prend la marge automatique, le frigo le suit. */
.icone-congelation {
  display: inline-flex;
  margin-left: auto;
  color: var(--zone-bleue);
  cursor: help;
}
.icone-congelation + .icone-frigo { margin-left: 0; }
.icone-congelation.eteint { color: var(--texte-doux); }

/* Le compte de portions qui attendent au frigo : une pastille POSEE SUR
   l'angle du frigo, comme un compteur de notifications. Posee a cote, elle
   se lisait comme une information independante (Guillaume, 05/09) ; a cheval
   sur l'icone, le lien entre les deux se voit sans y penser.

   Le liseré reprend le fond de la vignette : il detache le chiffre du trait
   du frigo sans introduire de couleur de plus. */
.frigo-marque { position: relative; display: inline-flex; }
.stock-frigo {
  position: absolute;
  top: -7px;
  right: -9px;
  min-width: 17px;
  padding: 0 3px;
  border: 2px solid var(--fond);
  border-radius: 999px;
  background: var(--zone-bleue);
  color: #fff;
  font-size: var(--fs-xs);
  line-height: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
@media (prefers-color-scheme: dark) {
  .stock-frigo { color: #0b1c2e; }
}
/* Dans la liste des recettes, l'icone est un bouton POSE PAR-DESSUS le coin :
   le pied lui reserve sa place, sinon l'indice passerait dessous. */
.carte-recette .vignette-pied { padding-right: 66px; }

.icone-congelation svg,
.icone-frigo svg {
  /* 18 px : un cran au-dessus des feuilles qu'il cotoie. Plus petit, le
     trait du congelateur et les deux poignees se confondaient. */
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.feuilles-grandes { margin: 0 0 10px; --taille-feuille: 22px; }
.feuilles-grandes .feuilles-note {
  margin-left: 10px;
  font-size: var(--fs-base);
  color: var(--texte-doux);
}
.note-indice {
  margin: 0 0 8px;
  font-size: var(--fs-md);
  color: var(--texte-doux);
}
.note-indice strong { font-size: var(--fs-lg); color: var(--texte); }
.points-indice {
  margin: 0 0 10px;
  padding-left: 1.2rem;
  font-size: var(--fs-md);
}
.points-indice li { margin-bottom: 2px; }

/* -- bloc depliable (l'indice de la modale recette) ----------------------- */

/* Un <details> habille en bloc : la ligne de resume est le titre du bloc,
   avec les feuilles a cote, et un chevron a droite qui dit qu'elle s'ouvre.
   Le marqueur natif est retire des DEUX facons (voir `.compte > summary`). */
.bloc-depliable { padding-bottom: 1rem; }
.bloc-depliable[open] { padding-bottom: 1.25rem; }
.bloc-depliable > summary {
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  list-style: none;
}
.bloc-depliable > summary::-webkit-details-marker { display: none; }
/* Le titre ne se coupe pas : sur 390 px, ce sont les feuilles qui se
   serrent (18 px au lieu de 22) pour que tout tienne sur une ligne. */
.bloc-depliable > summary h2 { margin: 0; white-space: nowrap; }
.bloc-depliable > summary .feuilles-grandes {
  margin: 0;
  cursor: pointer;
  --taille-feuille: 18px;
}
.bloc-depliable > summary .feuilles-note { margin-left: 6px; }
.bloc-depliable > summary::after {
  content: "▸";
  margin-left: auto;
  color: var(--texte-doux);
  font-size: var(--fs-lg);
  transition: transform .15s;
}
.bloc-depliable[open] > summary::after { transform: rotate(90deg); }
.bloc-depliable[open] > summary { margin-bottom: 10px; }
.bloc-depliable > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* -- bloc Photo de la modale recette -------------------------------------- */

/* Meme ratio 16/10 et meme traitement du pictogramme par defaut que les
   vignettes : l'apercu de la modale annonce exactement ce que la liste et
   le planning montreront. */
.photo-recette {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
/* La photo est un bouton : reset complet, sinon le fond et la bordure du
   navigateur dessinent une seconde carte autour de l'image. */
.photo-cible {
  position: relative;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 8px;
}
.photo-recette img {
  display: block;
  width: 200px;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border: 1px solid var(--bord);
  border-radius: 8px;
  background: var(--fond);
}
.photo-recette img.sans-photo { object-fit: contain; padding: 10px; opacity: 0.5; }
/* Pastille sombre et non un simple crayon pose dessus : le trait blanc doit
   rester lisible aussi bien sur une assiette claire que sur un fond de four. */
.photo-crayon {
  position: absolute;
  right: 6px;
  bottom: 6px;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
}
.photo-crayon svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.photo-cible:hover img { filter: brightness(0.9); }
.photo-cible:hover .photo-crayon { background: var(--accent); }
.photo-cible:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.verrou {
  border: 0;
  background: none;
  padding: 0 2px;
  font-size: var(--fs-lg);
  line-height: var(--lh-icone);
  cursor: pointer;
  opacity: 0.5;
}
.verrou:hover { opacity: 1; }
.verrouillee .verrou { opacity: 1; }
/* Un repas deja servi ne se change plus (06/09) : ses deux commandes restent
   en place, grisees, sans survol ni curseur — le cadenas dit encore s'il
   etait verrouille, mais ne repond plus. */
.verrou:disabled, .verrouillee .verrou:disabled {
  opacity: 0.25;
  cursor: default;
  filter: grayscale(1);
}

/* Bandeau gris clair pour detacher le titre du reste de la cellule. `--fond`
   et non `--carte` : les cellules de restes sont transparentes et laissent
   voir le panneau, blanc lui aussi — le bandeau doit donc contraster avec le
   BLANC dans les deux cas. Il s'etire jusqu'au cadenas, qui reste en dehors. */
.plat {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding: 3px 7px;
  border-radius: 6px;
  background: var(--fond);
  font-size: var(--fs-lg);
  /* Meme interligne que .vignette-titre : c'est le MEME titre de recette des
     deux cotes de l'ecran, il heritait ici du registre « prose » du body. */
  line-height: var(--lh-titre);
  font-weight: 500;
}
.vide { margin: 0 0 8px; color: var(--texte-doux); font-size: var(--fs-base); font-style: italic; }

.meta { display: flex; flex-wrap: wrap; gap: 5px; margin: 0; align-items: center; }

.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--fs-xs);
  background: var(--fond);
  color: var(--texte-doux);
  border: 1px solid var(--bord);
}
.badge.legumineuse,
.badge.complet { background: var(--accent-doux); color: var(--accent); border-color: transparent; }
.badge.restes { background: transparent; }
/* Les options du cuisinier (congelation, reste) se distinguent des tags
   qu'elles cotoient sur la fiche : ce ne sont pas des mots libres mais deux
   etats poses a la case, et le bleu des zones bleues n'est pas le leur. */
.badge.option {
  background: transparent;
  border-color: var(--bord-fort);
  color: var(--texte);
}

/* Le pied de la zone « Paramètres » : la grille des menus a son propre
   espacement, la ligne du bouton n'a pas a coller au dernier champ. */
.pied-parametres { margin-top: 14px; }

/* La ligne « Options » du formulaire de recette : deux cases cote a cote,
   qui passent l'une sous l'autre quand la ligne n'est plus assez large. */
.options-recette {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
}

.pourquoi {
  margin: 7px 0 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-texte);
  color: var(--texte-doux);
  /* Bornee a 2 lignes, quelle que soit la largeur de la cellule : le texte
     entier se lit au survol (title pose par le gabarit). La forme -webkit-
     est celle que tous les navigateurs implementent reellement. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}


/* -- saisie de recette --------------------------------------------------- */

/* Tous les types de champ texte, email/password/date compris : Guillaume a
   valide la modale Profil sur ce style arrondi (le 14/08, en reference au
   champ « Titre » de la recette). Les pages de connexion gardent leur propre
   rendu — leur regle .carte-compte, plus specifique, l'emporte. */
input[type="text"], input[type="url"], input[type="number"],
input[type="search"], input[type="email"], input[type="password"],
input[type="date"], select, textarea {
  font: inherit;
  font-size: var(--fs-lg);
  color: var(--texte);
  background: var(--carte);
  border: 1px solid var(--bord-fort);
  border-radius: var(--rayon);
  padding: 7px 10px;
  width: 100%;
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}
textarea { resize: vertical; }

.bloc {
  margin-bottom: 1.25rem;
  padding: 1rem 1.25rem 1.25rem;
  background: var(--carte);
  border: 1px solid var(--bord);
  border-radius: 12px;
  max-width: 900px;
}
.bloc h2 { margin: 0 0 4px; font-size: var(--fs-xl); font-weight: 500; }
.aide { margin: 0 0 12px; font-size: var(--fs-md); color: var(--texte-doux); }

.champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
}
.champ { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-md); color: var(--texte-doux); }
.champ.large { grid-column: 1 / -1; }

/* .ligne-import est conservee : la zone d'import est retiree de l'ecran
   « pour l'instant » (14/08) et reviendra probablement. */
.ligne-import { display: flex; gap: 8px; }
.ligne-import input { flex: 1; }

.coller { margin-bottom: 14px; }
.coller summary { cursor: pointer; font-size: var(--fs-base); color: var(--texte-doux); margin-bottom: 8px; }
.coller textarea { margin-bottom: 8px; }

/* Aide posee sous une .profil-ligne : elle s'aligne sur le champ, pas sur
   l'etiquette (160px + le gap de 14px). */
.aide-sous-ligne { margin: -6px 0 12px 174px; font-size: var(--fs-sm); }

/* La ligne d'ajout d'un ingredient : quantite etroite, nom sur le reste,
   bouton cale sur le BAS des champs — leurs etiquettes sont au-dessus. */
.ajout-ingredient {
  display: flex;
  /* wrap : sur mobile, les quatre elements passent sur deux lignes au lieu
     de s'ecraser. */
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
  margin-bottom: 8px;
}
/* La quantite est un nombre nu depuis la saisie structuree (18/08) : le
   champ retrecit, la liste d'unites prend la place. */
.ajout-ingredient .champ-quantite { flex: 0 0 84px; }
.ajout-ingredient .champ-unite { flex: 0 0 130px; }
.ajout-ingredient .champ-nom { flex: 1 1 160px; min-width: 0; }
.ajout-ingredient .bouton { flex: 0 0 auto; }

/* Les reglages d'un NOUVEL aliment, reveles quand le nom tape est inconnu :
   l'aliment doit naitre avec le bon rayon et la bonne categorie, pas avec
   des defauts silencieux. */
.ajout-details {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: flex-end;
  margin-bottom: 8px;
  padding: 8px 10px;
  border: 1px dashed var(--alerte);
  border-radius: var(--rayon);
  background: var(--alerte-doux);
}
/* [hidden] ne suffit pas face au display:flex ci-dessus, qui le surclasse
   — le cadre restait affiche en permanence depuis le 14/08 (vu le 07/09). */
.ajout-details[hidden] { display: none; }
.ajout-details .badge { align-self: center; }
.ajout-details .champ { flex: 1 1 130px; }
.ajout-details select { width: 100%; }

/* Le pari de l'analyseur quand il a devine l'aliment (09/09) : meme facture
   que le cadre du nouvel aliment, mais en trait plein et sans alerte — ce
   n'est pas un avertissement, c'est une question. */
.ajout-devine {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin-bottom: 8px;
  padding: 8px 10px;
  border: 1px solid var(--bord-fort);
  border-radius: var(--rayon);
  background: var(--fond);
}
.ajout-devine[hidden] { display: none; }
.ajout-devine span { flex: 1 1 auto; }

/* Une vignette par ingredient — la meme facture que les membres du foyer,
   en plus petit. Supprimable, pas modifiable : on supprime et on rajoute. */
.vignettes-ingredients {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 8px;
}
.vignette-ingredient {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  background: var(--fond);
  font-size: var(--fs-sm);
}
.vignette-ingredient strong {
  font-size: var(--fs-md);
  font-weight: 500;
  padding-right: 34px;      /* la place de la corbeille */
  overflow-wrap: anywhere;
}
.vignette-ingredient .pastille { align-self: flex-start; margin: 2px 0 0; }
.vignette-ingredient .icone-vignette {
  position: absolute;
  top: 6px;
  right: 6px;
}

.etape { display: flex; gap: 8px; align-items: flex-start; margin-bottom: 8px; }
.etape select { width: auto; flex: 0 0 auto; }
.etape textarea { flex: 1; }

.pied-formulaire {
  display: flex;
  gap: 12px;
  align-items: center;
  max-width: 900px;
  margin-bottom: 2rem;
}
/* Action destructive repoussee a l'extremite opposee de l'action principale :
   la marge automatique absorbe toute la place libre, donc la separation tient
   quelle que soit la largeur du pied. */
.pied-formulaire .bouton.danger { margin-left: auto; }
.message { font-size: var(--fs-md); color: var(--texte-doux); }
.message.erreur { color: var(--alerte); }

.recherche { display: flex; gap: 8px; max-width: 520px; margin-bottom: 1rem; }

.liste { width: 100%; border-collapse: collapse; max-width: 1100px; }
.liste th, .liste td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--bord);
  text-align: left;
  vertical-align: top;
  font-size: var(--fs-base);
}
.liste thead th {
  font-size: var(--fs-sm); font-weight: 500; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--texte-doux);
}
.liste td.etroit, .liste th.etroit { width: 1%; white-space: nowrap; }
.liste a { color: var(--texte); text-decoration: none; font-weight: 500; }
.liste a:hover { text-decoration: underline; }
.badge.alerte { background: var(--alerte-doux); color: var(--alerte); border-color: transparent; }

/* -- page liste : en-tete pleine largeur + colonne / panneau ------------- */
/* Tout est porte par .page-liste : app.css sert aussi l'ecran semaine et le
   formulaire de recette, qui gardent la mise en page precedente. */

/* La page occupe exactement la hauteur de la fenetre et ne defile pas
   elle-meme : seules les zones interieures le font. C'est ce qui garde
   l'en-tete immobile, plutot qu'un position: fixed qui l'extrairait du flux
   et obligerait a compenser sa hauteur a la main. */
body.page-liste {
  padding: 0;
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.entete-principale {
  flex: 0 0 auto;
  padding: 1.5rem clamp(1rem, 4vw, 3rem) 1rem;
  border-bottom: 1px solid var(--bord);
  background: var(--carte);
}

/* Le bandeau « Hors ligne », au-dessus de l'en-tete — fond rouge pastel,
   texte rouge en gras (Guillaume, 07/09, en essai). Membre du cadre en
   colonne de .page-liste, il pousse les panneaux vers le bas quand il
   apparait ; `hidden` suffit a l'effacer. */
.bandeau-hors-ligne {
  flex: 0 0 auto;
  padding: 8px clamp(1rem, 4vw, 3rem);
  background: var(--danger-doux);
  color: var(--danger);
  font-size: var(--fs-md);
  font-weight: 700;
  text-align: center;
}

.entete-haut {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-end;
  justify-content: space-between;
}


#mainLayout {
  display: flex;
  align-items: stretch;
  /* flex: 1 pour occuper la hauteur restante sous l'en-tete, min-height: 0
     pour AUTORISER le retrecissement : sans lui un enfant flex refuse de
     passer sous sa hauteur de contenu et le defilement interieur ne se
     declenche jamais. */
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

#zoneListe {
  /* flex-basis a 0 + min-width a 0 plutot qu'une largeur calculee : la
     colonne se partage la place restante par construction, a toute largeur
     de fenetre, et une table large ne la fait pas deborder. */
  flex: 1 1 0;
  min-width: 0;
  /* La zone qui defile, et non la page entiere : l'en-tete reste immobile.
     C'est aussi le conteneur de reference du `position: sticky` de la barre
     de recherche, qui se colle donc en haut de la liste. */
  overflow-y: auto;
  padding: 0 clamp(1rem, 4vw, 3rem) 2.5rem;
}

/* Barre de recherche collante en tete des vignettes : `top: 0` la colle au
   haut de #zoneListe, qui est desormais la zone de defilement. */
.barre-recherche {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
  /* Le fond est indispensable : sans lui les vignettes defileraient en
     transparence sous la barre. Il couvre exactement la colonne de contenu,
     qui est deja en retrait grace au padding de #zoneListe — aucune marge
     negative n'est donc necessaire. */
  background: var(--fond);
  padding: 1rem 0 0.85rem;
  border-bottom: 1px solid var(--bord);
}
.barre-recherche .recherche { margin: 0; flex: 1 1 320px; max-width: 520px; }
/* Tout replier puis Nouvelle recette, colles au bord droit — y compris quand
   la barre passe sur deux lignes sur telephone, d'ou la marge automatique. */
.barre-commandes { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* -- vignettes de role (modele des Epics du Kanban) ---------------------- */

.role-carte {
  margin-top: 1rem;
  background: var(--carte);
  border: 1px solid var(--bord);
  border-radius: 12px;
  overflow: hidden;
}

.role-entete { border-bottom: 1px solid var(--bord); }
.role-carte.replie .role-entete { border-bottom: 0; }

.role-bascule {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 14px;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-lg);
  color: var(--texte);
  text-align: left;
  cursor: pointer;
}
.role-bascule:hover { background: var(--fond); }

.chevron { font-size: var(--fs-sm); color: var(--texte-doux); width: 12px; }
.role-titre { font-weight: 500; }
.role-compte {
  margin-left: auto;
  font-size: var(--fs-md);
  color: var(--texte-doux);
  background: var(--fond);
  border: 1px solid var(--bord);
  border-radius: 999px;
  padding: 1px 10px;
}

.role-contenu { overflow: hidden; padding: 4px 0; }
.role-contenu .liste { margin: 0; }
.role-contenu .liste tbody tr:last-child td { border-bottom: 0; }

/* -- vignettes de recette ------------------------------------------------ */

.grille-recettes {
  display: grid;
  /* auto-fill + minmax plutot qu'un nombre de colonnes fixe : la colonne de
     gauche change de largeur quand on deplace la poignee du panneau, la
     grille doit suivre sans reglage. */
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px;
  padding: 12px 14px;
}

.recette-vignette {
  display: flex;
  flex-direction: column;
  background: var(--fond);
  border: 1px solid var(--bord);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: transform 0.1s ease, border-color 0.1s ease;
}
.recette-vignette:hover {
  transform: translateY(-2px);
  border-color: var(--accent);
}
.recette-vignette:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.vignette-photo {
  display: block;
  background: var(--carte);
  border-bottom: 1px solid var(--bord);
}
/* Le ratio est pose sur l'IMAGE, pas sur .vignette-photo qui l'entoure.
   Pose sur le parent — un flex item de .recette-vignette (colonne) — sa
   hauteur se resolvait via `height: 100%` sur l'enfant, un pourcentage qui
   exige une hauteur DEFINIE ; faute de l'obtenir avant que l'aspect-ratio du
   parent n'intervienne dans le calcul du flex-basis (`auto` par defaut),
   Chrome retombait sur la hauteur NATURELLE du fichier image pendant ce
   calcul — une photo portrait de 180x320 gonflait la vignette a 536 px de
   haut, quand Firefox appliquait le ratio sans detour. Reproduit et confirme
   par mesure (03/09) ; corrige comme .photo-recette et .fiche-photo, qui
   posent deja le ratio sur l'img elle-meme et n'ont jamais montre le bug. */
.vignette-photo img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  display: block;
}
/* L'image par defaut est un pictogramme : l'etirer serait laid, on la
   centre a taille reduite au lieu de la recadrer. */
.vignette-photo img.sans-photo { object-fit: contain; padding: 14px; opacity: 0.65; }

.vignette-corps {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 9px 11px 11px;
}

.vignette-titre {
  /* Meme taille que .plat dans le planning : c'est le MEME titre de recette
     des deux cotes de l'ecran (15/08). */
  font-size: var(--fs-lg);
  font-weight: 500;
  line-height: var(--lh-titre);
}

.vignette-temps {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-size: var(--fs-sm);
  color: var(--texte-doux);
}
.temps-etiquette { text-transform: uppercase; letter-spacing: 0.04em; font-size: var(--fs-xs); }

.vignette-marques { display: flex; flex-wrap: wrap; gap: 4px; }
.vignette-marques .badge { font-size: var(--fs-xs); padding: 1px 7px; }
.role-vide {
  margin: 0;
  padding: 12px 14px;
  font-size: var(--fs-md);
  font-style: italic;
  color: var(--texte-doux);
}

#poignee {
  flex: 0 0 6px;
  cursor: col-resize;
  background: var(--bord);
  border: 0;
}
#poignee:hover, #poignee:focus-visible {
  background: var(--accent);
  outline: none;
}

#panneauLateral {
  /* Moitie de la largeur par defaut. La poignee peut ensuite la modifier, et
     la valeur reglee est memorisee — auquel cas le script la reapplique en
     style inline, qui l'emporte sur cette regle. */
  width: 50%;
  /* Sans ce flex-shrink, #mainLayout comprime le panneau sous sa largeur
     demandee des que la fenetre manque de place — une largeur reglee a la
     souris doit refuser de retrecir toute seule. */
  flex-shrink: 0;
  border-left: 1px solid var(--bord);
  background: var(--carte);
  /* Padding horizontal seulement : la barre de semaine collante doit toucher
     le haut du panneau, sinon un bandeau vide defilerait au-dessus d'elle. */
  padding: 0 1.25rem 1.5rem;
  /* Le panneau defile independamment de la liste. */
  overflow-y: auto;
}

/* Chaque semaine est son propre bloc : c'est ce qui borne le `sticky` de son
   separateur. Sans ce conteneur, les trois separateurs se colleraient au meme
   endroit et se superposeraient. */
.semaine-bloc { position: relative; }
.semaine-bloc + .semaine-bloc { margin-top: 1.5rem; }

/* Separateur de semaine, fixe pendant que sa propre semaine defile. */
.barre-semaine {
  position: sticky;
  top: 0;
  z-index: 5;
  /* Deux lignes empilees, chacune tenant ses deux bouts : la semaine et son
     score, puis les pastilles et les Courses. En une seule rangee, les
     pastilles s'inseraient entre le titre et le score, qui n'etait plus au
     bord (Guillaume, 05/09). */
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--carte);
  padding: 1rem 0 0.85rem;
  border-bottom: 1px solid var(--bord);
}
/* `align-items: center` et non `baseline` : les feuilles et le bouton sont
   des boites, pas du texte, et se caleraient de travers. */
.barre-semaine-ligne {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
/* Les pastilles s'alignent a gauche et passent a la ligne entre elles
   plutot que de pousser le bouton Courses hors du bandeau. */
.semaine-pastilles {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
/* « À régénérer » est un bouton dans un <form>. Ce formulaire restait un
   bloc : son bouton s'y posait sur une LIGNE DE TEXTE, dont l'interligne du
   document (1,55) le decalait d'un pixel vers le bas. Un pixel se voit quand
   deux pastilles se cotoient. */
.semaine-pastilles form { display: flex; margin: 0; }
/* Regénérer et Courses, a droite du bandeau, ne se separent pas et ne se
   compriment pas : ce sont les pastilles qui passent a la ligne. */
.semaine-commandes { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.semaine-commandes form { display: flex; margin: 0; }
.semaine-periode { font-size: var(--fs-base); }
/* Gras franc, et non le 500 utilise ailleurs dans l'interface : l'annee doit
   se detacher nettement du reste du libelle. */
.semaine-periode strong { font-weight: 700; }
.semaine-plage { font-size: var(--fs-sm); font-style: italic; color: var(--texte-doux); }
.barre-semaine .bouton { padding: 4px 10px; font-size: var(--fs-md); }

/* Dans le panneau, la grille dispose de moitie moins de place que sur la page
   semaine : les colonnes se resserrent plutot que de deborder. */
#panneauLateral .grille { table-layout: fixed; }
#panneauLateral .col-jour { width: 84px; }
/* Le padding de la cellule vit sur .cellule-interieur depuis que le pied est
   en colonne flex : le poser aussi sur le td (regle historique) CUMULAIT les
   deux — pres du double d'espace au bord, releve par Guillaume. */
#panneauLateral .cellule-interieur { padding: 7px 8px 6px; }
/* Pas de reduction sur .plat : depuis que le planning ne vit QUE dans ce
   panneau (la page /semaine plein ecran a disparu le 12/08), cette regle
   etait la seule chose qui empechait le titre de rejoindre la taille de
   .vignette-titre — corrige le 15/08 a la demande de Guillaume. */
#panneauLateral .badge { font-size: var(--fs-xs); padding: 1px 6px; }
#panneauLateral .pourquoi { font-size: var(--fs-xs); }


/* Pendant le glisser : pas de selection de texte parasite, et le curseur
   col-resize reste affiche meme quand la souris sort de la poignee. */
body.redimensionnement { user-select: none; cursor: col-resize; }

/* -- modale de recette --------------------------------------------------- */

.modale-fond {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2.5vh 1rem;
  background: rgba(0, 0, 0, 0.28);
  backdrop-filter: blur(4px);
}
/* [hidden] ne suffit pas face au display:flex ci-dessus, qui le surclasse. */
.modale-fond[hidden] { display: none; }

.modale {
  display: flex;
  flex-direction: column;
  width: min(880px, 100%);
  /* Hauteur bornee et corps defilant : un formulaire long ne doit pas sortir
     de l'ecran, l'en-tete et le bouton de fermeture restant atteignables. */
  max-height: 95vh;
  background: var(--fond);
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  animation: modaleApparition 0.2s ease-out;
}

@keyframes modaleApparition {
  from { opacity: 0; transform: scale(0.97); }
  to { opacity: 1; transform: scale(1); }
}

.modale-entete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.25rem;
  border-bottom: 1px solid var(--bord);
  background: var(--carte);
  border-radius: 12px 12px 0 0;
}
/* Le titre pousse les commandes et la croix a droite. Il s'enroule sur deux
   lignes plutot que d'etre coupe : un titre de recette peut etre long, et
   « Barbecue chipolatas et… » ne dit plus quel plat on regarde. */
.modale-entete h2 {
  margin: 0;
  margin-right: auto;
  min-width: 0;
  font-size: var(--fs-xl);
  font-weight: 500;
}
.modale-commandes { display: flex; flex: 0 0 auto; gap: 8px; }
.modale-commandes .bouton { padding: 4px 12px; font-size: var(--fs-md); }

/* -- fiche de recette (lecture) ------------------------------------------ */

/* La photo pleine largeur, en 16/10 comme partout ailleurs, et sans cadre :
   c'est l'image qui ouvre la lecture, pas une carte de plus. */
.fiche-photo img {
  display: block;
  /* Bornee sur ecran large : pleine largeur, la photo occupait toute la
     hauteur visible et repoussait les ingredients hors de vue. */
  width: 100%;
  max-width: 420px;
  margin-inline: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 12px;
  margin-bottom: 1.25rem;
  background: var(--fond);
}
/* Une seule ligne de metadonnees, separee par des points mediaux : quatre
   petites cartes pour quatre nombres feraient un tableau de bord. */
.fiche-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: 0;
  font-size: var(--fs-base);
  color: var(--texte-doux);
}
.fiche-meta span:first-child { color: var(--texte); font-weight: 500; }
.fiche-meta span + span::before { content: "· "; }
.fiche-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 0; }
.fiche-ingredients { margin: 0; padding: 0; list-style: none; }
.fiche-ingredients li {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 5px 0;
  border-bottom: 1px solid var(--bord);
}
.fiche-ingredients li:last-child { border-bottom: 0; }
/* Largeur fixe pour la mesure : les quantites s'alignent en colonne et se
   balaient d'un coup d'oeil, comme dans la liste de courses. */
.fiche-mesure {
  flex: 0 0 88px;
  color: var(--texte-doux);
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
}
.fiche-aliment { flex: 1 1 auto; min-width: 0; }

.modale-fermer {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border: 1px solid var(--bord-fort);
  border-radius: var(--rayon);
  background: var(--carte);
  color: var(--texte-doux);
  font-size: var(--fs-xl);
  line-height: var(--lh-icone);
  cursor: pointer;
}
.modale-fermer:hover { color: var(--texte); border-color: var(--texte-doux); }

.modale-corps {
  overflow-y: auto;
  padding: 1rem 1.25rem 1.25rem;
}
/* Dans la modale, les blocs du formulaire ne recreent pas une seconde carte
   par-dessus celle de la modale. */
.modale-corps .bloc { max-width: none; }

/* -- comptes : pages de connexion --------------------------------------- */

/* `page-liste` interdit le defilement du document pour que les deux panneaux
   defilent seuls. Les pages de compte n'ont pas de panneau : elles reprennent
   le comportement normal d'une page. */
body.page-compte {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.carte-compte {
  width: 100%;
  max-width: 420px;
  padding: clamp(1.25rem, 4vw, 2rem);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  background: var(--carte);
}

/* Sur la carte de connexion, l'ecusson est centre au-dessus du titre : la
   carte est trop etroite pour une ligne logo + titre comme dans l'en-tete. */
.entete-compte { margin-bottom: 1.25rem; text-align: center; }
.entete-compte .sous-titre { margin-top: 6px; }
.logo-compte { width: 62px; height: 62px; margin-bottom: 10px; }

.formulaire-compte { display: flex; flex-direction: column; gap: 0.9rem; }

/* TOUT ce qui suit est confine a `.carte-compte`. Sans ce prefixe, `.champ`
   et `.message` — declares plus haut pour le formulaire de recette — se
   feraient ecraser ici : ces regles-ci viennent apres dans le fichier, et a
   specificite egale c'est la derniere qui gagne. Les champs de la modale de
   recette y avaient perdu leur fond et leurs arrondis, et ses messages
   d'erreur etaient passes du texte ambre a un pave rouge plein. */
.carte-compte .champ { display: flex; flex-direction: column; gap: 4px; }
.carte-compte .champ > span { font-size: var(--fs-base); color: var(--texte-doux); }
.carte-compte .champ > small { font-size: var(--fs-sm); color: var(--texte-doux); }
.carte-compte .champ input {
  padding: 9px 11px;
  border: 1px solid var(--bord-fort);
  border-radius: 8px;
  background: var(--fond);
  color: var(--texte);
  font: inherit;
}
.carte-compte .champ input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.bouton.large { width: 100%; justify-content: center; text-align: center; }

/* Sur ces pages, le message est la seule chose a lire : il est plein. Ailleurs
   — dans la modale — `.message` reste la ligne de texte discrete definie plus
   haut, et `.message.succes` juste au-dessous lui donne sa couleur. */
.carte-compte .message {
  margin: 0 0 1rem;
  padding: 9px 11px;
  border-radius: 8px;
  font-size: var(--fs-base);
}
.carte-compte .message.erreur { background: var(--danger); color: #fff; }
@media (prefers-color-scheme: dark) {
  .carte-compte .message.erreur { color: #2a0d0d; }
}
.carte-compte .message.succes { background: var(--accent-doux); color: var(--accent); }

.message.succes { color: var(--accent); }


.liens-compte {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  margin: 1.25rem 0 0;
  font-size: var(--fs-base);
}
.liens-compte a { color: var(--accent); }

/* -- comptes : pastille de l'en-tete ------------------------------------- */

.compte { position: relative; }
/* Le marqueur par defaut de <summary> (le petit triangle) n'a rien a faire
   dans une pastille ronde. Il faut le retirer des DEUX facons : WebKit
   n'ecoute que la pseudo-classe, les autres que `list-style`. */
.compte > summary { list-style: none; }
.compte > summary::-webkit-details-marker { display: none; }

.avatar-compte {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--bord-fort);
  border-radius: 50%;
  background: var(--carte);
  color: var(--texte-doux);
  cursor: pointer;
}
.avatar-compte:hover { border-color: var(--accent); color: var(--accent); }
.avatar-compte:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.avatar-compte svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}
.compte[open] .avatar-compte { border-color: var(--accent); color: var(--accent); }

.panneau-compte {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 240px;
  padding: 12px;
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  background: var(--carte);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.16);
}
.panneau-compte .identite {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 0 4px;
  font-size: var(--fs-base);
}
.panneau-compte .identite span {
  color: var(--texte-doux);
  font-size: var(--fs-md);
  /* Une adresse longue ne doit pas etirer le menu au-dela de l'ecran. */
  overflow-wrap: anywhere;
}
.panneau-compte form { margin: 0; }

/* -- lignes etiquette + champ (modales Profil ET Recette) ----------------- */

/* Une ligne = etiquette a gauche, champ a droite sur le reste de la largeur.
   Nee dans la modale Profil, reprise par la modale Recette (Titre, Tags) :
   les deux formulaires doivent garder le meme alignement. Identifiant et
   Nom complet (lecture seule, voir le gabarit du profil) reprennent la meme
   ligne : rien ne doit visuellement trahir qu'ils ne sont pas modifiables
   avant d'essayer d'y taper. */
.profil-ligne {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 10px;
}
/* PAS de :last-of-type pour annuler la derniere marge : « Nom complet » est
   la derniere div de la section (le formulaire est un form), la regle tombait
   sur elle et sa ligne venait se coller a celle d'Email. */

.profil-etiquette {
  flex: 0 0 160px;
  font-size: var(--fs-md);
  color: var(--texte-doux);
}

.profil-ligne input {
  flex: 1 1 auto;
  min-width: 0;      /* un input ne retrecit pas sous son contenu par defaut */
}

.profil-ligne input[readonly] { cursor: default; }

/* Bouton pose DANS la grille des champs, a droite de la derniere zone de
   saisie de sa ligne. `end` l'aligne sur le BAS des zones et non sur le haut
   de leur etiquette ; `span 2` lui donne de quoi tenir, une colonne de la
   grille (145px) etant plus etroite que son libelle. */
.profil-bouton-ligne {
  grid-column: span 2;
  align-self: end;
  justify-self: start;
}

/* -- zone Foyer de la modale Profil -------------------------------------- */

.vignettes-foyer {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 10px;
  margin-bottom: 12px;
}

.vignette-membre {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 12px;
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  background: var(--fond);
  font-size: var(--fs-md);
}
/* Les actions occupent le coin superieur droit : le nom leur laisse la place
   plutot que de passer dessous. */
/* 102 px : trois icones de 28 px et leurs deux ecarts, depuis que la cle
   de l'acces s'est ajoutee au crayon et a la corbeille (07/09). */
.vignette-membre strong { font-size: var(--fs-base); padding-right: 102px; }
.vignette-membre .membre-detail {
  color: var(--texte-doux);
  overflow-wrap: anywhere;
}
/* La cle d'un acces ouvert se colore : d'un coup d'oeil, qui peut se
   connecter et qui ne le peut pas. */
.icone-vignette.membre-acces.ouvert {
  color: var(--accent);
  border-color: var(--accent);
}
/* Le retrait est destructif : rouge au survol, comme la corbeille. */
#btn-retirer-acces:hover { color: var(--danger); border-color: var(--danger); }
.vignette-membre .pastille { align-self: flex-start; margin: 2px 0 0; }

.vignette-membre-actions {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  gap: 6px;
}

.icone-vignette {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--bord-fort);
  border-radius: 8px;
  background: var(--carte);
  color: var(--texte-doux);
  cursor: pointer;
}
.icone-vignette:hover { color: var(--accent); border-color: var(--accent); }
/* Le rouge est reserve au destructif — mais seulement au survol : une rangee
   de corbeilles rouges en permanence crierait plus fort que le contenu. */
.icone-vignette.membre-supprimer:hover,
.icone-vignette.ingredient-supprimer:hover,
.icone-vignette.rayon-supprimer:not(:disabled):hover {
  color: var(--danger);
  border-color: var(--danger);
}
.icone-vignette svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* La fiche (creation/modification), sous les vignettes, separee d'un filet. */
#profil-membre {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--bord);
}
#profil-membre h3 { margin: 0 0 10px; font-size: var(--fs-lg); font-weight: 500; }
#profil-membre .message { margin: 0 0 10px 174px; }

.case-membre {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-base);
  cursor: pointer;
}
/* `.profil-ligne input` etire les champs sur la ligne : une case a cocher
   n'a pas a s'etirer. */
.case-membre input[type="checkbox"] {
  flex: 0 0 auto;
  width: auto;
}
.aide-case { margin: 4px 0 0; font-size: var(--fs-sm); }
/* La case posee sous la grille des parametres : elle n'est pas dans une
   .profil-ligne, il lui faut son propre air au-dessus de l'aide. */
.case-parametre { margin-bottom: 10px; }

/* La grille de presence : l'etiquette s'aligne sur le HAUT de la table, pas
   sur son centre — le milieu vertical d'un tableau ne designe rien. */
.profil-ligne-grille { align-items: flex-start; }
.profil-ligne-grille .profil-etiquette { padding-top: 6px; }

.table-presence { border-collapse: collapse; }
.table-presence th {
  padding: 2px 4px;
  font-size: var(--fs-sm);
  font-weight: 400;
  color: var(--texte-doux);
  text-align: center;
}
.table-presence tbody th { text-align: right; padding-right: 8px; }
.table-presence td { padding: 2px; }

.case-presence {
  width: 34px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--bord-fort);
  border-radius: 8px;
  background: var(--carte);
  font-size: var(--fs-md);
  line-height: var(--lh-icone);
  cursor: pointer;
}
.case-presence:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.case-presence[data-etat="present"] {
  background: var(--accent-doux);
  border-color: var(--accent);
  color: var(--accent);
}
.case-presence[data-etat="ecole"] {
  background: var(--alerte-doux);
  border-color: var(--alerte);
}
.case-presence[data-etat="absent"] { color: var(--texte-doux); }

.legende-presence {
  margin: 6px 0 0;
  font-size: var(--fs-sm);
  color: var(--texte-doux);
}

/* -- modale Referentiel --------------------------------------------------- */

#filtre-aliments { max-width: 320px; margin-bottom: 10px; }

/* La table defile DANS la modale : 96 aliments ne doivent pas pousser le
   bloc des rayons hors de portee. */
.table-referentiel-defilante {
  max-height: 45vh;
  overflow-y: auto;
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
}
.table-referentiel { width: 100%; border-collapse: collapse; }
.table-referentiel thead th {
  position: sticky;
  top: 0;
  background: var(--carte);
  border-bottom: 1px solid var(--bord-fort);
  padding: 6px 10px;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--texte-doux);
  text-align: left;
}
.table-referentiel tbody th {
  padding: 4px 10px;
  font-size: var(--fs-md);
  font-weight: 400;
  text-align: left;
  overflow-wrap: anywhere;
}
.table-referentiel td { padding: 3px 6px; }
/* La case du bonus : centree sous son en-tete, et assez large pour qu'on la
   vise au doigt sans elargir la colonne. */
.colonne-bonus { text-align: center; }
.aliment-bonus { width: 18px; height: 18px; cursor: pointer; accent-color: var(--accent); }
.table-referentiel select { font-size: var(--fs-md); padding: 4px 6px; }
/* Le poids d'une piece/tranche : un petit nombre, pas une phrase. */
.table-referentiel .aliment-poids {
  width: 64px;
  font-size: var(--fs-md);
  padding: 4px 6px;
}
.table-referentiel tbody tr:nth-child(even) { background: var(--fond); }

.ligne-rayon {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
}
.ligne-rayon .rayon-nom, .ligne-rayon #nouveau-rayon { max-width: 260px; }
.ligne-rayon .icone-vignette:disabled {
  opacity: 0.35;
  cursor: default;
}
.ligne-rayon .icone-vignette:disabled:hover {
  color: var(--texte-doux);
  border-color: var(--bord-fort);
}
.rayon-effectif { font-size: var(--fs-sm); color: var(--texte-doux); }
.ligne-rayon-ajout { margin-top: 10px; }

/* Le bouton d'enregistrement partage la ligne de la date de naissance : sa
   largeur propre ne doit jamais empieter sur celle du champ. */
.profil-ligne .bouton { flex: 0 0 auto; }

/* Le pied du formulaire de recette reserve une marge basse pour la page
   pleine ; empilee dans la modale, elle creuse un trou entre les deux blocs. */
.modale-corps .pied-formulaire { margin-bottom: 0; }

/* Les commandes sont PREMIERES dans le balisage — le portrait les fige tout
   en haut. Sur ecran large elles retrouvent leur place, en bas : c'est le
   seul role de cette colonne flex, dont les autres enfants gardent l'ordre
   du document. */
.formulaire-recette { display: flex; flex-direction: column; }
.formulaire-recette .pied-formulaire { order: 1; margin-top: 1rem; }

/* La carte d'une recette : le lien de la vignette et la bascule Frigo cote
   a cote. Le bouton est en dehors du lien — imbriquer deux elements
   interactifs les rend incommandables au clavier — et pose par-dessus le
   coin bas droit, exactement la ou l'icone figure dans les autres listes. */
.carte-recette { position: relative; display: flex; }
.carte-recette > .recette-vignette { flex: 1 1 auto; min-width: 0; }

.bascule-congelation,
.bascule-frigo {
  position: absolute;
  right: 0;
  bottom: 0;
  /* 36 x 40 px de cible pour 18 px de dessin : au doigt, une pastille de 30 px se
     rate une fois sur trois. La cible deborde dans la marge de la carte, ou
     il n'y a rien d'autre a toucher. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--zone-bleue);
  cursor: pointer;
}
.bascule-congelation.eteint,
.bascule-frigo.eteint { color: var(--texte-doux); }
.bascule-congelation:hover,
.bascule-frigo:hover { background: var(--carte); }
.bascule-congelation:focus-visible,
.bascule-frigo:focus-visible {
  outline: 2px solid var(--zone-bleue);
  outline-offset: 1px;
}
.bascule-congelation svg,
.bascule-frigo svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Le flocon se pose juste a gauche du frigo : deux cibles jointives, sans
   chevauchement (06/10). */
.bascule-congelation { right: 36px; }

/* -- liste de courses ---------------------------------------------------- */

/* Le bandeau ne s'affiche que quand le planning a bouge depuis la photo. Il
   PROPOSE, il n'applique pas : une liste qui se reorganiserait toute seule
   au milieu d'un magasin serait inutilisable. */
.courses-bandeau {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: var(--rayon);
  background: var(--alerte-doux);
  color: var(--alerte);
  font-size: var(--fs-md);
}

.courses-resume { margin: 0; }

/* L'entete des dates, collant tout en haut du corps de la modale (24/09).
   Meme calage que la barre du formulaire recette : `top: -1rem` rattrape le
   padding haut du corps, les marges negatives l'etendent jusqu'a ses bords
   lateraux. Fond opaque, sinon les lignes defilent au travers. */
.courses-entete {
  position: sticky;
  top: -1rem;
  z-index: 2;
  margin: 0 -1.25rem 16px;
  padding: 6px 1.25rem 8px;
  background: var(--fond);
}
.courses-masquer { margin-top: 6px; font-size: var(--fs-sm); color: var(--texte-doux); }

/* Masquer les coches : un article pris s'efface, et un rayon tout pris avec
   lui. `.sursis` le garde deux secondes a sa place apres l'appui (courses.js)
   — de quoi rattraper une coche de travers. */
.courses.masquer-pris .courses-article[data-etat="pris"]:not(.sursis) { display: none; }
.courses.masquer-pris .courses-rayon:not(:has(.courses-article:is([data-etat="a_prendre"], .sursis))) {
  display: none;
}

.courses-rayon { margin-bottom: 18px; }

/* Collant DANS le corps de la modale, qui est la zone defilante : on sait
   toujours dans quel rayon on est. Fond opaque obligatoire, sinon les lignes
   defilent au travers — meme regle que les en-tetes du planning. */
.courses-rayon-titre {
  position: sticky;
  /* Sous l'entete collant des dates, dont courses.js pose la hauteur dans
     --haut-entete-courses. Le -1rem : l'offset se mesure depuis le bord
     INTERIEUR du corps de la modale, dont le padding haut est de 1rem —
     `top: 0` laissait une bande de 16 px ou les articles defilaient
     au-dessus du titre (Guillaume, 24/09). */
  top: calc(var(--haut-entete-courses, 0px) - 1rem);
  z-index: 1;
  margin: 0 0 6px;
  padding: 6px 0;
  /* --fond et non --carte : la zone defilante est le corps de la modale, qui
     herite du fond creme de `.modale`. Un fond blanc laisserait un rectangle
     visible sous le titre — meme piege que le bandeau des vignettes (15/08).
     Opaque dans tous les cas : sinon les lignes defilent au travers. */
  background: var(--fond);
  border-bottom: 1px solid var(--bord);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--texte-doux);
}

.courses-articles { margin: 0; padding: 0; list-style: none; }

.courses-article { border-bottom: 1px solid var(--bord); }
.courses-article:last-child { border-bottom: 0; }

.courses-ligne {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
}

.courses-nom {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-base);
  line-height: var(--lh-titre);
}

/* Un plat d'aujourd'hui le demande : a prendre en premier (05/10). */
.courses-nom.du-jour { font-weight: 700; }

.courses-quantite {
  flex: none;
  font-size: var(--fs-base);
  color: var(--texte-doux);
  white-space: nowrap;
  /* Chiffres de meme chasse : la colonne de quantites s'aligne et se balaie
     d'un coup d'oeil, ce qui est tout l'interet de les mettre a droite. */
  font-variant-numeric: tabular-nums;
}

/* Ce qui est pris s'efface sans disparaitre — et descend au bas de son rayon,
   ordre calcule cote serveur ET rejoue par courses.js apres un clic. */
.courses-article:not([data-etat="a_prendre"]) .courses-nom,
.courses-article:not([data-etat="a_prendre"]) .courses-quantite {
  color: var(--texte-doux);
  text-decoration: line-through;
}

/* La case a deux etats. Un seul SVG : la coche est dessinee en permanence,
   l'etat courant decide si elle se voit. */
.courses-etat {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--texte-doux);
  cursor: pointer;
}
.courses-etat svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.courses-article[data-etat="a_prendre"] .marque-pris { display: none; }
.courses-article[data-etat="pris"] .courses-etat { color: var(--accent); }

.courses-deplier {
  flex: none;
  padding: 4px 6px;
  border: 0;
  background: none;
  cursor: pointer;
  line-height: var(--lh-icone);
}
.courses-deplier[aria-expanded="true"] .chevron { transform: rotate(180deg); }
.courses-deplier .chevron { display: inline-block; }

.courses-detail {
  padding: 4px 0 12px 40px;
  font-size: var(--fs-sm);
  color: var(--texte-doux);
}
.courses-origines { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 0 0 10px; }
.courses-origine { white-space: nowrap; }

.courses-actions { display: flex; align-items: center; justify-content: flex-end; }

.courses-ajout { display: flex; gap: 8px; margin-top: 18px; }
.courses-ajout input { flex: 1; min-width: 0; }

/* -- congelateur (08/10) ------------------------------------------------- */

/* Au dessin de la liste de courses (Guillaume) : le plat a gauche, les
   portions a droite en chiffres de meme chasse, la date limite dessous. */
.congelateur-resume { margin: 0 0 10px; }
.congelateur-boites { margin: 0; padding: 0; list-style: none; }
.congelateur-boite { border-bottom: 1px solid var(--bord); }
.congelateur-boite:last-child { border-bottom: 0; }
.congelateur-ligne { display: flex; align-items: center; gap: 10px; padding: 7px 0; }
.congelateur-plat { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.congelateur-titre { font-size: var(--fs-base); line-height: var(--lh-titre); }
.congelateur-limite { font-size: var(--fs-sm); color: var(--texte-doux); }
/* A une semaine ou moins, ou deja passee : en rouge, c'est le signal. */
.congelateur-limite.bientot { color: var(--danger); font-weight: 600; }
.congelateur-pour { font-size: var(--fs-sm); color: var(--texte-doux); }
.congelateur-portions {
  flex: none;
  font-size: var(--fs-base);
  color: var(--texte-doux);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.congelateur-detail {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 16px;
  padding: 4px 0 12px;
  font-size: var(--fs-sm);
  color: var(--texte-doux);
}
.congelateur-detail[hidden] { display: none; }
.congelateur-date { flex: 1 1 auto; }
.congelateur-reglage { display: flex; align-items: center; gap: 12px; }
.congelateur-reglage .reglage-bouton { width: 40px; height: 40px; }

/* Le bouton du bandeau et sa pastille, posee sur l'angle comme le stock
   sur le frigo : rouge, c'est une alerte. */
.congelateur-lien { position: relative; }
.pastille-congel {
  position: absolute;
  top: -8px;
  right: -8px;
  min-width: 17px;
  padding: 0 3px;
  border: 2px solid var(--fond);
  border-radius: 999px;
  background: var(--danger);
  color: #fff;
  font-size: var(--fs-xs);
  line-height: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* -- mobile : deux vues exclusives sous le seuil ------------------------- */

/* La barre d'onglets n'existe que sous le seuil mobile. */
#onglets-mobile { display: none; }

/* Sous 720px, l'ecran devient deux vues exclusives — Planning et Recettes —
   basculees par la barre d'onglets du bas (choix de Guillaume, 17/08, le
   planning en vue d'arrivee). Avant cela, tout s'empilait dans une page de
   19 000 px ou le planning commencait au quinzieme ecran. L'ecran large ne
   change pas d'un pixel. */
@media (max-width: 720px) {
  /* Le cadre de l'ecran large est conserve : la page ne defile pas, la vue
     visible defile en interne — c'est ce qui garde les barres de semaine
     collantes et l'en-tete immobile. Une seule vue a la fois, donc pas de
     defilements imbriques (le probleme qui avait impose l'empilement en
     page defilante de l'ancienne version de ce bloc). 100dvh et non 100vh :
     Chrome Android escamote sa barre d'adresse en defilant, dvh suit la
     hauteur reellement disponible. */
  body.page-liste { height: 100dvh; }

  /* 160 px d'etiquette, c'est la moitie d'un ecran en portrait : le champ
     n'a plus de place. Chaque formulaire descend a la largeur de SON plus
     long intitule, mesuree au navigateur — les mots restent entiers, tout
     le reste va au champ. Profil : « Date de naissance » fait 107 px.
     Recette : « Titre » et « Tags » n'en demandent que 46. */
  .profil-etiquette { flex-basis: 112px; }
  #formulaire .profil-etiquette { flex-basis: 46px; }

  /* Modale Profil : l'intitule passe AU-DESSUS du champ (Guillaume, 04/09).
     Meme reduites a 112 px, les etiquettes ne laissaient pas de quoi
     afficher un champ entier dans la modale et les zones de saisie
     debordaient. `flex-wrap` plutot qu'une colonne : seule l'etiquette
     prend toute la ligne, ce qui la suit se partage la suivante — la date
     de naissance garde donc son bouton « Enregistrer » a cote d'elle,
     disposition voulue au cadrage. Le formulaire de recette n'est pas
     concerne : ses intitules tiennent en 46 px. */
  .formulaire-profil .profil-ligne { flex-wrap: wrap; gap: 4px 10px; }
  .formulaire-profil .profil-etiquette { flex-basis: 100%; }
  /* Les etiquettes VIDES ne servaient qu'a decaler une case a cocher ou un
     bouton sous les champs : empilees, elles ajouteraient une ligne blanche
     avant chacun. */
  .formulaire-profil .profil-etiquette:empty { display: none; }
  .formulaire-profil .profil-ligne-grille .profil-etiquette { padding-top: 0; }
  #formulaire .aide-sous-ligne { margin-left: 60px; }

  /* En-tete compacte : le sous-titre disparait, le logo et les boutons
     retrecissent, les commandes s'enroulent sous le titre. */
  .entete-principale { padding: 0.6rem 0.9rem; }
  .entete-haut { gap: 0.5rem; align-items: center; }
  .logo-entete { width: 32px; height: 32px; }
  .entete-principale h1 { font-size: var(--fs-xl); }
  .sous-titre { display: none; }
  .nav { gap: 6px; }
  .nav .bouton { padding: 5px 9px; font-size: var(--fs-md); }

  /* Les deux vues. La classe vue-recettes est posee par onglets.js. */
  body:not(.vue-recettes) #zoneListe { display: none; }
  body.vue-recettes #panneauLateral { display: none; }
  #poignee { display: none; }
  #panneauLateral {
    /* La largeur reglee a la souris est memorisee en style inline par
       panneau.js : !important pour la neutraliser ici. */
    width: auto !important;
    flex: 1 1 auto;
    min-width: 0;
    border-left: 0;
    padding: 0 0.9rem 1rem;
  }
  #zoneListe { padding: 0 0.9rem 1rem; }

  /* La grille du planning s'empile : une carte par repas, le nom du jour en
     separateur, plus d'en-tetes de colonnes. */
  .grille, .grille tbody, .grille tr, .grille td, .grille th { display: block; width: auto; }
  .grille thead { display: none; }
  .grille tr { margin-bottom: 1.1rem; }
  .col-jour { width: auto; }
  /* La colonne du jour doit reprendre TOUTE la largeur une fois empilee.
     `#panneauLateral .col-jour { width: 84px }` de l'ecran large l'emportait
     par sa specificite d'identifiant, quel que soit l'ordre : l'aplat du jour
     courant s'arretait au quart de l'ecran (Guillaume, 04/09). */
  #panneauLateral .col-jour { width: auto; }
  .grille tbody th.col-jour { padding: 2px 0 6px; }
  /* Empilee, la date n'est plus le bout gauche d'une ligne mais une bande a
     elle : son aplat s'arrondit des quatre cotes et se donne un retrait, sans
     quoi le texte collerait au bord de la couleur. */
  .grille tr.aujourdhui th.col-jour {
    border-radius: var(--rayon);
    padding: 6px 10px 8px;
    /* Plus de lisere a gauche : sur une bande pleine largeur il debordait de
       l'angle arrondi, et l'aplat suffit a designer le jour. */
    border-left: none;
  }
  /* En affichage bloc, height:1px cesserait d'etre un minimum de cellule
     de tableau et ecraserait la vignette. */
  .cellule { margin-bottom: 8px; height: auto; }
  /* L'etiquette Midi/Soir de chaque carte remplace les en-tetes masques. */
  .cellule[data-repas]::before {
    content: attr(data-repas);
    display: block;
    padding: 6px 8px 0;
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--texte-doux);
  }

  /* Les commandes se figent tout en haut de la modale, sous le titre et
     au-dessus de l'indice (Guillaume, 05/09) : sur un telephone, le pied du
     formulaire est a plusieurs ecrans de distance, et enregistrer demandait
     de tout redescendre. Elles sont premieres dans le balisage ; ici on
     leve seulement l'ordre qui les renvoyait en bas. */
  .formulaire-recette .pied-formulaire {
    order: -1;
    position: sticky;
    /* -1rem et non 0 : l'offset se mesure depuis le bord INTERIEUR du corps
       de la modale, donc `top: 0` laissait passer une bande de 16 px — la
       hauteur du padding — ou les champs defilaient au-dessus de la barre. */
    top: -1rem;
    z-index: 3;
    /* Le fond est indispensable : sans lui, les champs defilent au travers.
       Les marges negatives etendent la barre jusqu'aux bords du corps de la
       modale, dont le padding lateral la laisserait sinon flotter. */
    margin: -1rem -1.25rem 1rem;
    padding: 0.7rem 1.25rem;
    background: var(--carte);
    border-bottom: 1px solid var(--bord);
  }

  /* Modale en plein ecran : une fenetre flottante n'a pas de sens quand
     elle couvrirait de toute facon presque tout. */
  .modale-fond { padding: 0; }
  .modale { width: 100%; height: 100%; max-height: none; border-radius: 0; }
  /* Sauf la petite modale des portions : une ligne n'a pas a couvrir
     l'ecran, elle flotte au-dessus du planning (06/09). */
  .modale-fond:has(.reglage-portions) { padding: 2.5vh 1rem; }
  .modale:has(.reglage-portions) {
    width: 100%; height: auto; border-radius: 12px;
  }

  /* Sauf celle des courses, qui EST le troisieme onglet : elle s'arrete
     au-dessus de la barre et la laisse passer devant, pour qu'on en sorte
     comme des deux autres vues. Les autres modales ne changent pas.
     La classe est posee sur <body> par courses.js : la barre d'onglets
     PRECEDE la modale dans le balisage, aucun selecteur de voisinage ne
     pourrait l'atteindre depuis celle-ci. */
  body.courses-ouvertes #onglets-mobile { z-index: 1001; }
  body.courses-ouvertes .modale-fond {
    padding-bottom: calc(58px + env(safe-area-inset-bottom, 0px));
  }

  /* Le menu du compte s'ancrait sur la PASTILLE — `.compte` est en position
     relative — si bien que « left: 0; right: 0 » lui donnait la largeur de
     la pastille : une colonne de 90 px ou l'adresse e-mail tombait une
     lettre par ligne (releve par Guillaume le 02/09). Il s'ancre desormais
     sur l'EN-TETE, qui fait toute la largeur : le menu s'ouvre juste sous
     elle, d'un bord a l'autre, avec les memes marges qu'elle. */
  .entete-principale { position: relative; }
  .compte { position: static; }
  .panneau-compte { left: 0.9rem; right: 0.9rem; min-width: 0; }

  /* La barre d'onglets, COLLEE au bord bas de l'ecran (18/08). Elle etait
     d'abord en flux, dernier membre du cadre 100dvh — mais le clavier
     Android panote la vue pour garder le champ visible, et ce decalage
     survivait parfois a la fermeture : la barre restait juste sous le bord
     de l'ecran (bug releve par Guillaume apres l'edition d'une recette).
     En position fixe, elle est indifferente a tout decalage ; les zones
     defilantes reservent sa hauteur en bas pour qu'elle ne recouvre rien,
     et la modale plein ecran (z-index 1000) passe par-dessus. safe-area :
     l'encoche basse des telephones sans bouton. */
  #onglets-mobile {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 20;
    border-top: 1px solid var(--bord);
    background: var(--carte);
    padding-bottom: env(safe-area-inset-bottom);
  }
  #panneauLateral, #zoneListe {
    padding-bottom: calc(58px + env(safe-area-inset-bottom, 0px));
  }
  .onglet {
    flex: 1;
    padding: 11px 0 12px;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--fs-base);
    color: var(--texte-doux);
  }
  .onglet.actif {
    color: var(--accent);
    font-weight: 600;
    box-shadow: inset 0 2px 0 var(--accent);
  }
}


/* -- choix manuel du plat d'un creneau ----------------------------------- */

/* Les deux commandes du creneau, en haut a droite de la cellule : changer le
   plat, puis le verrouiller. Meme poids visuel que le cadenas — c'est une
   paire, pas une commande principale flanquee d'une seconde. */
.cellule-actions {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
}
.cellule-choix {
  padding: 0 2px;
  font-size: var(--fs-lg);
  line-height: var(--lh-icone);
  text-decoration: none;
  opacity: 0.5;
}
.cellule-choix:hover { opacity: 1; }
.cellule-choix:focus-visible {
  opacity: 1;
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Meme sort que le cadenas d'un repas servi (voir .verrou:disabled). Apres
   le survol, pour le neutraliser. */
.cellule-choix.inactif, .cellule-choix.inactif:hover {
  opacity: 0.25;
  cursor: default;
  filter: grayscale(1);
}

/* Sans survol, une commande a demi effacee ne se revele jamais — et c'est la
   SEULE facon de changer un plat. Au doigt, elle s'affiche donc en plein et
   s'entoure d'une marge de frappe ; la marge negative rend la hauteur prise
   pour que le bandeau titre ne s'ecarte pas. */
@media (hover: none) {
  .cellule-choix {
    opacity: 1;
    padding: 6px 8px;
    margin: -6px -6px -6px 0;
  }
  .cellule-choix.inactif { opacity: 0.25; }
}

/* Un creneau vide n'a pas de titre a aligner : son bandeau garde quand meme
   la commande a droite, a la meme place que dans une cellule pleine. */
.cellule-titre .vide { margin: 0; }

/* La semaine est devenue fausse et une regeneration sait la reparer. Un
   bouton, pas une simple etiquette : le remede est a un clic de l'aveu. */
.pastille.a-regenerer {
  border: 0;
  cursor: pointer;
  background: var(--alerte-doux);
  color: var(--alerte);
  text-transform: none;
}
.pastille.a-regenerer:hover { background: var(--alerte); color: var(--carte); }

/* La liste de la modale : les memes vignettes que le panneau de gauche, mais
   chacune est le bouton de soumission de son formulaire. D'ou la remise a
   zero des styles propres au <button>. */
.choix-barre { margin-bottom: 4px; }
.choix-barre input[type="search"] { flex: 1 1 240px; max-width: 420px; }
.choix-creneau strong { color: var(--texte); }

.choix-grille { padding: 12px 0; }
.choix-vignette {
  font: inherit;
  text-align: left;
  cursor: pointer;
  padding: 0;
}
.choix-vignette[hidden] { display: none; }
/* Le plat deja en place se signale sans se distinguer au point qu'on croie
   ne pas pouvoir le choisir : le reposer est un geste legitime. */
.choix-vignette.en-place { border-color: var(--accent); }
