/* Bazar Solidaire — Catalogue public — styles (mobile-first) — v3.1.2 (identité visuelle) + addendum v1.3
   (panier) + addendum v1.4 (en-tête/héros, catégories homogènes, boîte de dialogue, toast, panier conservé) */

:root {
  --dark: #1A1A1A;
  --orange: #F5A623;
  --cream: #F0EBE0;
  --peche: #F8C5A5;
  --sable: #F7D8A8;
  --sauge: #D9D9C8;
  --bleu-gris: #D1DEE2;
  --terracotta: #F2B193;
  --lavande: #DDD8E5;
}

* { box-sizing: border-box; }
html, body {
  margin: 0;
  padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--cream);
  color: var(--dark);
}
a { text-decoration: none; color: inherit; }
.icon-svg { width: 20px; height: 20px; display: block; }

/* Bandeau identité. REFONTE du 22/08/2026 (9e correction) : le système précédent (panier positionné à droite
   sur la MÊME ligne que le titre, via un espaceur fantôme à gauche) laissait le panier visuellement "à côté
   du logo" — Lébou a demandé que rien ne partage la ligne du logo ni celle du sous-titre. Remplacé par un
   empilement vertical simple : bloc identité (logo+titre+sous-titre, centré, pleine largeur) PUIS, sur une
   ligne à part en dessous, le panier seul aligné à droite (.app-header-cart-row, visible uniquement sur
   Mission/À propos/Ma commande via .is-compact) — élimine tout risque de chevauchement par construction
   (deux lignes distinctes ne peuvent pas se chevaucher), plus besoin de réserver un espace symétrique. */
.app-header {
  background: var(--dark);
  padding: 14px 16px 0;
  text-align: center;
}
/* Bloc identité (logo + titre + sous-titre), aligné sur l'ENSEMBLE monogramme+texte. .app-identity
   (position:relative) est la référence de largeur du sous-titre : seul .app-title-link (son unique enfant
   en flux normal) compte, le sous-titre (position:absolute) ne l'élargit pas — garantit qu'il ne déborde
   jamais à gauche du monogramme ni à droite de "Solidaire", quelle que soit sa taille de police.
   Titre fixé à 36px (ne plus retoucher — demande explicite). Sous-titre 13px→16px (demande explicite,
   l'écart avec le titre 36px paraissait énorme) : marge de largeur disponible large à 36px (~282px pour le
   bloc complet contre ~245px nécessaires au sous-titre à 16px, ~13% de marge), aucun risque de troncature.
   padding-bottom (24px) et top (43px, inchangé, dépend de la hauteur du TITRE pas du sous-titre) recalculés
   pour la nouvelle hauteur de ligne du sous-titre. */
.app-identity { position: relative; display: inline-block; padding-bottom: 24px; }
.app-title-link { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-width: 0; }
.bs-monogram { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; }
.app-title { font-size: 36px; line-height: 1.15; font-weight: 800; letter-spacing: -0.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.app-title .w { color: #ffffff; }
.app-title .o { color: var(--orange); }
.app-subtitle {
  position: absolute; left: 0; right: 0; top: 43px;
  color: #c9c9c9; font-size: 16px; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Variante allégée réservée à l'ACCUEIL uniquement (retour du 22/08/2026, test visuel demandé) — classe
   posée par JS (toggleEncartAccroche(), app.js) sur <body>, jamais sur les autres pages (Catégories/
   Recherche/fiche produit/Mission/À propos/Ma commande gardent le sous-titre et l'espacement actuels,
   inchangés). Sous-titre masqué + l'espace qu'il réservait (padding-bottom de .app-identity) supprimé, ce
   qui fait remonter naturellement la ligne recherche+panier juste sous "Bazar Solidaire". */
body.is-home .app-subtitle { display: none; }
/* Décalage léger vers la droite — Mission et À propos UNIQUEMENT (23/08/2026, round retours 3), demande
   explicite ("il équilibre bien le bandeau" sur ces 2 pages) — Catégories/Recherche/fiche produit/Ma commande
   gardent le sous-titre centré, non touchés. Marge de sécurité large avant l'ellipsis (~37px, voir plus haut),
   8px de décalage ne crée aucun risque de troncature. */
body.is-static-page .app-subtitle { transform: translateX(8px); }
/* padding-bottom 0→10px (retour du 22/08/2026) : trop serré entre logo et barre de recherche, un peu d'air
   redonné sans revenir à l'espace d'origine (qui réservait la place du sous-titre, désormais masqué). */
body.is-home .app-identity { padding-bottom: 10px; }

/* Panier sur sa propre ligne (Mission/À propos/Ma commande uniquement) — sous le sous-titre. Retour du
   22/08/2026 : padding-right ramené à 10px — Lébou a confirmé vouloir resserrer l'espace UNIQUEMENT sur ces
   3 pages (Mission/À propos/Ma commande), sans toucher #header-fn-row (bandeau recherche+panier partagé par
   Accueil/Catégories/Recherche/fiche produit, resté à 16px). Les deux paddings ne sont donc plus identiques,
   c'est un choix assumé (les deux zones sont structurellement distinctes, pas la même barre). */
.app-header-cart-row { display: none; justify-content: flex-end; padding: 4px 10px 6px; }
.app-header.is-compact .app-header-cart-row { display: flex; }
/* Le panier est DÉPLACÉ (JS, toggleHeaderSearch() dans render.js) ici sur Mission/À propos/Ma commande
   (écrans sans recherche), et #header-fn-row (vidée) disparaît totalement (voir .no-search plus bas). Sur
   les écrans avec recherche, le panier reste dans #header-fn-row comme avant. */

/* Ligne fonctionnelle (recherche + panier, RIEN d'autre — voir .category-page-title pour le retour/libellé de
   catégorie) — élément frère indépendant de <header class="app-header"> depuis le 22/08/2026 (3e correction,
   voir commentaire sur .app-header ci-dessus). Fond sombre porté directement par cette ligne (plus hérité du
   parent, puisqu'elle n'est plus imbriquée dedans) pour rester visuellement continue avec le bandeau identité
   au-dessus, sans interstice ni bordure entre les deux. */
.app-header-fn-row {
  display: flex; align-items: center; gap: 8px;
  background: var(--dark); padding: 10px 16px;
}
/* En-tête compact (Mission/À propos/Ma commande) : le panier ayant été déplacé dans .app-header-cart-row
   pour ces 3 écrans (voir plus haut), cette ligne n'a plus rien à afficher (recherche masquée par ailleurs)
   — la faire disparaître entièrement supprime toute sa hauteur. */
.app-header-fn-row.no-search { display: none; }

/* Sticky (pages de navigation catalogue + fiche produit uniquement, voir setHeaderNavContext() dans
   render.js) : maintenant que la ligne est un frère direct du <body> (hauteur = toute la page), elle peut
   rester collée pendant l'intégralité du scroll — c'est le point corrigé le 22/08/2026 (3e correction).
   Hauteur réelle de la barre une fois collée : padding(10)+icône panier(44)+padding(10) = 64px, valeur
   reprise comme "top" par .category-page-title (juste en dessous) pour un empilement sans chevauchement. */
.app-header-fn-row.is-sticky {
  position: sticky; top: 0; z-index: 15;
}
/* Hauteur réduite d'environ 30 % (padding vertical 10px -> 7px) et un peu moins large horizontalement —
   retour du 19/08/2026 (2e round), la barre paraissait trop imposante. */
.header-search-form {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px;
  background: #fff; border: 1px solid #e4ddd0; border-radius: 999px; padding: 7px 14px;
}
.home-search-icon { flex: 0 0 auto; display: flex; color: #8a8a8a; }
.home-search-icon .icon-svg { width: 16px; height: 16px; }
.home-search-input { flex: 1; border: none; outline: none; background: transparent; font-size: 14px; min-width: 0; }
.home-search-input::-webkit-search-cancel-button { -webkit-appearance: none; }
/* Croix d'effacement personnalisée (le bouton natif est désactivé ci-dessus) — affichée uniquement quand le
   champ contient du texte (piloté en JS via l'attribut hidden). */
.header-search-clear {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0; border: none; background: transparent; color: #9a9186; cursor: pointer;
}
.header-search-clear[hidden] { display: none; }
.header-search-clear .icon-svg { width: 13px; height: 13px; }

.cart-icon-link {
  flex: 0 0 auto;
  position: relative;
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; /* cible tactile >= 44x44 px — v1.4 section 4.2 */
  color: #ffffff;
}
.cart-icon-wrap .icon-svg { width: 24px; height: 24px; }
.cart-badge-count {
  position: absolute; top: 2px; right: 2px;
  min-width: 17px; height: 17px; padding: 0 4px;
  background: var(--orange); color: var(--dark);
  font-size: 10.5px; font-weight: 800; line-height: 17px; text-align: center;
  border-radius: 999px; border: 1.5px solid var(--dark);
}

/* Encart d'accroche — v3.1.2 section 2.3. Toujours dans le DOM ; .is-hidden masque hors accueil (JS ne
   crée/retire jamais la balise <picture>/<img>, seule cette classe change — section 6.2).
   Cœur décoratif supprimé — addendum v1.4 section 4.3 (le cœur de l'onglet Mission n'est pas concerné). */
.encart-accroche {
  position: relative;
  background: var(--dark);
  text-align: center;
  padding: 0 16px 18px;
  /* Pas de margin-top ici : un margin entre .app-header et .encart-accroche (tous deux à fond sombre)
     laisserait transparaître le fond crème du corps de page dans l'intervalle — bande blanche signalée le
     19/08/2026 (3e round). L'espacement avant la photo héro est réparti entre le padding-bottom de
     .app-header, ce padding-top et le margin-top de .hero-picture ci-dessous — réduit au fil de plusieurs
     rounds (compacité globale de la zone haute), et ramené à 0 le 22/08/2026 (padding-top ; espace
     recherche/panier→photo "fortement réduit", demande explicite ; proportions de la photo non touchées).
     padding-bottom 12px→18px (22/08/2026) : espace avant "Acheter ici..." (18px total avec le padding-top
     de #view, 6px, inchangé) jugé trop faible — total porté à 24px, +33% (minimum 30% demandé). */
  overflow: hidden;
}
.encart-accroche.is-hidden { display: none; }
.hero-picture { display: block; max-width: 640px; margin: 0 auto 14px; border-radius: 14px; overflow: hidden; }
.hero-photo { width: 100%; height: auto; display: block; object-fit: cover; }
/* Sous-texte du héro retiré le 22/08/2026 (4e correction, jugé redondant avec le slogan) — le slogan garde
   sa propre marge basse (6px), qui suffit à espacer le lien "En savoir plus" en dessous. */
/* Poppins Bold (700) — retour du 22/08/2026, ciblé sur 4 titres de l'Accueil uniquement (celui-ci + .reassurance-title
   + .section-title plus bas) : noms produits, prix, boutons, libellés, textes courants et logo "Bazar Solidaire"
   explicitement NON concernés. font-weight passé de 800 à 700 (graisse "Bold" standard chargée, pas d'ExtraBold). */
/* Gras allégé 700→400 (retour du 22/08/2026) : Poppins ne charge que 2 graisses (400/700, voir <head>) —
   400 déjà chargée (titres de page), donc aucun coût supplémentaire pour ce léger allégement. Reste sur
   2 lignes maximum au texte/largeur actuels (inchangé, déjà vérifié à l'écran). */
/* 18px→14px (retour du 22/08/2026) : passait sur 3 lignes au lieu de 2 (constat réel sur capture), et jugé
   encore trop dense en plus de ça — les deux corrigés par la même réduction, avec une marge volontaire
   (calcul basé sur la largeur mobile réelle ~328px de contenu) pour fiabiliser le retour à 2 lignes. */
.encart-slogan { font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; color: #ffffff; font-size: 14px; font-weight: 400; line-height: 1.35; margin: 0 0 6px; max-width: 480px; margin-left: auto; margin-right: auto; }
.encart-lien { display: inline-block; color: var(--orange); font-size: 13px; font-weight: 700; border-bottom: 1px solid var(--orange); padding-bottom: 1px; }

#view { max-width: 640px; margin: 0 auto; padding: 6px 16px 96px; min-height: 40vh; }

/* Encart de réassurance — v3.1.2 section 2.5 */
.reassurance { margin-bottom: 26px; text-align: center; }
.reassurance-title { font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 15px; font-weight: 700; margin: 0 0 8px; }
.reassurance-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.reassurance-col { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.reassurance-icon-circle {
  width: 42px; height: 42px; border-radius: 50%; background: var(--sable);
  display: flex; align-items: center; justify-content: center; color: var(--dark);
}
.reassurance-icon-circle .icon-svg { width: 22px; height: 22px; }
.reassurance-label { font-size: 11px; font-weight: 600; line-height: 1.25; }

/* Cartes de catégories — présentation homogène (remplace les teintes pastel fixes en fond plein) —
   addendum v1.4 section 5.3, appliquée aux DEUX emplacements (raccourcis accueil + page dédiée). Accent
   coloré limité via une bordure gauche pilotée par --accent (posée en ligne, une valeur par carte). */
.category-tile {
  background: #ffffff;
  border: 1px solid #ded2ba;
  border-left: 4px solid var(--accent, var(--sable));
  box-shadow: 0 2px 5px rgba(26, 26, 26, 0.08);
  color: var(--dark);
}
.category-tile-grid .icon-svg { color: #2b2b2b; }

/* Grille d'accueil : 5 raccourcis + "Voir toutes" — v3.1.2 section 2.6, titre "Catégories populaires" — v1.4 section 5.1 */
/* margin-bottom 26px→34px (22/08/2026) : espace avant "Bonnes affaires du moment" augmenté, demande explicite. */
.shortcuts-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 34px; }
.shortcut-card {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  border-radius: 14px; padding: 16px 6px; text-align: center; min-height: 80px; color: var(--dark);
}
.shortcut-icon .icon-svg { width: 24px; height: 24px; }
.shortcut-label { font-size: 12.5px; font-weight: 700; line-height: 1.2; }
.shortcut-voir-toutes { font-weight: 800; }

/* Bloc "Bonnes affaires" — v3.1.2 section 2.7 : grille 2x2, aucun "Voir tout" */
.bonnes-affaires { margin-bottom: 26px; }
/* 16px/700→22px/600 (22/08/2026) : titres agrandis, semi-gras (troisième graisse Poppins chargée pour ça,
   voir <head>). white-space:nowrap garantit une seule ligne même si la marge réelle s'avère plus juste que
   prévu sur un appareil donné ("Bonnes affaires du moment", 26 caractères, est le plus long des deux). */
.section-title { font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 22px; font-weight: 600; margin: 0 0 8px; white-space: nowrap; }

.payment-info-full {
  font-size: 12.5px; color: #555; line-height: 1.5; margin: 10px 0; padding: 10px 12px;
  background: #fff; border: 1px solid #e4ddd0; border-radius: 10px;
}

/* align-items:start — Accueil "Bonnes affaires" UNIQUEMENT (classe exclusive à ce bloc, voir
   renderBonnesAffaires(), render.js) : sans ça, la grille CSS étire chaque carte à la hauteur de la plus
   grande de sa rangée (comportement stretch par défaut), et comme .product-card-link est en flex:1 (pas ses
   enfants), l'espace excédentaire s'accumulait dans le vide entre le prix et l'icône panier au lieu d'être
   distribué au contenu — corrigé le 24/08/2026 (retour ciblé sur l'aération des cartes de l'accueil). Les
   listes de catégories (.product-list-grid, classe séparée) ne sont pas concernées. */
.product-list-grid2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; align-items: start; }
.product-list-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }

/* min-width:0 — retour du 22/08/2026 : correctif d'un piège CSS Grid connu. Sans lui, une carte grid item
   1fr peut se voir imposer une largeur MINIMALE égale au min-content de son texte (nom/prix), ce qui peut
   élargir une colonne au-delà de sa part théorique et donc, via aspect-ratio (qui suit la largeur RÉELLE de
   la colonne, pas sa largeur nominale), rendre son cadre photo plus haut que celui de l'autre colonne —
   correctif candidat pour l'écart de hauteur signalé le 22/08/2026 sur "Bonnes affaires". */
.product-card { display: flex; flex-direction: column; min-width: 0; background: #fff; border-radius: 10px; overflow: hidden; border: 1px solid #eee; }
/* Zone CTA alignée en bas de carte, quelle que soit la longueur du nom ou la présence d'un badge — retour du
   22/08/2026 : .product-card-link (photo+infos) grandit pour occuper l'espace disponible (les cartes d'une
   même rangée de grille sont déjà de même hauteur, stretch par défaut), poussant .product-card-actions tout
   en bas ; pas de hauteur fixe (qui aurait pu rogner un nom long). */
.product-card-link { display: flex; flex-direction: column; flex: 1; }
/* Vignette réduite (retour du 22/08/2026) : hauteur modérément réduite (4/3 au lieu du carré 1/1) pour voir
   davantage de produits à l'écran, sans rogner l'article (object-fit: contain, plutôt que cover) — la fiche
   produit garde un affichage rempli, voir l'override ci-dessous.
   Retour du 22/08/2026 : cadre passé de aspect-ratio:4/3 à la technique padding-top (ratio 4:3 = 75%),
   robuste et éprouvée depuis longtemps sur tous les navigateurs — après un écart de hauteur réel confirmé
   entre cartes (mesure pixel sur capture réelle, largeurs identiques mais hauteurs différentes malgré
   aspect-ratio posé), pour éliminer tout doute sur le rendu plutôt que de deviner la cause exacte sans accès
   navigateur. height:0 + padding-top:75% fixe la hauteur du cadre en fonction UNIQUEMENT de sa largeur
   (jamais du contenu), quel que soit le format de la photo. Le contenu (photo ou pictogramme de repli) est
   absolument positionné pour remplir ce cadre (règle .product-photo > * ci-dessous), et centré à l'intérieur
   — remplace le centrage par flex directement sur .product-photo, qui n'a plus de hauteur de contenu réelle. */
.product-photo { position: relative; width: 100%; height: 0; padding-top: 75%; background: #f0f0f0; overflow: hidden; }
.product-photo > * { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.product-photo img { width: 100%; height: 100%; object-fit: contain; display: block; }
.photo-fallback { color: #bbb; }
.photo-fallback-icon .icon-svg { width: 32px; height: 32px; }
.product-info { padding: 8px; }
.product-nom { font-size: 13px; font-weight: 600; line-height: 1.3; margin-bottom: 4px; }
.product-prix { font-size: 15px; color: var(--dark); font-weight: 800; }
.product-badges { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
/* line-height fixée (au lieu de la valeur par défaut du navigateur, non garantie) — rend la hauteur du badge
   déterministe par calcul (padding 2+2 + 10.5×1.3 ≈ 17,65px) plutôt qu'estimée, pour que le min-height ci-
   dessous (.product-list-grid2 .product-badges) réserve exactement l'espace réel du badge — 24/08/2026. */
.badge { display: inline-block; font-size: 10.5px; line-height: 1.3; padding: 2px 6px; border-radius: 4px; }
.badge-reserve { background: #fff3cd; color: #8a6500; }
.badge-etat { background: var(--sauge); color: var(--dark); }
/* Réserve la hauteur d'un badge même absent — Accueil "Bonnes affaires" UNIQUEMENT (voir opts.reserveBadgeSpace,
   render.js), pour que toutes les cartes de la grille aient la même hauteur de contenu (nom+prix+badge), donc
   la même hauteur totale de carte et la même position d'icône panier, qu'un badge état/réservé soit présent ou
   non. 18px = hauteur réelle calculée du badge (2+2 padding + 10,5×1,3 line-height ≈ 17,65px, arrondi).
   N'affecte pas les listes de catégories (product-list-grid, classe séparée, non ciblée ici). */
.product-list-grid2 .product-badges { min-height: 18px; }

/* Zone actions des cartes de liste (Bonnes affaires + catégories) — alignée à droite, poids visuel réduit
   (remplace le bouton vert pleine largeur par une petite icône panier) — demande du 24/08/2026. */
.product-card-actions { display: flex; justify-content: flex-end; padding: 4px 8px 8px; }
/* Icône panier discrète, cartes de liste uniquement — reprend le même langage visuel que les pastilles de
   réassurance (fond sable, icône sombre, voir .reassurance-icon-circle) plutôt qu'un nouveau style, pour
   rester cohérent avec l'identité visuelle existante. Volontairement distincte du panier de l'en-tête (icône
   blanche sur fond sombre, 44px) pour éviter toute confusion entre les deux — celle-ci est claire sur fond
   clair, plus petite. 40px : proche du minimum de 44px recommandé pour une cible tactile (panier de l'en-tête)
   tout en restant visuellement discrète comme demandé. */
.product-card-ajouter-icon {
  width: 40px; height: 40px; padding: 0; border-radius: 50%; border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: var(--sable); color: var(--dark);
}
.product-card-ajouter-icon .icon-svg { width: 20px; height: 20px; }
/* État "déjà ajouté" — même fond orange que le badge du panier de l'en-tête (.cart-badge-count), pour que le
   retour visuel "produit dans la commande" soit reconnaissable d'un coup d'œil, icône blanche dessus. */
.product-card-ajouter-icon.is-added { background: var(--orange); color: #fff; cursor: default; }
.stale-notice-card { text-align: center; padding: 8px; margin: 0; font-size: 11px; }

/* Bouton texte vert — conservé pour la fiche produit uniquement (ajouterButton(), render.js), qui garde le
   bouton "Ajouter à ma commande" pleine largeur inchangé — n'est plus utilisé sur les cartes de liste
   (remplacées par .product-card-ajouter-icon ci-dessus) depuis le 24/08/2026, voir .fiche-cta ci-dessous. */
.product-card-ajouter {
  text-align: center; background: #25D366; color: #fff; font-weight: 700; font-size: 12.5px;
  padding: 8px; border-radius: 8px; border: none; width: 100%; font-family: inherit; cursor: pointer;
}
.product-card-ajouter.is-added { background: #eee; color: #888; cursor: default; }

/* Réduction de l'aération des cartes "Bonnes affaires" — Accueil UNIQUEMENT (.product-list-grid2, scoping déjà
   utilisé pour align-items:start ci-dessus), reprise du 24/08/2026 après pause déjeuner : r6 avait rendu les
   hauteurs uniformes mais Lébou a signalé qu'il restait trop d'espace. Chaque valeur resserrée modérément
   (jamais à 0, pour rester lisible/cliquable), sur les 3 leviers déjà identifiés avant la pause : vignette
   photo, padding de .product-info, padding de .product-card-actions. Les listes de catégories
   (.product-list-grid, classe séparée) ne sont pas concernées. */
.product-list-grid2 .product-photo { padding-top: 68%; } /* 75%→68% : cadre 4:3 un peu moins haut, object-fit:contain inchangé (aucun rognage) */
.product-list-grid2 .product-info { padding: 6px 8px 4px; } /* 8px partout → 6px haut, 4px bas (transition vers badges/actions, déjà espacés par leurs propres marges) */
.product-list-grid2 .product-nom { margin-bottom: 2px; } /* 4px→2px */
/* Hauteur du nom réservée à 2 lignes — Accueil UNIQUEMENT (26/08/2026) : même principe que
   .product-list-grid2 .product-badges (min-height ci-dessus) mais pour le nom du produit, qui n'était pas
   couvert. Cause du bug remonté ("les cartes changent de taille quand je change de produit") : align-items:start
   (ci-dessus) ne stretch plus les cartes d'une même rangée à la même hauteur — un nom d'1 ligne vs 2 lignes
   donnait donc deux cartes de hauteur différente sur la même rangée. min-height:34px = 2 lignes pleines
   (13px × line-height 1.3 ≈ 16,9px/ligne, arrondi) réserve cette hauteur même si le nom ne tient que sur 1 ligne ;
   -webkit-line-clamp:2 tronque proprement (…) un nom qui dépasserait 2 lignes, pour ne jamais casser à nouveau
   l'alignement dans l'autre sens. Ne touche pas .fiche-produit ni .product-list-grid (catégories, stretch par
   défaut, non concernées par ce bug). */
.product-list-grid2 .product-nom {
  min-height: 34px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.product-list-grid2 .product-badges { margin-top: 2px; } /* 4px→2px — n'affecte pas min-height:18px (hauteur propre du badge, réservée à l'identique pour garder l'uniformité acquise en r6) */
.product-list-grid2 .product-card-actions { padding: 2px 8px 5px; } /* 4px/8px/8px → 2px/8px/5px, icône 40px inchangée (cible tactile) */

/* Catégories (page "Toutes les catégories" — v3.1.2 section 3, et raccourcis d'accueil) */
.categories-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; padding-bottom: 24px; }
.category-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  border-radius: 12px; padding: 16px 8px; text-align: center; color: var(--dark);
  min-height: 84px;
}
.category-icon .icon-svg { width: 26px; height: 26px; }
.category-label { font-size: 13px; font-weight: 700; line-height: 1.2; }

/* Bloc "Notre mission" sur l'accueil — v3.1.2 section 2.8 */
.mission-home { position: relative; display: flex; align-items: center; gap: 14px; margin-bottom: 20px; padding: 14px; background: #fff; border-radius: 12px; border: 1px solid #eee; overflow: hidden; }
.mission-home-photo { flex: 0 0 84px; width: 84px; height: 84px; border-radius: 10px; overflow: hidden; background: #f0f0f0; }
.mission-home-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mission-home-text { flex: 1; min-width: 0; }
/* Titre 14px→22px (même taille/graisse que "Bonnes affaires"/"Catégories populaires", cohérence), texte et
   lien passés en Poppins — 22/08/2026. Taille du texte non précisée par Lébou ("je n'ai pas la taille") :
   12,5px→14px choisi par cohérence avec le reste du site (fiche-descriptif est aussi à 14px). */
.mission-home-titre { font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 22px; font-weight: 600; margin: 0 0 4px; }
.mission-home-texte { font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 14px; line-height: 1.5; margin: 0 0 6px; color: #444; }
.mission-home-lien { font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 14px; font-weight: 700; color: var(--dark); }
.mission-home-motif {
  position: absolute; right: -20px; bottom: -20px; width: 70px; height: 70px; border-radius: 50%;
  background: var(--orange); opacity: 0.15; pointer-events: none;
}

/* margin-bottom 24px (23/08/2026, round retours 2) : le bloc "Chaque achat compte" qui suit directement
   était collé à la photo — 24px = même espace que .static-section entre ce bloc et le suivant ("Merci..."),
   pour un espacement visuellement cohérent des deux côtés du bloc. */
.mission-page-photo { margin-top: 16px; margin-bottom: 24px; border-radius: 12px; overflow: hidden; }
.mission-page-photo img { width: 100%; height: auto; display: block; }

/* Page title / fiche produit — 22px, police Poppins REGULAR (poids 800→400 le 22/08/2026, "vérifier que
   c'est bien Poppins sans gras" — Google Fonts ne charge plus que le poids 400, voir <head>), testée
   uniquement ici : ni le logo "Bazar Solidaire" (28px, police système, gras), ni les textes courants, ni les
   noms de produits n'en héritent — fallback sur la police système si Poppins ne charge pas. Taille revue
   30→28→22px (22/08/2026) : doit rester "moins grand que le logo Bazar Solidaire" (28px) — explicitement
   plus petit, pas juste une graisse différente. Concerne "Notre mission", "À propos", "Ma commande" et
   "Catégories" (même classe, même niveau hiérarchique). Le titre de la page catégorie
   (.category-page-title, juste en dessous) reste volontairement à sa taille d'origine (18px, police système)
   pour rester sous ce niveau, comme demandé. */
.page-title {
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 28px; font-weight: 400; margin: 0 0 14px; display: flex; align-items: center; gap: 8px;
}
/* Modificateur H1 légèrement plus grand — round 3 du 23/08/2026, "Notre mission" et "À propos" UNIQUEMENT
   (classe ajoutée en plus de .page-title sur ces 2 écrans seulement) : "Ma commande" et "Catégories"
   partagent la même classe .page-title de base et ne doivent pas être touchés ce round. */
.page-title-lg { font-size: 30px; }
.page-title-icon .icon-svg { width: 20px; height: 20px; }

/* Titre de la page catégorie ("← Informatique Électronique") — reste à son emplacement d'origine (sur fond
   clair, dans #view, présentation .page-title inchangée), le pictogramme de catégorie est remplacé par une
   flèche de retour PLEINE (retour du 22/08/2026, 3e correction — la flèche à contour fin du round précédent
   n'était pas assez identifiable, et devait de toute façon remplacer le pictogramme, pas s'y ajouter). Cette
   flèche est la SEULE utilisée ici — les pictogrammes de catégories de l'accueil et de "Toutes les
   catégories" (voir .shortcut-icon/.category-icon) ne sont pas concernés. Titre sticky, juste sous la barre
   sombre (recherche + panier) — top: 64px correspond à la hauteur réelle de cette barre une fois collée
   (padding 10px + icône panier 44px + padding 10px). */
.category-page-title {
  position: sticky; top: 64px; z-index: 14;
  background: var(--cream);
  margin: 0 -16px 14px; padding: 10px 16px 8px;
  border-bottom: 1px solid #e4ddd0;
  /* Reste sous le niveau des titres de page (28px) — hiérarchie demandée le 22/08/2026 — et hors du test
     typographique Poppins (repasse explicitement sur la police système, sinon hériterait de .page-title). */
  font-size: 18px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-weight: 700;
}
/* Bouton retour rond, fond plein — retour du 22/08/2026 (style seul revu, emplacement/libellé inchangés) :
   la flèche seule (sans fond) restait peu identifiable comme "bouton" ; un badge rond sombre avec flèche
   claire dedans est un motif de retour standard, net et sans ambiguïté. align-items:center hérité de
   .page-title (parent) aligne verticalement ce badge sur le libellé, sans réglage supplémentaire ici. */
.category-back-link {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; background: var(--dark); color: #ffffff;
}
.category-back-icon .icon-svg { width: 17px; height: 17px; }
.back-link { display: inline-block; margin-bottom: 12px; font-size: 14px; color: #666; }
.fiche-produit { background: #fff; border-radius: 12px; border: 1px solid #eee; overflow: hidden; }
/* Fiche produit : affichage complet du produit, sans rognage — retour du 22/08/2026, aligne la fiche sur la
   même règle que les cartes de liste (object-fit:contain hérité de .product-photo img, plus d'override ici). */
.fiche-nom { font-size: 18px; margin: 12px 16px 4px; }
.fiche-prix { font-size: 18px; font-weight: 700; color: var(--dark); margin: 0 16px 4px; }
.fiche-categorie { font-size: 13px; color: #666; margin: 0 16px 8px; display: flex; align-items: center; gap: 6px; }
.fiche-categorie-icon .icon-svg { width: 16px; height: 16px; }
.fiche-produit .product-badges { margin: 0 16px 8px; }
.fiche-descriptif { font-size: 14px; line-height: 1.5; margin: 8px 16px; white-space: pre-wrap; word-break: break-word; }
.fiche-livraison { font-size: 12px; color: #777; margin: 4px 16px 8px; }
.fiche-cta { margin: 16px; }
.reserve-notice, .stale-notice { color: #8a6500; font-size: 13px; }

.whatsapp-button {
  display: block; text-align: center; background: #25D366; color: #fff; font-weight: 700;
  padding: 12px; border-radius: 10px; font-size: 15px; border: none; width: 100%; font-family: inherit; cursor: pointer;
}
.fiche-cta .product-card-ajouter { margin-top: 8px; padding: 12px; font-size: 13px; }

/* Recherche — non vide avant saisie, addendum v1.4 section 11 (champ = celui de l'en-tête, retour du 19/08/2026) */
.empty-message { color: #888; font-size: 14px; text-align: center; padding: 24px 0; }

/* Pages statiques (Notre mission / À propos) — round 3 du 23/08/2026 : justification retirée (mots coupés/
   espacements irréguliers signalés), retour à l'alignement à gauche ; interligne resserré (1.65->1.5) ;
   espace avant chaque titre de section encore augmenté (26px->32px). */
.static-lead {
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 17px; font-weight: 600; font-style: italic; color: var(--dark); margin: 0 0 18px;
}
.static-section { margin-bottom: 24px; }
.static-heading {
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 21px; font-weight: 700; margin: 32px 0 10px; color: var(--dark);
}
.static-section p {
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 16.5px; line-height: 1.5; color: #444; margin: 0 0 10px; text-align: left;
}
.static-section p:last-child { margin-bottom: 0; }
.static-list {
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  margin: 8px 0 0; padding-left: 20px; font-size: 16.5px; line-height: 1.5; color: #444; text-align: left;
}
.static-list li { margin-bottom: 4px; }
.static-list li:last-child { margin-bottom: 0; }
/* Liste numérotée (étapes de commande) — pastille ronde à la place des chiffres natifs, cohérent avec les
   autres badges ronds du site (ex. .category-back-link). */
.static-list-ordered { list-style: none; counter-reset: static-step; padding-left: 0; }
.static-list-ordered li { counter-increment: static-step; position: relative; padding-left: 30px; }
/* top:0->3px (23/08/2026, round retours) : la pastille numérotée paraissait "un cran au-dessus" du début de
   la première phrase — l'interligne de .static-list li (1.5) laisse un espace au-dessus des glyphes que la
   pastille (absolue, top:0) n'a pas, décalage optique corrigé par ce léger recul vers le bas. */
.static-list-ordered li::before {
  content: counter(static-step); position: absolute; left: 0; top: 3px;
  width: 20px; height: 20px; border-radius: 50%; background: var(--dark); color: #fff;
  font-size: 11px; font-weight: 700; display: flex; align-items: center; justify-content: center;
}
/* Icône inline dans un item de liste (panier, étape 2 "Comment commander ?" — À propos) */
.static-inline-icon { display: inline-flex; vertical-align: -4px; margin: 0 1px; }
.static-inline-icon .icon-svg { width: 18px; height: 18px; }
/* Note "n'est pas une boutique en ligne" — sélecteur renforcé (.static-section p.static-note) pour primer sur
   .static-section p ci-dessus : sans ça, la spécificité CSS plus élevée de .static-section p écrasait déjà
   silencieusement cette règle depuis le round 2 (bug préexistant, corrigé au passage). Accent discret par une
   bordure gauche (pas un encadré plein, resterait "trop lourd") + espace au-dessus nettement augmenté pour la
   séparer clairement de la fin du bloc "Comment commander ?". */
.static-section p.static-note {
  /* 12.5px->14.5px puis 14.5px->16px (23/08/2026, round retours puis round retours 2, "augmenter encore") :
     pas de largeur fixe ni d'overflow/nowrap sur ce bloc, le texte s'enroule normalement à cette taille,
     aucun mot coupé. Traitement visuel par ailleurs jugé satisfaisant (bordure, couleur, espace au-dessus) —
     seule la taille de police a été retouchée, rien d'autre changé sur ce bloc. */
  font-size: 16px; line-height: 1.5; color: #666; margin: 20px 0 0;
  padding: 8px 0 8px 10px; border-left: 2px solid var(--orange); text-align: left;
}
/* Encadré "Chaque achat compte" — fond distinct de .static-highlight (remerciement) pour ne pas dupliquer
   deux fois le même traitement visuel sur la même page. */
.static-emphasis {
  background: #fdf3e2; border: 1px solid #f0dfc0; border-radius: 12px; padding: 18px 16px;
}
.static-emphasis .static-heading { margin-top: 0; }
/* Encadré de remerciement — même palette que .pour-commander (écran Ma commande). Cœur (round 3) : fond
   sombre retiré (jugé trop dur), remplacé par un disque orange (couleur d'accent du site, pas de noir) —
   cœur plein blanc dessus, bien visible par contraste plutôt qu'un cœur blanc "nu" sur fond clair. */
.static-highlight {
  background: #fbecc7; border: 1.5px solid #dda63f; border-left: 4px solid var(--orange);
  border-radius: 8px; padding: 16px; font-size: 18px; line-height: 1.5; color: var(--dark); text-align: left;
}
.static-highlight p { margin: 0; }
.static-highlight-heart {
  display: flex; align-items: center; justify-content: center; margin: 14px auto 0;
  width: 34px; height: 34px; border-radius: 50%; background: var(--orange);
}
.static-highlight-heart svg { display: block; }
/* margin-bottom 14px->11px (24/08/2026) : "diminuer un peu l'espace entre les 3 lignes", demande explicite. */
.static-contact-row { display: flex; align-items: center; gap: 10px; margin-bottom: 11px; }
/* Icône DEVANT, même taille/traitement pour les 3 lignes (Adresse/Téléphone/Facebook) — présentation revue le
   24/08/2026 (2e passe du jour) : retour à l'icône à gauche (abandon du logo à droite), suppression des
   libellés texte ("Adresse :" etc.) — structure des 3 lignes strictement identique, alignement garanti par
   construction plutôt qu'ajusté au pixel. */
.static-contact-icon {
  flex: 0 0 auto; width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center; color: var(--dark);
}
.contact-icon-badge svg { display: block; }
.static-contact-text {
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 16.5px; line-height: 1.5; color: #444;
  min-width: 0;
}
.static-contact-link { cursor: pointer; }
/* CTA "Découvrir notre mission" — bouton centré, fond orange. */
.static-cta-link {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  margin: 22px auto 0; max-width: 280px;
  font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 15px; font-weight: 700; color: var(--dark);
  background: var(--orange); padding: 13px 20px; border-radius: 10px; text-align: center;
}

/* États d'erreur / obsolescence */
.error-box { text-align: center; padding: 48px 16px; color: #666; }
.retry-button {
  margin-top: 12px; padding: 10px 20px; border-radius: 8px; border: none; background: var(--dark); color: #fff;
  font-size: 14px; font-weight: 600;
}
.retry-small { padding: 6px 12px; font-size: 12px; }
.stale-banner {
  background: #fff3cd; color: #8a6500; font-size: 13px; padding: 8px 16px; display: flex;
  justify-content: space-between; align-items: center; gap: 8px; position: sticky; top: 0; z-index: 5;
}

/* Écran "Ma commande" — addendum v1.3 sections 2.5 à 2.9 */
.cart-update-message { background: #fff3cd; color: #8a6500; font-size: 13px; padding: 10px 12px; border-radius: 8px; margin-bottom: 14px; }
.cart-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
.cart-row { display: flex; flex-direction: column; gap: 8px; background: #fff; border: 1px solid #eee; border-radius: 10px; padding: 10px 12px; }
.cart-row-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.cart-row-info { min-width: 0; }
.cart-row-nom { font-size: 13px; font-weight: 700; }
.cart-row-ref { font-size: 11px; color: #888; }
.cart-row-prix { font-size: 12.5px; color: var(--dark); font-weight: 700; flex: 0 0 auto; white-space: nowrap; }
.cart-row-remove { align-self: flex-end; background: none; border: 1px solid #ddd; border-radius: 8px; padding: 6px 10px; font-size: 11.5px; color: #a33; cursor: pointer; }
.cart-total { display: flex; justify-content: space-between; align-items: baseline; font-size: 16px; font-weight: 800; margin: 6px 0 4px; padding-top: 8px; border-top: 1px solid #e4ddd0; }
.cart-send-btn { margin-top: 4px; }
.cart-clear-btn { display: block; width: 100%; margin-top: 10px; background: none; border: none; color: #888; font-size: 12.5px; text-decoration: underline; cursor: pointer; padding: 6px; font-family: inherit; }

/* Bloc "Pour commander :" — écran "Ma commande" uniquement, plus identifiable que le texte courant sans
   devenir une alerte lourde — addendum v1.4 section 9.3 (remplace .payment-info-full sur cet écran). */
.pour-commander {
  background: #fbecc7; border: 1.5px solid #dda63f; border-left: 4px solid var(--orange);
  border-radius: 10px; padding: 12px 14px; margin: 10px 0; box-shadow: 0 1px 3px rgba(26, 26, 26, 0.07);
}
.pour-commander-titre { font-size: 13.5px; font-weight: 800; margin: 0 0 6px; color: var(--dark); }
.pour-commander-etapes { margin: 0; padding-left: 18px; font-size: 12.5px; line-height: 1.55; color: #444; }
.pour-commander-etapes li { margin-bottom: 3px; }
.pour-commander-etapes li:last-child { margin-bottom: 0; }

/* Navigation basse fixe — état actif addendum v1.4 section 12, jamais fondé sur la seule couleur (libellé
   plus gras + trait supérieur + icône plus foncée, en plus de la couleur). */
.bottom-nav {
  position: fixed; bottom: 0; left: 0; right: 0; background: #fff; border-top: 1px solid #eee;
  display: flex; z-index: 20;
  padding-bottom: max(2px, env(safe-area-inset-bottom, 0px));
}
.bottom-nav-item {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 8px 4px 6px;
  font-size: 10px; color: #666; position: relative;
}
.bottom-nav-item .icon-svg { width: 18px; height: 18px; margin: 0 auto; }
.bottom-nav-item span { line-height: 1; }
.bottom-nav-item.is-active { color: var(--dark); }
.bottom-nav-item.is-active .icon-svg { color: var(--orange); stroke-width: 2; }
.bottom-nav-item.is-active span { font-weight: 800; }
.bottom-nav-item.is-active::before {
  content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 30px; height: 3px; border-radius: 0 0 3px 3px; background: var(--orange);
}

/* Boîte de dialogue de confirmation accessible — réutilisée pour la commande directe et le vidage de la
   commande — addendum v1.4 sections 7.2/7.3/9.3. */
.dialog-overlay {
  position: fixed; inset: 0; background: rgba(26, 26, 26, 0.55); z-index: 40;
  display: flex; align-items: flex-end; justify-content: center;
}
/* Sans cette règle, "display: flex" ci-dessus (règle d'auteur) l'emporterait sur [hidden] { display: none }
   de la feuille de style user-agent : l'attribut hidden posé par JS n'aurait alors plus aucun effet visuel. */
.dialog-overlay[hidden] { display: none; }
.dialog-box {
  background: #fff; width: 100%; max-width: 480px; border-radius: 16px 16px 0 0; padding: 20px 20px calc(20px + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 480px) {
  .dialog-overlay { align-items: center; }
  .dialog-box { border-radius: 16px; }
}
.dialog-title { font-size: 16px; margin: 0 0 10px; }
.dialog-text { font-size: 13.5px; line-height: 1.6; color: #444; margin: 0 0 18px; white-space: pre-line; }
.dialog-actions { display: flex; gap: 10px; }
.dialog-btn-secondary, .dialog-btn-primary {
  flex: 1; padding: 12px; border-radius: 10px; font-size: 14px; font-weight: 700; border: none;
  font-family: inherit; cursor: pointer;
}
.dialog-btn-secondary { background: #f0ebe0; color: var(--dark); }
.dialog-btn-primary { background: #25D366; color: #fff; }
.dialog-btn-primary:disabled { background: #cfcfcf; color: #888; cursor: not-allowed; }

/* Toast transitoire — addendum v1.4 section 8. Perceptible sans dépendre de la seule couleur (texte lisible
   par lui-même, contraste suffisant). */
.toast {
  position: fixed; left: 50%; bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%) translateY(8px);
  background: var(--dark); color: #fff; font-size: 13px; font-weight: 600;
  padding: 10px 18px; border-radius: 999px; z-index: 50;
  opacity: 0; transition: opacity 0.2s ease, transform 0.2s ease; pointer-events: none;
  max-width: 90%; text-align: center;
}
.toast.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Écrans mobiles très étroits — s'assurer que la ligne fonctionnelle (recherche + icône panier) et le
   bandeau ne chevauchent rien */
@media (max-width: 340px) {
  .app-title { font-size: 19px; }
  .app-subtitle { font-size: 12px; }
  .app-header-fn-row { gap: 6px; }
  .header-search-form { padding: 9px 12px; }
}
