/* ═══════════════════════════════════════════════════════════════════════════
   Le contenu et la communication — lot 18.

   Cette feuille ne contient QUE ce qui n'existait pas :

   1. cinq grilles de tableau dense (les écrans de ce lot) ;
   2. le bandeau d'annonce, qui vit sur la vitrine et sur la boutique — donc
      hors du poste de travail, donc hors de `gestion.css` ;
   3. la page publique de désinscription.

   Tout le reste — boutons, badges, champs, tuiles, jauges, tableau dense,
   onglets — est repris tel quel de `gestion.css` et de `compte.css`. Aucun
   composant n'est inventé (DEC-038).

   ⚠️ **La bascule mobile est répétée ici, et c'est le prix d'une feuille
   séparée.** Dans `gestion.css`, la règle qui transforme une ligne de tableau
   en fiche sous 900 px est une **énumération** de noms de grilles — donc une
   grille déclarée ailleurs n'en profite pas. Les cinq grilles de ce lot ont
   donc leur propre règle, plus bas, et `tests/test_contenu_frequentation.py`
   vérifie qu'aucune ne peut être oubliée. C'est exactement le piège n° 68
   (« une énumération est une liste qu'on oubliera d'étendre »), et la seule
   parade tenable sans toucher au fichier d'une autre session.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Les grilles des cinq écrans ─────────────────────────────────────────── */

.grille-pages,
.grille-annonces,
.grille-campagnes,
.grille-avis,
.grille-frequentation { display: grid; gap: var(--space-3); }

.grille-pages {
  grid-template-columns: minmax(200px, 2fr) minmax(140px, 1.2fr) 116px 108px 184px;
  min-width: 900px;
}

.grille-annonces {
  grid-template-columns: minmax(220px, 2.2fr) minmax(160px, 1.2fr) 116px 132px 160px;
  min-width: 940px;
}

.grille-campagnes {
  grid-template-columns: minmax(200px, 2fr) minmax(150px, 1.2fr) 132px 116px 128px;
  min-width: 920px;
}

/* La première colonne est la case des actions groupées, à la largeur de celle
   des produits et des commandes : on coche partout de la même façon. La
   troisième porte le texte de l'avis, qui est la raison d'être de l'écran. */
.grille-avis {
  grid-template-columns: 48px minmax(160px, 1.2fr) minmax(260px, 2.6fr) 92px 176px;
  min-width: 1020px;
  align-items: start;
}

.grille-frequentation {
  grid-template-columns: minmax(220px, 2.4fr) 108px minmax(160px, 1.4fr);
  min-width: 700px;
}

/* ── Le poste de travail : deux colonnes pour la fiche d'une campagne ────── */

.contenu-double {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(20rem, 26rem);
  gap: var(--space-5);
  align-items: start;
  margin-top: var(--space-5);
}

/* L'aperçu du message, rendu dans un cadre plutôt que dans une nouvelle page :
   on veut le voir à côté de son segment, pas à sa place. */
.apercu-courrier {
  width: 100%;
  min-height: 26rem;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  background: var(--surface);
}

/* ── Le bandeau d'annonce (vitrine et boutique) ──────────────────────────── */

.annonce {
  box-sizing: border-box;
  width: 100%;
  padding: var(--space-3) var(--space-5);
  background: var(--color-accent-100);
  color: var(--color-neutral-800);
  border-bottom: 1px solid var(--color-accent-300);
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  line-height: 1.5;
}

.annonce--attention {
  background: var(--color-primary-100);
  border-bottom-color: var(--color-primary-300);
}

.annonce__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2) var(--space-4);
  max-width: 72rem;
  margin: 0 auto;
  text-align: center;
}

.annonce__lien {
  display: inline-flex;
  align-items: center;
  min-height: 44px; /* plancher tactile du projet, depuis le lot 4 */
  font-weight: 600;
  color: var(--color-primary-700);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.annonce__lien:hover,
.annonce__lien:focus-visible { color: var(--color-primary-800); }

/* ── La page publique de désinscription ──────────────────────────────────── */

.desinscription {
  box-sizing: border-box;
  max-width: 40rem;
  margin: 0 auto;
  padding: var(--space-8) var(--space-5);
  text-align: center;
}

.desinscription h1 {
  font-family: var(--font-display);
  margin-bottom: var(--space-4);
}

.desinscription p { margin-bottom: var(--space-4); line-height: 1.6; }

.desinscription form { margin-top: var(--space-5); }

/* ── Sous 900 px : une ligne de tableau devient une fiche ─────────────────
   Même transformation que `gestion.css`, sur les grilles de ce lot. Les règles
   d'ordre (`.ligne__identite`, `.ligne__nombre`) et l'étiquette
   `[data-intitule]::before` viennent de `gestion.css` et s'appliquent déjà :
   on ne les répète pas, elles ne dépendent pas du nom de la grille. */

@media (max-width: 900px) {
  .contenu-double { grid-template-columns: minmax(0, 1fr); }

  /* ⚠️ Le texte d'un avis passait AVANT le nom du produit : une cellule sans
     `order` vaut 0, donc elle précède `.ligne__identite`, qui est en `order: 1`
     (piège n° 53, vu à l'écran en 375 px sur la fiche d'un avis). Les classes
     ordonnées de `gestion.css` conviennent à un chiffre ou à une mention
     courte, pas à un paragraphe : celle-ci le range après le nom **et** lui
     donne toute la largeur de la fiche, ce qu'un avis demande. */
  .ligne__texte { order: 2; flex: 1 1 100%; }

  .grille-pages,
  .grille-annonces,
  .grille-campagnes,
  .grille-avis,
  .grille-frequentation {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    min-width: 0;
    padding: var(--space-3) var(--space-4);
  }

  .annonce { padding: var(--space-3) var(--space-4); }
  .annonce__inner { justify-content: flex-start; text-align: left; }
}


/* ── Le composeur de la liste de diffusion ────────────────────────────────
   « Il faudrait générer comme pour l'envoi de SMS la même interface graphique,
   en déplaçant la présentation pour bien voir que c'est pas la même chose »
   (Jérôme, 16/09/2026). Trois panneaux empilés — on écrit, on choisit ce qu'on
   annonce, puis on regarde qui reçoit — là où l'écran des SMS part de la liste.

   Rien de neuf ici (DEC-038) : les panneaux sont ceux des fiches, les lignes
   celles des tableaux denses. Ce fichier ne pose que la grille des colonnes et
   le repli d'un rayon. */

.composeur__bloc { margin-bottom: var(--space-6); }
.composeur__pied { margin-bottom: var(--space-10); }

.grille-diffusion {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 44px 96px minmax(140px, 1.2fr) minmax(180px, 1.4fr) minmax(120px, 1fr) minmax(150px, 1fr);
  min-width: 860px;
}

/* Un rayon replié tient en une ligne : l'arbre du catalogue en compte quatre-
   vingts, et quatre-vingts listes dépliées feraient un écran qu'on ne parcourt
   plus. Un rayon dont quelque chose est retenu s'ouvre de lui-même (`open`
   posé par le serveur — le script ne fabrique pas d'interface, DEC-031). */
.rayon-propose {
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-2);
  background: var(--color-neutral-0);
}

.rayon-propose--enfant { margin-left: var(--space-5); }

.rayon-propose__titre {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  font-weight: 600;
}

.rayon-propose__compte { color: var(--color-neutral-500); font-size: var(--fs-caption); }

.rayon-propose__entier {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4) var(--space-3);
  border-top: 1px solid var(--color-neutral-200);
  font-size: var(--fs-body-sm);
  color: var(--color-neutral-700);
}

.rayon-propose__produits {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-1) var(--space-3);
  padding: 0 var(--space-4) var(--space-4);
}

.produit-propose {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 32px;
  font-size: var(--fs-body-sm);
}

/* Une case désactivée ne se distinguerait pas d'une case décochée : c'est le
   rayon entier qui décide, et la ligne doit le montrer. */
.produit-propose input:disabled + .produit-propose__ugs,
.produit-propose input:disabled ~ .produit-propose__nom { color: var(--color-neutral-400); }

.produit-propose__ugs { color: var(--color-neutral-500); font-size: var(--fs-caption); }
.produit-propose__nom { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Le formulaire des filtres est VIDE : ses champs vivent plus bas, dans le
   panneau « Qui reçoit », et le rejoignent par leur attribut `form`. Sans
   `display: none`, `.filtres` lui donnait quand même son fond et son padding —
   une barre beige vide au milieu de la page, mesurée à l'écran. Masqué, il
   continue de recevoir la soumission : c'est l'attribut `form` qui associe les
   champs, pas la position du formulaire. */
#filtres-diffusion { display: none; }

/* Le menu d'affichage porte « Ceux qui ne recevront pas » : à la largeur par
   défaut, il rendait « Ceux qui ne recev… ». Un filtre dont on ne lit pas le
   choix courant ne dit pas ce qu'on regarde. Mesuré, pas estimé. */
.filtres--en-ligne { margin-bottom: var(--space-4); }
.filtres--en-ligne select[name="filtre"] { min-width: 210px; }

@media (max-width: 900px) {
  .rayon-propose--enfant { margin-left: var(--space-3); }
  /* Les trois contrôles du filtre l'un sous l'autre : côte à côte sur 375 px,
     le menu d'affichage n'avait plus que 90 px et coupait son intitulé. */
  .filtres--en-ligne { flex-wrap: wrap; }
  .filtres--en-ligne .filtres__choix,
  .filtres--en-ligne .filtres__recherche,
  .filtres--en-ligne select[name="filtre"] { flex: 1 1 100%; min-width: 0; }
  .rayon-propose__produits { grid-template-columns: minmax(0, 1fr); }

  .grille-diffusion {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    min-width: 0;
    padding: var(--space-3) var(--space-4);
  }
}
