/* Socle de lisibilité, pas une identité visuelle : largeur de ligne bornée,
   polices du système, un peu d'air. Le thème et la décoration viendront quand
   il y aura des pages à décorer. */

:root {
	--encre: #1b1b1b;
	--papier: #fdfdfb;
	--trait: #d8d4cc;
	--lien: #7a4b1e;
	--alerte: #8c2f16;
	--alerte-fond: #fbf0ec;
}

* {
	box-sizing: border-box;
}

body {
	margin: 0;
	background: var(--papier);
	color: var(--encre);
	font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	font-size: 1.05rem;
	line-height: 1.6;
}

header,
main,
footer {
	max-width: 42rem;
	margin: 0 auto;
	padding: 1rem;
}

header {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.5rem;
	align-items: baseline;
	border-bottom: 1px solid var(--trait);
}

.marque {
	font-weight: 700;
	font-size: 1.25rem;
	text-decoration: none;
	color: inherit;
}

nav {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
}

a {
	color: var(--lien);
}

h1 {
	font-size: 1.6rem;
	line-height: 1.25;
}

footer {
	border-top: 1px solid var(--trait);
	color: #6b675f;
	font-size: 0.9rem;
}

/* L'en-tête du compte est poussé au bout de la ligne : la marque et la
   navigation gardent leur ordre de lecture, le compte se trouve là où on le
   cherche. margin-left plutôt qu'un justify-content sur l'en-tête, qui
   écarterait aussi la marque de la navigation. */
.compte {
	display: flex;
	align-items: baseline;
	gap: 0.75rem;
	margin-left: auto;
}

/* Le message d'échec se distingue par la couleur et par le trait, pas par la
   seule couleur : celle-ci ne se voit pas de tous les yeux, et role="alert"
   ne porte que pour les lecteurs d'écran. */
.erreur {
	border-left: 3px solid var(--alerte);
	padding: 0.5rem 0.75rem;
	background: var(--alerte-fond);
	color: var(--alerte);
}

/* La photo occupe la largeur de la colonne sans jamais la dépasser, et garde
   ses proportions : la miniature 800x0 n'a qu'une largeur imposée, sa hauteur
   dépend de l'original. */
.illustration {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 4px;
}

/* Portions, durées, type de plat, saisons, tags, auteur : des couples
   libellé/valeur qui se lisent en diagonale, donc sur une ligne chacun plutôt
   qu'en colonnes — un tableau à deux colonnes casserait sur un téléphone. */
.faits {
	margin: 1rem 0;
}

.faits dt {
	display: inline;
	font-weight: 600;
}

.faits dt::after {
	content: " : ";
}

.faits dd {
	display: inline;
	margin: 0;
}

.faits dd::after {
	content: "";
	display: block;
}

/* Les puces n'apportent rien à une liste d'ingrédients déjà alignée, et
   mangent de la marge sur un écran étroit. */
.ingredients {
	list-style: none;
	padding: 0;
}

.ingredients li {
	padding: 0.15rem 0;
	border-bottom: 1px solid var(--trait);
}

.aliment {
	font-weight: 600;
}

/* La note se distingue de l'aliment sans être reléguée : c'est de
   l'information utile en cuisine, pas une annotation de bas de page. */
.note {
	font-style: italic;
}

.facultatif {
	color: #6b675f;
	font-size: 0.9em;
}

.etapes {
	padding-left: 1.5rem;
}

.etapes li {
	margin-bottom: 0.5rem;
}

/* Ce que la suppression d'une recette emporte avec elle. Les puces restent :
   c'est un inventaire qu'on relit avant de trancher, pas une liste de plus. */
.emporte {
	margin: 0.4rem 0;
	padding-left: 1.2rem;
}

/* Le champ de recherche et son bouton sur une ligne : le bouton n'existe que
   pour qui n'a pas JavaScript, il ne doit pas prendre la place du champ. */
.recherche {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem;
	margin: 1rem 0;
}

.recherche input {
	flex: 1 1 14rem;
	padding: 0.4rem 0.6rem;
	border: 1px solid var(--trait);
	border-radius: 3px;
	font: inherit;
}

/* La barre des types se replie sur plusieurs lignes plutôt que de déborder :
   la collection en porte huit à l'installation, et rien n'empêche d'en ajouter
   depuis l'administration. */
.types ul {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 0.75rem;
	margin: 0 0 1rem;
	padding: 0;
	list-style: none;
	font-size: 0.9rem;
}

/* Le filtre posé se lit comme une phrase, et sa sortie est à côté de son nom :
   un critère posé d'un clic doit se retirer d'un clic. */
.filtre-actif {
	margin: 0 0 1rem;
	color: #6b675f;
	font-size: 0.9rem;
}

.filtre-actif .nom {
	font-weight: 600;
	color: inherit;
}

/* La barre des filtres, sous la recherche : une ligne discrète, qui ne dispute
   pas la place au champ de recherche ni à la grille. */
.filtres {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.75rem;
	margin: 0 0 1rem;
	font-size: 0.9rem;
}

/* Un filtre posé doit se lire comme une phrase, et porter sa sortie à côté de
   lui : sans ça, un clic n'a pas de retour. */
.filtre-saison {
	margin: 0;
	color: #6b675f;
}

.de-saison {
	padding: 0.15rem 0.6rem;
	border: 1px solid var(--trait);
	border-radius: 999px;
	text-decoration: none;
}

/* La grille se règle sur la largeur disponible plutôt que sur un nombre de
   colonnes : la même page tient sur un téléphone et sur un écran large. */
.grille {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
	gap: 1.25rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.vignette {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	padding-bottom: 0.75rem;
	border-bottom: 1px solid var(--trait);
}

/* Le titre porte le lien, et l'image vit dedans : toute la vignette est
   cliquable sans qu'un lecteur d'écran annonce deux liens pour une recette. */
.titre {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	font-weight: 600;
	text-decoration: none;
}

.titre:hover,
.titre:focus {
	text-decoration: underline;
}

/* Hauteur fixée par le format de la miniature : sans elle, la grille saute au
   fur et à mesure que les images arrivent. */
.miniature {
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	background: var(--trait);
	border-radius: 3px;
}

.type-de-plat {
	margin: 0;
	color: #6b675f;
	font-size: 0.9rem;
}

.tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem;
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: 0.85rem;
}

.tags li {
	padding: 0.05rem 0.45rem;
	border: 1px solid var(--trait);
	border-radius: 999px;
}

/* Le filtre actif se lit avant les résultats, et porte sa sortie avec lui :
   un filtre posé d'un clic doit se retirer d'un clic. */
.filtre {
	margin: 0 0 1rem;
	font-size: 0.9rem;
	color: #6b675f;
}

/* L'absence de résultat se lit comme une phrase, pas comme une erreur : ce
   n'est pas une panne, c'est une réponse. */
.absence {
	color: #6b675f;
}

/* Les suggestions se posent sous le champ, en une ligne qui va à la ligne :
   elles proposent, elles n'occupent pas la page. Vides, elles ne laissent
   aucun creux — la liste n'a alors ni bordure ni marge à elle. */
.suggestions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem;
	margin: 0.35rem 0 0;
	padding: 0;
	list-style: none;
}

.suggestions button {
	padding: 0.1rem 0.55rem;
	border: 1px solid var(--trait);
	border-radius: 999px;
	background: none;
	font: inherit;
	font-size: 0.85rem;
	cursor: pointer;
}

.pagination {
	display: flex;
	justify-content: space-between;
	gap: 1rem;
	margin-top: 1.5rem;
}

/* Le formulaire est une colonne : une étiquette, son champ, et de l'air entre
   les deux. Pas de grille à deux colonnes, qui casse sur téléphone là où
   l'essentiel de la saisie d'une recette se fait. Les formulaires du lot et de
   l'établi suivent les mêmes règles, groupées et non recopiées : trois copies
   divergeraient au premier réglage. */
.formulaire-recette,
.formulaire-lot,
.formulaire-etabli {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
}

.formulaire-recette label,
.formulaire-lot label,
.formulaire-etabli label {
	margin-top: 0.75rem;
}

.formulaire-recette input,
.formulaire-recette select,
.formulaire-recette textarea,
.formulaire-lot textarea,
.formulaire-etabli textarea {
	font: inherit;
	padding: 0.4rem;
	border: 1px solid var(--trait);
	background: var(--papier);
	color: inherit;
}

.formulaire-recette button,
.formulaire-lot button,
.formulaire-etabli button {
	font: inherit;
	margin-top: 1.5rem;
	padding: 0.5rem 1rem;
	align-self: flex-start;
}

/* L'aperçu de l'image que le site d'origine propose. Elle est distante et
   n'est pas encore attachée à la recette : une hauteur bornée, pour qu'une
   bannière de 3000 pixels ne pousse pas le reste du formulaire hors de vue. */
.apercu-distant {
	max-width: 100%;
	max-height: 12rem;
	object-fit: contain;
	align-self: flex-start;
}

/* Une case à cocher et son libellé sur la même ligne : sans cette règle, le
   flex du formulaire les empilerait l'un sous l'autre. */
.case {
	display: flex;
	align-items: baseline;
	gap: 0.5rem;
}

.case input {
	width: auto;
}

/* Le choix de la source, dans l'établi : les deux options tiennent ensemble
   plutôt que de flotter entre les champs du formulaire. Sans marge propre, le
   fieldset se collerait à l'étiquette du champ suivant. */
.sources {
	margin: 0.75rem 0 0;
	padding: 0.75rem;
	border: 1px solid var(--trait);
}

.saisons {
	margin-top: 0.75rem;
	border: 1px solid var(--trait);
}

/* Les notes de cuisine : un journal, pas une discussion. Pas d'avatar, pas de
   fil indenté, pas de cadre — la signature en petit, le texte à la ligne, et
   un trait pour séparer deux notes. */
.commentaires {
	margin-top: 2.5rem;
	border-top: 1px solid var(--trait);
}

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

.note-de-cuisine {
	padding: 1rem 0;
	border-bottom: 1px solid var(--trait);
}

.signature {
	margin: 0 0 0.5rem;
	font-size: 0.9rem;
	color: #6b6459;
}

/* Le lien et le bouton de la même note sur une seule ligne : le formulaire de
   suppression est un bloc, et l'empilerait sinon sous le lien de modification. */
.actions {
	display: flex;
	align-items: baseline;
	gap: 1rem;
	font-size: 0.9rem;
}

.ajout-de-note {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	margin-top: 1.5rem;
}

.ajout-de-note textarea {
	font: inherit;
	padding: 0.4rem;
	border: 1px solid var(--trait);
	background: var(--papier);
	color: inherit;
}

.ajout-de-note button {
	font: inherit;
	padding: 0.5rem 1rem;
	align-self: flex-start;
}

/* Le champ « coller l'URL » : la même colonne que le formulaire de recette,
   pour un champ unique et son bouton. */
.formulaire-import {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
}

.formulaire-import input {
	font: inherit;
	padding: 0.4rem;
	border: 1px solid var(--trait);
	background: var(--papier);
	color: inherit;
}

.formulaire-import button {
	font: inherit;
	margin-top: 1rem;
	padding: 0.5rem 1rem;
	align-self: flex-start;
}

/* Le disclaimer du lot : lisible, et collé au bouton qu'il précède. Pas la
   couleur de l'alerte — une alerte permanente cesse d'en être une, et celle-ci
   s'affiche à chaque visite. */
.avertissement {
	margin: 1.5rem 0 0;
	padding: 0.6rem 0.8rem;
	border-left: 3px solid var(--trait);
	color: #6b675f;
	font-size: 0.9rem;
}

/* Les lignes qu'un lot n'a pas retenues, et ce qu'on leur reproche. */
.ecartees {
	margin: 0;
	padding-left: 1.2rem;
}

.ecartee {
	margin-bottom: 0.3rem;
}

/* Le suivi d'une fournée : la progression pendant qu'elle tourne, le rapport
   ensuite. Les deux vivent au même endroit de la page — le fragment se
   remplace lui-même —, donc ils partagent l'espace qui les entoure. */
.progression,
.fournee {
	margin: 0.4rem 0;
}

/* Le compte traité sur le total est ce qu'on lit en revenant sur la page :
   il se détache du reste sans crier. */
.progression {
	font-size: 1.1rem;
}

/* La dernière recette entrée : un titre venu d'un site tiers, en retrait, qui
   dit que la fournée avance encore. */
.derniere {
	margin: 0.4rem 0;
	color: #6b675f;
}

/* Les comptes du rapport, et le détail des échecs par famille. Une même règle
   pour les deux listes : les distinguer visuellement laisserait croire qu'on
   ne les lit pas de la même façon. */
.familles {
	margin: 0 0 1rem;
	padding-left: 1.2rem;
}

.famille {
	margin-bottom: 0.2rem;
}

/* Les adresses qui n'ont pas abouti. Le <code> les garde sélectionnables d'un
   bloc, pour qu'elles se reprennent à la main dans l'import unitaire. */
.echecs {
	margin: 0;
	padding-left: 1.2rem;
}

.echec {
	margin-bottom: 0.3rem;
}

/* La cause, à côté de l'adresse et non à sa place : c'est elle qui dit s'il
   vaut la peine de réessayer. */
.cause {
	color: #6b675f;
}

/* Une adresse reprise : l'utilisateur a déclaré s'en être occupé. Atténuée et
   non barrée — elle reste en échec, et reste à recopier dans l'import
   unitaire. */
.reprise {
	color: #6b675f;
}

/* Le compte des reprises sur le total des échecs, au-dessus de la liste :
   c'est ce qui reste à faire, d'un coup d'œil, et c'est ce qu'on vient relire
   en revenant sur la page. */
.reprises {
	margin: 0.4rem 0 0.8rem;
	font-size: 1.1rem;
}

/* La case d'une ligne reste sur la ligne : un formulaire est un bloc, et
   l'empilerait sinon sous la cause. */
.bascule-reprise {
	display: inline;
	margin-left: 0.5rem;
}

/* La liste des fournées, sous le formulaire de saisie. Détachée par un trait,
   comme les notes de cuisine sous une recette : c'est le même geste — ce qui a
   déjà été fait, sous ce qu'on est en train de faire. */
.fournees {
	margin-top: 2.5rem;
	border-top: 1px solid var(--trait);
}

.liste-fournees {
	margin: 0;
	padding-left: 1.2rem;
}

.fournee-listee {
	margin-bottom: 0.3rem;
}

/* Un compte qui n'a encore rien lancé lit une phrase : une section vide passe
   pour une panne. */
.aucune-fournee {
	color: #6b675f;
}

/* La vue agrégée de l'établi : quelle passe on lit, dans quel ordre, et sous
   quel filtre. Trois phrases au-dessus d'un tableau, qui disent ce qu'on
   regarde — une liste de milliers de lignes sans en-tête ne se relit pas. */
.passe,
.bascule {
	margin: 0.4rem 0;
	color: #6b675f;
	font-size: 0.9rem;
}

/* Les quatre ordres de lecture, côte à côte comme la barre des types. */
.tris ul {
	display: flex;
	flex-wrap: wrap;
	gap: 0.8rem;
	margin: 0.8rem 0;
	padding: 0;
	list-style: none;
}

/* L'ordre en cours se lit comme les autres, mais ne se clique pas : un lien
   vers la page où l'on est déjà est un lien qui ment. */
.tri-actif {
	font-weight: 600;
}

/* Le tableau des groupes. Un vrai tableau, et non la grille des vignettes :
   ce sont cinq valeurs alignées d'une ligne à l'autre, et c'est l'alignement
   qui fait qu'on repère l'intrus en descendant la colonne. */
.groupes {
	width: 100%;
	margin: 1rem 0;
	border-collapse: collapse;
	font-size: 0.95rem;
}

.groupes th {
	padding: 0.4rem 0.5rem;
	border-bottom: 1px solid var(--trait);
	text-align: left;
	font-weight: 600;
}

.groupe td {
	padding: 0.4rem 0.5rem;
	border-bottom: 1px solid var(--trait);
	vertical-align: top;
}

/* La clé du groupe : c'est elle qu'on cherche des yeux en descendant. */
.aliment-canonique {
	font-weight: 600;
}

.categorie {
	color: #6b675f;
}

/* Les signaux, en pastilles : ce qui attire l'œil sur la ligne. */
.signaux {
	line-height: 1.8;
}

.signal {
	padding: 0.1rem 0.4rem;
	border: 1px solid var(--trait);
	border-radius: 0.8rem;
	white-space: nowrap;
	font-size: 0.85rem;
}

/* Les deux poids, à droite et en chiffres alignés : une colonne de nombres
   qui ne s'aligne pas ne se compare pas. */
.formes,
.occurrences {
	text-align: right;
	font-variant-numeric: tabular-nums;
}

/* La page détail de l'établi : les formes distinctes d'une passe, leur lecture
   champ à champ, et le va-et-vient avec le groupe qui les range.

   La dernière colonne de la vue agrégée descend ici : elle se lit comme un
   lien ordinaire, sans peser plus que la clé du groupe. */
.detail {
	white-space: nowrap;
	font-size: 0.9rem;
}

/* Le tableau des formes. Dix colonnes étroites plutôt qu'une phrase par ligne :
   la lecture du parser se relit en descendant une colonne, et c'est ce qui
   fait ressortir la ligne où l'unité a été prise pour l'aliment. */
.formes-lues {
	width: 100%;
	margin: 1rem 0;
	border-collapse: collapse;
	font-size: 0.9rem;
}

.formes-lues th {
	padding: 0.4rem 0.5rem;
	border-bottom: 1px solid var(--trait);
	text-align: left;
	font-weight: 600;
}

.forme td {
	padding: 0.4rem 0.5rem;
	border-bottom: 1px solid var(--trait);
	vertical-align: top;
}

/* La ligne brute, telle que le corpus la porte : c'est elle qu'on lit en
   premier, et c'est elle qu'on compare à ce que le parser en a fait. */
.brut {
	font-weight: 600;
}

/* Les champs de la lecture. Le gris les met derrière la ligne brute : ce sont
   des valeurs dérivées, pas la source.

   « note » et « facultatif » ne sont pas inédites — la fiche recette les porte
   sur ses lignes d'ingrédients (ligne 146). Posées nues ici, en fin de feuille
   et à spécificité égale, elles gagneraient là-bas aussi et repeindraient une
   page que l'établi ne touche pas. Elles se portent donc par le conteneur de
   chacun des deux écrans : le tableau des formes, et la lecture de la fiche. */
.quantite,
.unite,
.partitif,
.aliment-lu,
.motif,
.forme td.note,
.forme td.facultatif,
.lecture dd.note,
.lecture dd.facultatif {
	color: #4a463f;
}

.quantite {
	text-align: right;
	font-variant-numeric: tabular-nums;
}

/* Le groupe sous lequel la forme est rangée, sur la ligne comme sur la fiche :
   c'est le chemin de remontée, et il se voit. */
.rangement {
	font-size: 0.9rem;
}

/* La fiche d'une forme : son poids, sa lecture, et d'où elle vient. */
.poids {
	margin: 0.4rem 0;
	color: #6b675f;
	font-size: 0.9rem;
}

.lecture {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: 0.3rem 1rem;
	margin: 1rem 0;
}

.lecture dt {
	color: #6b675f;
	font-size: 0.9rem;
}

.lecture dd {
	margin: 0;
}

/* La provenance : les recettes du carnet qui portent cette ligne. Une liste
   nue, chaque entrée menant à sa fiche. */
.provenance {
	margin: 0.5rem 0;
	padding-left: 1.2rem;
}

.origine {
	margin-bottom: 0.2rem;
}

/* La borne, dite quand elle mord : une liste tronquée en silence se lit comme
   une liste complète. */
.bornee,
.sans-provenance {
	color: #6b675f;
	font-size: 0.9rem;
}

/* L'annotation : le verdict qu'un œil humain dépose, et qu'on garde.

   Les classes sont neuves et aucune n'est portée ailleurs sur le site : la
   feuille est commune et plate, et une règle nue reprenant un nom déjà employé
   repeindrait l'autre page sans qu'aucune erreur ne le dise. */
.annotations {
	margin: 1.5rem 0;
}

.annotation-posee {
	border-left: 3px solid #d8d2c4;
	padding-left: 0.8rem;
	margin-bottom: 0.8rem;
}

/* Le verdict se lit d'un coup d'œil : c'est lui qui dit qu'une cible est
   tranchée, et sous quel moteur elle l'a été. */
.verdict {
	display: inline-block;
	background: #efe9db;
	border-radius: 0.2rem;
	padding: 0.05rem 0.4rem;
	margin: 0 0.3rem 0.2rem 0;
	font-size: 0.9rem;
}

.verdicts {
	white-space: normal;
}

/* Les deux champs, et ils ne se ressemblent pas : ce qui pourra partir est
   affirmatif, ce qui reste ici est en retrait. C'est la seule marque visuelle
   de la séparation, et elle vaut mieux qu'une légende. */
.note-partageable {
	margin: 0.2rem 0;
}

.note-locale {
	margin: 0.2rem 0;
	color: #6b675f;
	font-size: 0.9rem;
}

.lecture-attendue {
	margin: 0.2rem 0;
	font-size: 0.9rem;
}

/* Le formulaire, rendu aux deux niveaux. */
.annotation {
	display: grid;
	gap: 0.3rem;
	margin: 0.8rem 0;
}

/* Les libellés du formulaire enveloppent leur champ — un identifiant se
   répéterait d'une ligne ouverte à l'autre : le champ passe sous son texte.
   Par l'enfant direct, pour laisser la lecture attendue à sa propre grille. */
.annotation > label,
.saisie-des-verdicts label {
	display: grid;
	gap: 0.2rem;
}

.annotation-ouverte {
	background: #faf7f0;
}

.lecture-attendue-saisie {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: 0.3rem 0.8rem;
	align-items: center;
	border: 1px solid #d8d2c4;
	padding: 0.5rem 0.8rem;
}

/* Le bouton qui ouvre le formulaire sur la ligne : discret, la ligne elle-même
   étant ce qu'on lit. */
.annoter {
	font-size: 0.85rem;
}
