/* 5-feuilles.css — ce qui s'ouvre par-dessus : la feuille devenue dialogue, le logo, le portrait, les
 * étapes d'un agent en direct, la livraison.
 *
 * ── L'ORDRE COMPTE ─────────────────────────────────────────────────────────────────
 * Ce fichier est une TRANCHE de l'ancien app.css, découpé en neuf morceaux contigus. Le
 * chiffre en tête du nom est son rang de cascade, et ce n'est pas de la décoration : lus
 * dans l'ordre, les neuf fichiers valent exactement l'ancien, à l'octet près. Les intervertir
 * change ce qui l'emporte — et une cascade inversée ne se voit pas, elle se constate trois
 * jours plus tard sur un écran précis.
 *
 * Deux raisons de ne PAS regrouper par thème en réordonnant : les paires
 * `@media`/`@container` se redoublent (chacune doit rester APRÈS la @media qu'elle double),
 * et `container-type` définit l'unité de mesure de tout ce qu'il contient. Le découpage
 * contigu rend ces deux pièges impossibles au lieu de demander qu'on y pense.
 *
 * `tests/test_feuilles_css.py` vérifie que les quatre points de chargement listent bien ces
 * neuf fichiers, dans ce rang.
 */

/* — au-delà de l'ordinateur portable : la feuille devient un dialogue —
 * Une feuille qui monte du bas est un geste de POUCE : elle arrive là où la main est déjà.
 * Sur un écran de 1600 px tenu à cinquante centimètres, c'est un panneau de 1600 px de large
 * qui coupe la page en deux — et comme `.sheet-body` n'avait aucune largeur maximale nulle
 * part, une ligne « Menthe » faisait 1568 px pour une pastille et trois courtes lignes.
 *
 * On change l'ALIGNEMENT, et surtout pas le mode d'affichage : `lane-ai` rend son propre
 * `.sheet-body` dans un élément qui n'a pas de `display` à lui et ne tient sa mise en page
 * que du `display: flex` ci-dessus. Le passer en grille ferait retomber ce composant-là en
 * `inline`, où il ignorerait sa largeur — le piège documenté en tête de ce fichier.
 *
 * Le rembourrage de `.sheet-body` n'est PAS touché, et c'est délibéré : le bouton de sortie
 * est collant, et le bandeau opaque qui l'accompagne a des `inset` négatifs calés dessus.
 * Changer l'un sans l'autre fait défiler le contenu de part et d'autre d'un bouton qui
 * flotte. (`env(safe-area-inset-bottom)` vaut zéro sur un ordinateur : ils tombent juste.)
 *
 * 768 px, et c'est désormais le SEUL seuil de toute l'application : celui où la barre passe
 * déjà en haut. C'est le moment où Lane cesse de se tenir comme un téléphone ; la feuille
 * doit cesser en même temps, sans quoi une tablette en portrait reçoit une barre
 * d'ordinateur au-dessus d'un panneau de téléphone — ce qu'elle recevait, et c'était le
 * pire endroit de l'application. */
@media (min-width: 768px) {
  .sheet {
    align-items: center;
    justify-content: center;
    padding: var(--s5);
  }

  .sheet-body {
    width: min(860px, 100%);
    max-height: min(80vh, 760px);
    border: 1px solid var(--line);
    border-radius: var(--radius);   /* les quatre coins, pas seulement ceux du haut */
    box-shadow: var(--shadow);
  }

  /* Les items sont des frères plats entre les titres de famille — le même problème que les
   * blocs d'un onglet, et la même solution : une enveloppe, sans quoi une grille rangerait le
   * titre dans une colonne et sa liste dans la suivante. Ici on ne pose QUE les colonnes :
   * la colonne unique et la gouttière viennent de la règle de base, qui est celle du
   * téléphone. */
  .sheet-body { container-type: inline-size; }

  /* Un segmenteur dit « voici les trois formes possibles » : il doit tenir dans un regard.
   * Étiré à la largeur du dialogue, chaque option devient une cible de 270 px pour un mot de
   * six lettres — on ne lit plus un choix, on balaie une barre. */
  .sheet-body .states { max-width: 420px; }
}

/* Les colonnes d'un panneau se mesurent sur le PANNEAU, pas sur la fenêtre. La différence
 * compte : le dialogue est borné à 860 px alors que la fenêtre peut faire 2560, et un
 * catalogue qui compterait ses colonnes sur la fenêtre en mettrait six dans un panneau qui
 * en tient trois. */
@container (min-width: 560px) {
  .liste { grid-template-columns: repeat(auto-fill, minmax(var(--liste-min, 240px), 1fr)); }

  /* Les paires de polices s'écrivent dans leur propre police, et c'est tout leur intérêt :
   * serrées à 240 px, l'échantillon se coupe et on ne juge plus rien. */
  .liste.lisible { --liste-min: 340px; }
}

.preset {
  display: flex;
  align-items: center;
  gap: var(--s4);
  padding: var(--s4);
  text-align: left;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.preset span { min-width: 0; }
.preset b { display: block; font: var(--w-gras) var(--t5)/var(--lh-ui) var(--font-head); }
.preset small { display: block; color: var(--mist); font-size: var(--t2); }

/* Six pastilles : trois en clair, trois en sombre. Une charte qui n'a l'air bien que dans
 * un des deux modes n'est pas une charte, c'est la moitié d'une. */
.swatch { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s0); flex: 0 0 auto; }
.swatch i { width: var(--s4); height: var(--s4); border-radius: var(--radius-xs); border: 1px solid var(--line); }


/* — la photo, posée dans la charte —
 *
 * Ce qu'on ajoute est AUTOUR du visage : un aplat, un anneau, un cadre. Les traitements qui
 * remappaient les couleurs de l'image (duotone, teinte) ont été essayés et retirés — ils
 * rendent un visage vert ou bleu, et un visage recoloré n'est plus la photo de quelqu'un,
 * c'est un filtre.
 *
 * Ces règles existent en double, ici et dans `workers/portrait.mjs` qui écrit le fichier :
 * la politique de sécurité interdit d'injecter une feuille de style dans la page, donc le
 * serveur ne peut pas les fournir aux deux. Un test vérifie qu'elles restent identiques —
 * deux copies qui divergent donnent un aperçu qui ment.
 *
 * Les trois classes du sélecteur ne sont pas du zèle : `.logo-art.photo` pose déjà un fond,
 * à spécificité égale et plus bas dans le fichier — c'est lui qui gagnait, et la vignette
 * restait indiscernable de l'original.
 */
.logo-art.photo.p-fond { background: var(--p-couleur, var(--accent)); padding: 12%; }
.logo-art.photo.p-fond img { border-radius: 50%; }
.logo-art.photo.p-cercle { background: var(--p-couleur, var(--accent)); padding: 7%;
                           border-radius: 50%; }
.logo-art.photo.p-cercle img { border-radius: 50%; }
.logo-art.photo.p-cadre { background: var(--p-couleur, var(--accent)); padding: 9%; }
.logo-art.photo.p-cadre img { border-radius: 4%; }

/* — les couleurs du logo —
 * De une à trois, prises dans la charte. Le nombre n'est pas un réglage à part : il se lit
 * dans ce qui est allumé, ce qui évite un sélecteur « 1 / 2 / 3 » à tenir d'accord avec la
 * sélection elle-même. */

.palette { display: flex; flex-wrap: wrap; gap: var(--s2); }

.pastille {
  position: relative;
  min-height: 44px;
  min-width: 44px;
  padding: 0 var(--s3);
  border: 2px solid var(--line);
  border-radius: var(--radius-sm);
  /* Le libellé est là pour les lecteurs d'écran et pour qui distingue mal deux nuances
   * voisines — mais il ne doit pas salir la pastille, dont on juge la COULEUR. */
  font: 0/0 var(--font-body);
  color: transparent;
}

.pastille.on {
  border-color: var(--text);
  box-shadow: 0 0 0 2px var(--ground) inset;
}

/* La coche : elle dit « allumée » sans dépendre de la bordure, invisible sur une couleur
 * proche de celle du fond. */
.pastille.on::after {
  content: "✓";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font: var(--w-gras) var(--t5)/var(--lh-plat) var(--font-body);
  color: var(--ground);
  text-shadow: 0 0 3px var(--text);
}

/* — choix de logo : on juge un dessin, pas une description — */

/* Le catalogue était figé à trois colonnes À TOUTE LARGEUR : des cellules de 480 px autour
 * d'un dessin de 64 px dans un panneau plein écran, et trois vignettes serrées à 90 px sur
 * un téléphone. On juge un dessin en le comparant à ses voisins : il en faut le plus
 * possible dans un regard, et moins dès que la place manque. */
.logos { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--s2); }

.logo-choice {
  display: grid;
  justify-items: center;
  gap: var(--s2);
  padding: var(--s3) var(--s2);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-align: center;
}

.logo-art { width: 64px; height: 64px; display: block; }
.logo-art svg { width: 100%; height: 100%; display: block; }
.logo-choice b { font: var(--w-fort) var(--t2)/var(--lh-titre) var(--font-body); }
.logo-choice small { color: var(--mist); font-size: var(--t1); line-height: var(--lh-ui); }

/* Quatorze vignettes en vrac se parcourent mal ; quatre groupes de trois ou quatre se
 * choisissent. Le titre de famille fait le tri à la place de l'œil. */
.sheet h3 { margin: var(--s4) 0 var(--s2); }
.sheet h3:first-of-type { margin-top: var(--s2); }

.btn.wide { width: 100%; margin-top: var(--s3); }

/* — étapes d'un agent, en direct —
 * Un agent qui travaille trois minutes sans rien afficher est indiscernable d'un agent
 * planté. C'est la première raison qu'on a de tuer un outil qui marchait très bien. */

.steps {
  list-style: none;
  max-width: 100%;
  overflow: hidden;
  margin: var(--s2) 0 0;
  padding: 0;
  font: var(--w-normal) var(--t1)/var(--lh-corps) var(--font-mono);
  color: var(--mist);
}

.steps li { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.steps span { opacity: .6; }

/* Bouton secondaire : présent, mais qui ne dispute pas l'attention à l'action principale.
 * Écarter un diagnostic doit rester possible d'un geste, jamais être le geste évident. */
/* Écarter un diagnostic doit rester possible d'un geste, sans jamais être le geste
 * évident. Sans fond, il ne dispute plus l'attention au bouton principal — et sur l'écran
 * précédent les deux étaient du même vert, donc indistinguables. */
.ghost {
  min-width: var(--tap);
  background: none;
  border: 1px solid var(--line);
  color: var(--mist);
  font-size: var(--t6);
}

.spin {
  color: var(--warn);
  font-size: var(--t6);
  animation: spin 1.4s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* Les cartes de travail portent leur niveau sur le bord : lisible en diagonale, sans
 * ajouter ni couleur de fond ni icône supplémentaire. */
.work li { border-left: 3px solid var(--lv, var(--line)); }

/* Trois lignes au plus. Un diagnostic qui liste quarante URL occupe l'écran entier et
 * repousse le bouton hors de vue : on ne peut plus agir sur ce qu'on vient de lire. Le
 * détail complet reste dans le diagnostic, il n'est pas perdu — juste pas ici. */
.work li b {
  font: var(--w-fort) var(--t4)/var(--lh-ui) var(--font-body);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.work li small {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Sur un téléphone, un titre long et deux boutons ne tiennent pas sur une ligne. */
@media (max-width: 420px) {
  .work li { flex-wrap: wrap; }
  .work li div { flex: 1 1 100%; }
  .work li button { flex: 1; }
  .work li .ghost { flex: 0 0 var(--tap); }
}

/* La même chose, mesurée sur la COLONNE et non sur la fenêtre. Les deux coexistent, et ce
 * n'est pas un doublon qu'on aurait oublié de nettoyer : c'est ce qui rend le changement
 * sans risque sur l'application mobile. Capacitor vise iOS 13 par défaut, où `@container`
 * n'existe pas et est ignoré en silence — mais sur un téléphone la fenêtre EST étroite,
 * donc la requête ci-dessus se déclenche et le rendu est celui d'avant. La requête de
 * conteneur ne sert que dans le cas qu'un téléphone n'atteint jamais : une colonne étroite
 * dans une fenêtre large. Le repli est donc gratuit. Supprimer la `@media` le ferait
 * disparaître, et personne ne reviendrait dire que sa liste est illisible. */
@container (max-width: 420px) {
  .work li { flex-wrap: wrap; }
  .work li div { flex: 1 1 100%; }
  .work li button { flex: 1; }
  .work li .ghost { flex: 0 0 var(--tap); }
}

/* — livrer : le geste qui manquait —
 * Un chantier terminé n'est pas livré ; son travail dort sur une branche. Le bouton porte
 * la couleur d'accent pleine, parce que c'est la seule action de la carte qui change
 * quelque chose hors de la machine. */
.ship { padding-inline: var(--s5); }
.done { color: var(--ok); font-size: var(--t7); padding-inline: var(--s3); }

/* — détails d'une confirmation —
 * Approuver « livrer » sans voir la destination n'est pas une approbation. */
.details { margin: 0; display: grid; gap: var(--s2); }
.details div { display: flex; gap: var(--s3); padding: var(--s2) 0; border-bottom: 1px solid var(--line); }
.details dt { flex: 0 0 40%; margin: 0; color: var(--mist); font-size: var(--t3); }
.details dd { flex: 1; margin: 0; font-size: var(--t4); overflow-wrap: anywhere; }


/* Le logo du produit dans l'en-tête : c'est à sa place qu'on juge s'il fonctionne, pas
 * dans une feuille de choix. */
/* `cover` : le logo d'un produit peut être une photo, donc rectangulaire. Sans lui, une
 * image large était ÉCRASÉE dans le carré de l'en-tête — un visage étiré, qu'on croit
 * d'abord mal découpé à la source. On recadre, on ne déforme pas. */
.mark { width: 28px; height: 28px; border-radius: var(--radius-sm); flex: 0 0 auto; object-fit: cover; }

