/* Console de gestion, dense, legible, no framework.
   One tool used by three people who each look at one screen. */

:root {
	--fond: #f6f7f8;
	--carte: #fff;
	--bord: #dfe3e6;
	--texte: #1c2125;
	--doux: #667079;
	--accent: #0f6b4f;
	--accent-clair: #e6f2ed;
	--rouge: #a32020;
	--rouge-clair: #fbeaea;
	--ambre: #8a5a00;
	--ambre-clair: #fdf3e0;
	/* L'ambre de la palette est une couleur de TEXTE : assez sombre pour se
	   lire sur fond clair. Sur une pastille de 8 px elle vire au brun et se
	   confond avec le rouge. Il faut donc une version vive, qui ne sert qu'aux
	   aplats. */
	--ambre-vif: #e8930c;
	--orange: #b4520a;
	--orange-clair: #fce8d8;
	--bleu: #1b4f8a;
	--bleu-clair: #e8f0f9;
	/* Le violet des commandes en cours, remonté en variable : il servait déjà
	   dans la pastille d'état, il sert maintenant au survol de la puce de
	   carte, et deux endroits qui portent la même couleur doivent la lire au
	   même endroit. */
	--violet: #553a96;
	--violet-clair: #ece7f8;
	/* Un filet plus léger que --bord, pour ce qui doit se voir sans se poser
	   en cadre : la puce de carte, par exemple. */
	--bord-doux: #edf0f2;
	/* Une seule durée pour tous les changements d'état au survol. Écrite ici,
	   elle se change en un endroit au lieu de vingt. */
	--transition: .3s ease;
	/* Bande alternée des tableaux : assez pour grouper l'oeil, pas assez pour
	   se lire comme un état. Les couleurs d'état ont leur propre palette. */
	--bande: #eef1f3;
	color-scheme: light;
}

* { box-sizing: border-box; }

body {
	margin: 0;
	font: 14px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
	color: var(--texte);
	background: var(--fond);
}

a { color: var(--bleu); }
a { transition: color var(--transition); }
a:hover { color: #0d3f6e; }

/* ---- Chrome ------------------------------------------------------------ */

header.top {
	display: flex;
	align-items: center;
	gap: 24px;
	padding: 0 20px;
	background: #12201c;
	color: #eaf1ee;
}

header.top .marque {
	font-weight: 700;
	letter-spacing: .02em;
	padding: 14px 0;
	white-space: nowrap;
	color: #eaf1ee;
	text-decoration: none;
}

header.top .marque:hover span { color: #a8dcc4; }

header.top .marque span { color: #7fc4a8; font-weight: 400; }

nav.principal { display: flex; gap: 2px; flex: 1; }

nav.principal a {
	color: #b9c9c3;
	text-decoration: none;
	padding: 15px 12px;
	border-bottom: 3px solid transparent;
}

nav.principal a:hover { color: #fff; background: rgba(255,255,255,.06); }
nav.principal a.actif { color: #fff; border-bottom-color: #4fae87; }

/* Count bubble, the WordPress way: round, coloured, and only there when
   something is actually waiting. */
nav.principal .bulle {
	display: inline-block;
	min-width: 18px;
	height: 18px;
	margin-left: 6px;
	padding: 0 5px;
	border-radius: 9px;
	background: #c9402f;
	color: #fff;
	font-size: 11px;
	font-weight: 600;
	line-height: 18px;
	text-align: center;
	vertical-align: 1px;
}

header.top .compte { font-size: 13px; color: #9fb3ac; display: flex; gap: 12px; align-items: center; }
header.top .compte form { margin: 0; }
header.top .compte button {
	background: none; border: 1px solid #3a5049; color: #b9c9c3;
	border-radius: 4px; padding: 4px 10px; cursor: pointer; font-size: 12px;
}
header.top .compte button:hover { border-color: #7fc4a8; color: #fff; }

main { padding: 20px; max-width: 1500px; }

h1 { font-size: 20px; margin: 0 0 4px; }
h2 { font-size: 15px; margin: 24px 0 8px; }
p.sous { color: var(--doux); margin: 0 0 18px; max-width: none; }

/* ---- Cards and stats --------------------------------------------------- */

/* The stat cards are a summary, the filters below are controls: the gap says
   they are two different things. */
.stats { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 56px; }

.stat {
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: 6px;
	padding: 12px 16px;
	min-width: 150px;
}

.stat .valeur { font-size: 22px; font-weight: 650; line-height: 1.1; }
.stat .label { color: var(--doux); font-size: 12px; margin-top: 3px; }
.stat.alerte .valeur { color: var(--rouge); }

.carte {
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: 6px;
	overflow: hidden;
	margin-bottom: 20px;
}

/* ---- Tables ------------------------------------------------------------ */

.table-wrap { overflow-x: auto; }

table { border-collapse: collapse; width: 100%; font-size: 13px; }

th {
	text-align: left;
	font-weight: 600;
	color: var(--doux);
	background: #f0f2f4;
	padding: 8px 10px;
	border-bottom: 1px solid var(--bord);
	white-space: nowrap;
	position: sticky;
	top: 0;
}

td { padding: 8px 10px; border-bottom: 1px solid #eef1f3; vertical-align: top; }
tr:last-child td { border-bottom: 0; }
/* Bande alternée de la liste des commandes. Très pâle : elle sert à suivre une
   ligne du regard jusqu'au bout d'un tableau large, pas à découper la page.
   
   Le fond passe par une variable posée sur la LIGNE plutôt que par une couleur
   écrite sur la cellule : sinon la bande, plus spécifique qu'un simple
   `tr.choisie td`, écraserait la sélection et le survol une ligne sur deux.
   Toutes ces règles ont ici la même spécificité, c'est donc leur ordre qui
   tranche, du plus général au plus précis. */
table.table-commandes tbody > tr > td { background: var(--fond-ligne, transparent); }

.table-commandes tr:nth-child(even) { --fond-ligne: #f7f9fa; }
.table-commandes tr.choisie { --fond-ligne: #eef6f2; }
.table-commandes tr:hover { --fond-ligne: #eef3f6; }
.table-commandes tr.choisie:hover { --fond-ligne: #e6f1eb; }

tr:hover td { background: #fafbfc; }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
td.sku { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; white-space: nowrap; }
td.lib { min-width: 240px; }

/* ---- Order contents ----------------------------------------------------- */

/* One row per article, each on its own line with a hairline between them, and
   the label cut with an ellipsis rather than wrapping into a paragraph: an
   order of eleven lines has to stay one glanceable block. The full labels are
   one hover away. */
/* The customer column is identification, not reading: two truncated lines are
   enough, and the width goes to the order contents instead. */
td.client { max-width: 132px; }
td.client .nom, td.client .muet { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

td.contenu { max-width: 430px; }

.articles { display: flex; flex-direction: column; }

.articles .art {
	display: grid;
	/* Hauteur de ligne déclarée, et non héritée : la led se place par rapport à
	   elle, et une valeur implicite la rendrait impossible à calculer. */
	line-height: 1.5;
	/* max-content on the quantity: "244 ×" must not wrap onto two lines. */
	grid-template-columns: max-content max-content minmax(0, 1fr);
	gap: 8px;
	align-items: baseline;
	padding: 4px 0;
	border-top: 1px solid #eef1f3;
}

/* Une colonne fixe pour la led, seulement sur les lignes qui en portent une :
   la liste des devis réutilise ces mêmes classes sans led, et lui imposer une
   quatrième colonne écrasait la quantité sur la référence. La colonne est
   gardée même quand la led est vide, sinon les libellés d'une même commande
   ne s'alignent plus entre eux. */
.articles .art:has(.led) {
	grid-template-columns: 8px max-content max-content minmax(0, 1fr);
}

/* La led se centre sur la PREMIÈRE ligne du libellé, pas sur la hauteur totale
   de la cellule : quand un nom d'article passe sur deux lignes, un centrage
   vertical la ferait descendre entre les deux. On la colle donc en haut, puis
   on la redescend de la moitié de ce qui reste d'une ligne de texte. */
.articles .art .led {
	align-self: start;
	width: 8px;
	height: 8px;
	margin: calc((1.5em - 8px) / 2) 0 0;
}

.articles .art .led.vide { background: transparent; }

.articles .art:first-child { border-top: 0; padding-top: 0; }
.articles .art:last-child { padding-bottom: 0; }

.articles .qte { color: var(--doux); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* La référence est une donnée d'appoint, pas une destination : en bleu elle se
   lisait comme un lien et invitait à un clic qui n'existe pas. Même gris que
   dans la fiche, pour que la même information ait partout la même allure. */
.articles .ref {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 11.5px;
	color: var(--doux);
	white-space: nowrap;
}

.articles .nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.articles .plus { color: var(--doux); font-size: 11.5px; padding-top: 4px; }

td.contenu[data-tip] { cursor: help; }
td.contenu[data-tip]:hover .nom { color: var(--texte); }

/* ---- Tooltip ------------------------------------------------------------ */

/* Rendered on <body> and positioned fixed: inside .table-wrap (overflow: auto)
   an absolutely positioned tooltip would be clipped by its own scroller. */
#tip {
	position: fixed;
	z-index: 60;
	/* Never wider than the viewport on a narrow window; the height cap is set
	   by the placement code, which knows the actual room left. */
	max-width: min(540px, calc(100vw - 24px));
	overflow: hidden;
	padding: 11px 13px;
	border-radius: 7px;
	background: #12201c;
	color: #e7efec;
	font-size: 12.5px;
	line-height: 1.45;
	box-shadow: 0 10px 30px rgba(10, 25, 20, .28);
	pointer-events: none;
	opacity: 0;
	transform: translateY(-3px);
	transition: opacity .3s ease, transform .3s ease;
}

@media (prefers-reduced-motion: reduce) {
	#tip { transition: none; }
}

#tip.on { opacity: 1; transform: translateY(0); }

#tip .titre {
	color: #7fc4a8;
	font-weight: 600;
	margin-bottom: 7px;
	padding-bottom: 6px;
	border-bottom: 1px solid rgba(255, 255, 255, .1);
}

#tip .art {
	display: grid;
	/* max-content on the quantity: "244 ×" must stay on one line here too. */
	grid-template-columns: max-content max-content 1fr auto;
	gap: 12px;
	padding: 4px 0;
	align-items: baseline;
}

#tip .art .qte { white-space: nowrap; }

#tip .art + .art { border-top: 1px solid rgba(255, 255, 255, .07); }
#tip .qte { color: #9fb3ac; font-variant-numeric: tabular-nums; }
#tip .ref { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px; color: #8fd0b4; white-space: nowrap; }
#tip .nom { color: #eaf1ee; }
#tip .prix { color: #9fb3ac; font-variant-numeric: tabular-nums; white-space: nowrap; }
#tip .vide { color: #9fb3ac; }

/* ---- Badges ------------------------------------------------------------ */

.b {
	display: inline-block;
	padding: 2px 7px;
	border-radius: 3px;
	font-size: 11.5px;
	font-weight: 600;
	white-space: nowrap;
}

.b.ok { background: var(--accent-clair); color: var(--accent); }
.b.ko { background: var(--rouge-clair); color: var(--rouge); }
/* Un remboursement n'est pas une annulation : la vente a eu lieu, l'argent est
   reparti. Orange soutenu pour ne pas le confondre avec le rouge des échecs. */
.b.rembourse { background: var(--orange-clair); color: var(--orange); }
.b.attente { background: var(--ambre-clair); color: var(--ambre); }
.b.neutre { background: #eef1f3; color: var(--doux); }
.b.info { background: var(--bleu-clair); color: var(--bleu); }
.b.encours { background: var(--violet-clair); color: var(--violet); }

/* One colour per shop, so a flow is recognised before it is read. Kept off the
   red/green axis used by stock states: these say WHERE, not whether it is bad. */
.b.s-aql { background: #e3f1e9; color: #14664a; }
.b.s-hpl { background: #e4eefb; color: #1a4f8f; }
.b.s-ba  { background: #ece7f8; color: #553a96; }
.b.s-jm  { background: #f3eee4; color: #7a5a22; }

.age { color: var(--doux); font-size: 11.5px; white-space: nowrap; }
.age.vieux { color: var(--ambre); }
.age.inconnu { color: var(--rouge); }

.muet { color: var(--doux); }
.petit { font-size: 12px; }

/* ---- Filters ----------------------------------------------------------- */

.filtres {
	display: flex;
	flex-wrap: wrap;
	gap: 5px;
	align-items: center;
	margin-bottom: 12px;
}

/* Compact pills: a filter row is navigation, not content. */
.filtres a, .filtres .pilule {
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: 4px;
	padding: 2px 9px;
	text-decoration: none;
	color: var(--texte);
	font-size: 12px;
	line-height: 1.6;
}

/* Two columns: the filter families stack on the left, the period sits on the
   right, and the whole block hugs the table instead of floating above it. */
/* flex-end: the left column is two rows tall, so the period lines up with its
   LAST row and sits as close to the table as the filters do. */
.barre-filtres {
	display: flex;
	align-items: flex-end;
	gap: 24px;
	margin-bottom: 8px;
}

.col-filtres { display: flex; flex-direction: column; gap: 4px; }
.barre-filtres .filtres { margin-bottom: 0; }
.barre-filtres .periodes { margin-left: auto; }

/* One family per row: the labels line up, so do the pills. */
.filtres > .muet:first-child { min-width: 118px; }

.filtres a:hover { border-color: #9aa5ad; }
.filtres a.actif { background: var(--texte); color: #fff; border-color: var(--texte); }
.filtres a .n { color: var(--doux); margin-left: 5px; font-size: 12px; }
.filtres a.actif .n { color: #c9d2d8; }

input[type=search], input[type=text], input[type=password] {
	font: inherit;
	padding: 6px 10px;
	border: 1px solid var(--bord);
	border-radius: 4px;
	background: var(--carte);
	min-width: 220px;
}

button.primaire {
	font: inherit;
	font-weight: 600;
	padding: 7px 16px;
	border: 0;
	border-radius: 4px;
	background: var(--accent);
	color: #fff;
	cursor: pointer;
}

button.primaire:hover { background: #0c5740; }

/* ---- Login ------------------------------------------------------------- */

.connexion {
	max-width: 340px;
	margin: 12vh auto;
	background: var(--carte);
	border: 1px solid var(--bord);
	border-radius: 8px;
	padding: 26px;
}

.connexion h1 { font-size: 17px; margin-bottom: 16px; }
.connexion label { display: block; font-size: 12px; color: var(--doux); margin: 12px 0 4px; }
.connexion input { width: 100%; }
.connexion button { width: 100%; margin-top: 18px; }
.connexion .erreur { background: var(--rouge-clair); color: var(--rouge); padding: 8px 10px; border-radius: 4px; font-size: 13px; }

/* ---- Source freshness --------------------------------------------------- */

/* One dot in the header, detail on hover: freshness matters when a source goes
   quiet, not on every screen at all times. */
.sources-etat {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 4px 9px;
	border: 1px solid #3a5049;
	border-radius: 20px;
	font-size: 12px;
	color: #9fb3ac;
	cursor: help;
}

.sources-etat:hover, .sources-etat:focus { border-color: #7fc4a8; color: #eaf1ee; outline: none; }
.sources-etat b { color: #e3b75a; font-weight: 600; }

.pt { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #4fae87; flex: none; }
.pt.vieux { background: #d59a20; }
.pt.ko { background: #d96464; }

#tip .src { display: flex; justify-content: space-between; gap: 22px; padding: 3px 0; align-items: center; }
#tip .src + .src { border-top: 1px solid rgba(255, 255, 255, .07); }
#tip .src .pt { margin-right: 6px; }

.vide { padding: 28px; text-align: center; color: var(--doux); }

/* ---- Selection ---------------------------------------------------------- */

th.coche, td.coche { width: 30px; padding-right: 0; }
th.coche input, td.coche input { width: 15px; height: 15px; cursor: pointer; accent-color: var(--accent); }

tr.choisie td { background: #eef6f2; }
tr.choisie:hover td { background: #e6f1eb; }

/* Same 12px scale as the filter row above it: this is a toolbar, not content. */
.barre-selection {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 6px 12px;
	margin-bottom: 10px;
	border: 1px solid #cfe0d8;
	border-radius: 6px;
	background: var(--accent-clair);
	font-size: 12px;
}

.barre-selection .compte { color: var(--accent); margin-right: 4px; }

.barre-selection button.primaire {
	font-family: inherit;
	font-size: 12px;
	line-height: 1.6;
	padding: 2px 12px;
}

.barre-selection button.primaire:disabled { background: #9bb8ab; cursor: not-allowed; }

.barre-selection button.lien {
	font-family: inherit;
	font-size: 12px;
	background: none;
	border: 0;
	color: var(--accent);
	text-decoration: underline;
	cursor: pointer;
	margin-left: auto;
}

/* Rows open their detail on click, except where a real control sits. */
tbody tr[data-detail] { cursor: pointer; }
a.numero { font-weight: 600; text-decoration: none; }
a.numero:hover { text-decoration: underline; }

/* ---- Shipping and totals ------------------------------------------------ */

.articles + .port,
td.contenu .port {
	margin-top: 5px;
	padding-top: 5px;
	border-top: 1px dashed var(--bord);
	color: var(--doux);
	font-size: 11.5px;
}

td.contenu .port .muet { margin-left: 4px; }

.note-devis { margin-top: 4px; color: var(--texte); font-style: italic; font-size: 11.5px; }

.valeur-devis { font-size: 19px; font-weight: 650; line-height: 1.2; }

/* A retried order is dead, not urgent: it says so without shouting in red. */
.reprise { color: var(--doux); }
tr:has(.reprise) td { opacity: .72; }
tr:has(.reprise):hover td { opacity: 1; }

td.totaux { line-height: 1.3; }
td.totaux .ttc { font-weight: 600; }
td.totaux .ht { color: var(--doux); font-size: 11.5px; }

#tip .pied {
	margin-top: 8px;
	padding-top: 7px;
	border-top: 1px solid rgba(255, 255, 255, .14);
	color: #b9c9c3;
}

#tip .pied > div { display: flex; justify-content: space-between; gap: 24px; padding: 2px 0; }
#tip .pied .fort { color: #eaf1ee; font-weight: 600; }

/* ---- Order detail ------------------------------------------------------- */

.detail-tete { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin-bottom: 16px; }
.detail-tete h2 { margin: 0 0 3px; font-size: 17px; }
.detail-etat { text-align: right; }

.detail-blocs { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 18px; }

.detail .bloc {
	border: 1px solid var(--bord);
	border-radius: 6px;
	padding: 10px 12px;
	background: var(--carte);
}

.titre-bloc { font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--doux); margin-bottom: 5px; }

/* Un titre de bloc qui porte une action : le libellé à gauche, l'action à
   droite, sur la même ligne de base. */
.titre-bloc.titre-action { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

.titre-bloc .carte {
	display: inline-flex;
	align-items: center;
	color: #4285f4;
	text-decoration: none;
	padding: 2px;
	border-radius: 4px;
	line-height: 0;
}

.titre-bloc .carte:hover { background: var(--violet-clair); }

/* Dans la liste des devis, l'icône et le lieu forment une seule puce
   cliquable. Le survol change son fond plutôt que de souligner le texte : un
   soulignement sur une puce la fait ressembler à deux choses à la fois. */
td.lieu .carte {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 4px 10px 4px 6px;
	border: 1px solid var(--bord-doux);
	border-radius: 4px;
	background: var(--carte);
	color: inherit;
	text-decoration: none;
	line-height: 1.3;
}

/* Le repère reprend le bleu des cartes : il se repère au premier coup d'oeil
   sans tirer l'oeil plus que le lieu lui-même. */
td.lieu .carte svg { color: #4285f4; flex: 0 0 auto; }

td.lieu .carte:hover {
	border-color: var(--violet);
	background: var(--violet-clair);
}

td.lieu .carte:hover span { color: var(--violet); text-decoration: none; }

table.detail-lignes { border: 1px solid var(--bord); border-radius: 6px; }

/* Un article occupe deux lignes de tableau, l'article puis son état de
   préparation. La bande alternée porte sur les DEUX, sinon elle changerait de
   couleur au milieu de chaque article et ne regrouperait plus rien. */
table.detail-lignes tr.bande > td { background: var(--bande); }

/* Pas de filet entre un article et son état : c'est le même bloc. Le filet
   revient sous l'état, là où l'article suivant commence. */
table.detail-lignes tr.article > td { border-bottom: 0; padding-bottom: 4px; }
table.detail-lignes tr.preparation > td { padding-top: 0; }

/* Les trois contrôles se calent à droite, sous la colonne des totaux. Le
   groupe étant en inline-flex, c'est la cellule qui le pousse, pas lui. */
tr.preparation > td { text-align: right; }

tr.preparation > td > .b,
tr.preparation > td > .petit { display: block; text-align: right; }

/* La référence est une donnée d'appoint : lisible, mais elle ne doit pas
   concurrencer le libellé de l'article. */
/* Qté, Réf et Total ne prennent que leur contenu : c'est le libellé de
   l'article qui doit récupérer toute la largeur restante. */
table.detail-lignes th.num,
table.detail-lignes td.num,
table.detail-lignes th:nth-child(2),
table.detail-lignes td.sku { width: 1%; white-space: nowrap; }

table.detail-lignes th.lib,
table.detail-lignes td.lib { width: auto; }

table.detail-lignes td.sku,
table.detail-lignes td.sku a {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 11px;
	color: var(--doux);
	letter-spacing: -.01em;
}

table.detail-lignes td.sku a { text-decoration: none; border-bottom: 1px dotted var(--bord); }
table.detail-lignes td.sku a:hover { color: var(--texte); }

/* Totals as their own block, right-aligned like an invoice: they are not more
   lines of the order, so they do not live in its table. */
.recap {
	width: min(320px, 100%);
	margin: 12px 0 0 auto;
	font-size: 13px;
}

.recap .ligne {
	display: flex;
	justify-content: space-between;
	gap: 18px;
	padding: 5px 0;
	color: var(--doux);
	font-variant-numeric: tabular-nums;
}

.recap .ligne span:last-child { white-space: nowrap; }
.recap .ligne .muet { font-size: 11.5px; }

.recap .total {
	margin-top: 4px;
	padding-top: 9px;
	border-top: 1px solid var(--bord);
	color: var(--texte);
	font-size: 15px;
	font-weight: 650;
}

.detail-liens { display: flex; gap: 16px; margin-top: 16px; }

/* ---- Preparation: address, line states, notes --------------------------- */

.detail .adresse { line-height: 1.5; }

/* The phone is the one thing a picker dials under pressure: readable size,
   grouped in pairs by View::telephone(). */
.detail .tel { font-size: 16px; font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.detail .tel a { text-decoration: none; }
.detail .tel a:hover { text-decoration: underline; }

.note-client {
	border-left: 3px solid var(--ambre);
	background: var(--ambre-clair);
	border-radius: 0 6px 6px 0;
	padding: 10px 14px;
	margin-bottom: 18px;
}

/* État de préparation : trois contrôles qui n'en font qu'un.
   Séparés, ils donnaient trois cadres empilés sur une ligne de tableau, ce qui
   est beaucoup de traits pour trois gestes. Ils partagent donc une seule
   bordure, comme un champ de recherche avec son bouton, et le groupe entier
   s'allume à la saisie plutôt que chaque morceau de son côté. */
.etat-ligne {
	display: inline-flex;
	align-items: stretch;
	height: 27px;
	border: 1px solid var(--bord);
	border-radius: 5px;
	background: var(--carte);
	overflow: hidden;
	transition: border-color var(--transition), box-shadow var(--transition);
}

.etat-ligne:focus-within {
	border-color: var(--accent);
	box-shadow: 0 0 0 2px var(--accent-clair);
}

.etat-ligne select,
.etat-ligne input[type=text],
.etat-ligne button {
	font-family: inherit;
	font-size: 12px;
	border: 0;
	background: none;
	outline: none;
	padding: 0 9px;
}

/* La flèche native pèse lourd à cette taille : on la remplace par un chevron
   tracé, et le champ garde la place qu'il faut pour lui. */
.etat-ligne select {
	appearance: none;
	padding-right: 22px;
	color: var(--texte);
	font-weight: 600;
	cursor: pointer;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5 6 7.5 9 4.5' fill='none' stroke='%23667079' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 7px center;
	background-size: 11px;
}

/* Un filet fin sépare les trois zones, à la place de trois bordures.
   La zone de saisie reste blanche même quand le groupe porte la couleur de
   l'état : c'est là qu'on écrit, et un fond teinté donne l'impression d'un
   champ désactivé. */
.etat-ligne input[type=text] {
	min-width: 200px;
	flex: 1 1 340px;
	border-left: 1px solid var(--bord);
	background: var(--carte);
	color: var(--texte);
}

.etat-ligne input[type=text]::placeholder { color: #9aa3ab; }

.etat-ligne button.primaire {
	border-left: 1px solid var(--bord);
	background: transparent;
	color: var(--accent);
	font-weight: 600;
	letter-spacing: .02em;
	cursor: pointer;
	transition: background-color var(--transition), color var(--transition);
}

.etat-ligne button.primaire:hover { background: var(--accent); color: #fff; border-left-color: var(--accent); }

.notes { padding: 0; }
.notes .note { padding: 10px 14px; border-bottom: 1px solid #eef1f3; }
.notes .note:last-of-type { border-bottom: 0; }
.note-tete { display: flex; gap: 8px; align-items: baseline; margin-bottom: 3px; }

.note-form {
	display: flex;
	gap: 8px;
	align-items: flex-start;
	padding: 12px 14px;
	border-top: 1px solid var(--bord);
	background: #fafbfc;
}

.note-form textarea {
	flex: 1;
	font: inherit;
	font-size: 13px;
	padding: 7px 10px;
	border: 1px solid var(--bord);
	border-radius: 4px;
	resize: vertical;
}

/* ---- Modal -------------------------------------------------------------- */

.modale {
	position: fixed;
	inset: 0;
	z-index: 80;
	display: flex;
	align-items: flex-start;
	justify-content: center;
	padding: 5vh 16px 16px;
	background: rgba(14, 26, 22, .66);
	opacity: 0;
	transition: opacity .18s ease;
	overflow-y: auto;
}

.modale.on { opacity: 1; }

.modale-boite {
	/* La fiche de commande tient trois colonnes de blocs et un tableau de
	   lignes : à 820 px les libellés produits se repliaient sur trois lignes
	   pour rien. */
	width: min(1100px, 100%);
	background: var(--fond);
	border-radius: 9px;
	box-shadow: 0 20px 60px rgba(10, 25, 20, .3);
	padding: 20px 22px 22px;
	transform: translateY(-6px);
	transition: transform .18s ease;
}

.modale.on .modale-boite { transform: translateY(0); }

.modale-fermer {
	position: absolute;
	top: 14px;
	right: 18px;
	font: inherit;
	font-size: 22px;
	line-height: 1;
	background: none;
	border: 0;
	color: #eaf1ee;
	cursor: pointer;
	padding: 4px 8px;
}

.modale-chargement { padding: 30px; text-align: center; color: var(--doux); }

/* The page behind a modal stays put: scrolling it under the dialog loses the
   reader's place in a 380-row table. */
body.modale-ouverte { overflow: hidden; }


/* Tous les changements d'état au survol partagent la même durée : une
   interface où chaque élément réagit à sa vitesse se lit comme un bug. */
header.top .marque span { transition: color var(--transition); }
nav.principal a { transition: color var(--transition), background-color var(--transition); }
header.top .compte button { transition: color var(--transition), border-color var(--transition); }
tr td { transition: background-color var(--transition); }
.filtres a { transition: border-color var(--transition); }
button.primaire { transition: background-color var(--transition), border-color var(--transition); }
.sources-etat { transition: color var(--transition), border-color var(--transition); }
.titre-bloc .carte { transition: color var(--transition), background-color var(--transition); }
td.lieu .carte { transition: color var(--transition), background-color var(--transition), border-color var(--transition); }
td.lieu .carte span { transition: color var(--transition); }
table.detail-lignes td.sku a { transition: color var(--transition); }
.pages a { transition: border-color var(--transition); }

@media (prefers-reduced-motion: reduce) {
	.modale, .modale-boite { transition: none; }
	*, *::before, *::after {
		transition-duration: .01ms !important;
		/* Le reflet de la puce « new » et le battement de son étincelle sont du
		   décor : qui demande moins de mouvement n'en veut pas non plus. */
		animation: none !important;
	}
}

/* ---- Date column -------------------------------------------------------- */

td.quand { white-space: nowrap; line-height: 1.3; }
td.quand .muet { font-size: 11.5px; }

/* ---- Period picker ------------------------------------------------------ */

.filtres.periodes { margin-top: -4px; }

/* Pushed to the right edge: the period sits opposite the status filters. */
.filtres .intervalle {
	display: flex;
	align-items: center;
	gap: 6px;
	margin-left: auto;
}

/* Same 12px as the pills: the period row is a filter, not a form to fill in. */
.filtres .intervalle select,
.filtres .intervalle input[type=date],
.filtres .intervalle button {
	font-family: inherit;
	font-size: 12px;
	line-height: 1.6;
	padding: 2px 8px;
	border: 1px solid var(--bord);
	border-radius: 4px;
	background: var(--carte);
}

.filtres .intervalle select { cursor: pointer; }
.filtres .intervalle input[type=date] { min-width: 0; }

/* The shared rule above sets a white background: put the action colour back,
   or the primary button reads as disabled. */
.filtres .intervalle button.primaire {
	background: var(--accent);
	border-color: var(--accent);
	color: #fff;
	padding: 2px 12px;
	font-weight: 600;
	cursor: pointer;
}

.filtres .intervalle button.primaire:hover { background: #0c5740; border-color: #0c5740; }

/* ---- Pagination --------------------------------------------------------- */

.pages {
	display: flex;
	align-items: center;
	gap: 4px;
	flex-wrap: wrap;
	margin: 2px 0 22px;
}

.pages a {
	min-width: 32px;
	padding: 5px 9px;
	text-align: center;
	border: 1px solid var(--bord);
	border-radius: 4px;
	background: var(--carte);
	color: var(--texte);
	text-decoration: none;
	font-variant-numeric: tabular-nums;
}

.pages a:hover { border-color: #9aa5ad; }
.pages a.actif { background: var(--texte); color: #fff; border-color: var(--texte); }
.pages a.saut { color: var(--doux); }

/* A first/last arrow on the first/last page stays visible but inert, so the
   control does not jump around as you page through. */
.pages a.inactif { opacity: .4; pointer-events: none; }

.pages .ecart { color: var(--doux); padding: 0 2px; }
.pages .compte { margin-left: 10px; color: var(--doux); font-size: 12px; }

/* Case « se souvenir de moi » : alignée sur la ligne de base du libellé, pas
   sur le haut de la case, sinon le texte flotte au-dessus. */
.connexion .memo {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 14px 0 4px;
	font-size: 13px;
	font-weight: 400;
	color: var(--muet);
	cursor: pointer;
}

.connexion .memo input {
	width: auto;
	margin: 0;
	accent-color: var(--accent);
}

/* Réponse à un devis de livraison : un montant court et une note longue, donc
   deux largeurs et non deux colonnes égales. */
.reponse-devis {
	border: 1px solid var(--bord);
	border-radius: 6px;
	background: var(--carte);
	padding: 14px 16px;
	margin-bottom: 14px;
}

.reponse-devis .champs { display: flex; gap: 16px; flex-wrap: wrap; }
.reponse-devis label { display: flex; flex-direction: column; gap: 5px; flex: 0 0 200px; }
.reponse-devis label.large { flex: 1 1 320px; }
.reponse-devis label > span:first-child { font-size: 12px; color: var(--doux); }

/* L'unité colle au champ : un prix sans sa monnaie se lit deux fois. */
.reponse-devis .avec-unite { display: flex; align-items: stretch; }
.reponse-devis .avec-unite input { border-radius: 4px 0 0 4px; text-align: right; }

.reponse-devis .avec-unite .unite {
	display: flex;
	align-items: center;
	padding: 0 9px;
	border: 1px solid var(--bord);
	border-left: 0;
	border-radius: 0 4px 4px 0;
	background: var(--fond);
	color: var(--doux);
	font-size: 12px;
}

.reponse-devis textarea,
.reponse-devis .avec-unite input {
	padding: 8px 10px;
	border: 1px solid var(--bord);
	border-radius: 5px;
	background: var(--carte);
	color: var(--texte);
	font-family: inherit;
	font-size: 13px;
	line-height: 1.5;
	transition: border-color var(--transition), box-shadow var(--transition);
}

.reponse-devis textarea {
	width: 100%;
	resize: vertical;
	min-height: 72px;
}

.reponse-devis textarea::placeholder { color: #9aa3ab; }

.reponse-devis textarea:focus,
.reponse-devis .avec-unite input:focus {
	border-color: var(--accent);
	box-shadow: 0 0 0 2px var(--accent-clair);
	outline: none;
}

/* Le champ montant et son unité se touchent : arrondis seulement à l'extérieur. */
.reponse-devis .avec-unite input { border-radius: 5px 0 0 5px; border-right: 0; }
.reponse-devis .avec-unite .unite { border-radius: 0 5px 5px 0; }

.reponse-devis .pied {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 12px;
	margin-top: 12px;
}

/* Avertissement de chantier : ambre, pas rouge. Rien n'est cassé, c'est une
   étape qui n'est pas encore là. */
.reponse-devis .destinataire {
	margin: 12px 0 0;
	padding: 8px 10px;
	border-radius: 5px;
	background: var(--ambre-clair);
	color: var(--ambre);
}

.reponse-devis .destinataire strong { font-weight: 700; }

/* Retour d'action, au-dessus du formulaire qui l'a déclenchée. */
.bandeau {
	padding: 9px 12px;
	border-radius: 5px;
	margin-bottom: 12px;
	font-size: 13px;
}

.bandeau.ok { background: var(--accent-clair); color: var(--accent); }
.bandeau.ko { background: var(--rouge-clair); color: var(--rouge); }



/* Led de préparation, en tête de ligne. Un point plein plutôt qu'un badge :
   la colonne fait six pixels de large et la couleur suffit à scanner la
   liste ; le détail est dans l'infobulle. Rien n'est affiché tant que
   personne n'a touché une ligne, sinon toute la liste porterait un point gris
   qui ne dirait plus rien. */
td.coche { white-space: nowrap; }

.led {
	display: inline-block;
	width: 8px;
	height: 8px;
	margin-right: 7px;
	border-radius: 50%;
	vertical-align: middle;
	cursor: help;
	transition: transform var(--transition);
}

.led:hover, .led:focus { transform: scale(1.35); outline: none; }

.led.ok      { background: var(--accent); }
.led.ko      { background: var(--rouge); }
.led.attente { background: var(--ambre-vif); }
.led.encours { background: var(--violet); }
.led.neutre  { background: #b9c0c6; }

/* Le groupe de contrôles prend la couleur de l'état courant : on lit l'état
   sans dérouler le menu, et la ligne d'article se relit d'un coup d'oeil. */
.etat-ligne.etat-ok      { border-color: #b7d8c8; background: #f3faf6; }
.etat-ligne.etat-ko      { border-color: #e6b9b9; background: #fdf5f5; }
.etat-ligne.etat-attente { border-color: #e6cf9f; background: #fdf9f0; }

.etat-ligne.etat-ok select      { color: var(--accent); }
.etat-ligne.etat-ko select      { color: var(--rouge); }
.etat-ligne.etat-attente select { color: var(--ambre); }

.etat-ligne.etat-ok input[type=text],
.etat-ligne.etat-ok button.primaire      { border-left-color: #cfe6da; }
.etat-ligne.etat-ko input[type=text],
.etat-ligne.etat-ko button.primaire      { border-left-color: #eecfcf; }
.etat-ligne.etat-attente input[type=text],
.etat-ligne.etat-attente button.primaire { border-left-color: #eddfbe; }

/* Leds dans l'infobulle de contenu : même code couleur que la liste, mais sur
   fond sombre. Les lignes intactes gardent une place vide plutôt que rien, pour
   que les libellés restent alignés. */
/* Même règle dans l'infobulle : une colonne de plus, et seulement là où une
   led existe. L'infobulle des devis n'en a pas. */
#tip .art:has(.led) {
	grid-template-columns: 8px max-content max-content 1fr auto;
}

/* Même règle que dans la liste : la led tient sur la première ligne, celle où
   commence le libellé, et pas au milieu d'un nom qui déborde sur deux lignes. */
#tip .art .led {
	align-self: start;
	width: 8px;
	height: 8px;
	margin: calc((1.45em - 8px) / 2) 0 0;
	cursor: default;
}
#tip .art .led.vide { background: transparent; }
#tip .art .led.neutre { background: #4a5a55; }

/* Colonnes de gabarit connu : numéro, date, boutique. Sans largeur fixe, la
   table se recalcule à chaque filtre et tout glisse latéralement sous l'oeil,
   ce qui donne l'impression que la page a changé alors qu'elle a juste été
   triée. La largeur est posée sur l'en-tête, que le tableau suit. */
table th.col-commande, table td.col-commande { width: 96px; }
table th.col-date,     table td.col-date     { width: 92px; }
table th.col-boutique, table td.col-boutique { width: 104px; }

table th.col-commande,
table th.col-date,
table th.col-boutique,
table td.col-commande,
table td.col-date,
table td.col-boutique { white-space: nowrap; }

/* Commande entrée depuis le dernier passage. Une puce sous le numéro plutôt
   qu'un point devant : elle se lit, elle ne se devine pas, et elle ne dispute
   pas sa place à la led d'état de préparation.
   
   C'est le seul endroit de la console où l'on s'autorise une couleur vive et
   un mouvement : la puce disparaît d'elle-même au passage suivant, donc elle
   ne peut pas devenir le bruit de fond de l'écran. */
.puce-neuve {
	display: inline-flex;
	align-items: center;
	gap: 3px;
	position: relative;
	overflow: hidden;
	margin-top: 3px;
	padding: 2px 4px 2px 5px;
	border-radius: 3px;
	background: #0e9aa7;
	color: #fff;
	font-family: inherit;
	font-size: 10px;
	font-weight: 700;
	letter-spacing: .05em;
	text-transform: uppercase;
	cursor: default;
}

/* Un reflet qui traverse la puce, pas un clignotement : on doit pouvoir lire
   l'écran à côté sans être happé toutes les secondes. */
.puce-neuve::after {
	content: '';
	position: absolute;
	inset: 0 auto 0 -60%;
	width: 45%;
	background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .5), transparent);
	animation: puce-reflet 3.4s ease-in-out infinite;
	pointer-events: none;
}

@keyframes puce-reflet {
	0%, 62% { transform: translateX(0); }
	100%    { transform: translateX(420%); }
}

/* La croix ne se montre qu'au survol de la puce : au repos elle n'a rien à
   dire, et une croix permanente donnerait envie de fermer quelque chose. */
.puce-neuve .croix {
	display: flex;
	align-items: center;
	width: 0;
	padding: 0;
	border: 0;
	margin: 0;
	overflow: hidden;
	background: none;
	color: inherit;
	opacity: 0;
	cursor: pointer;
	transition: width var(--transition), opacity var(--transition), margin var(--transition);
}

.puce-neuve:hover .croix,
.puce-neuve:focus-within .croix {
	width: 11px;
	margin-left: 3px;
	opacity: .85;
}

.puce-neuve .croix:hover { opacity: 1; }

/* L'étincelle bat doucement, en opacité seulement : pas de déplacement, qui
   ferait sauter le texte à côté. */
.puce-neuve .etincelle {
	flex: 0 0 auto;
	animation: puce-etincelle 2.2s ease-in-out infinite;
}

@keyframes puce-etincelle {
	0%, 100% { opacity: .65; }
	50%      { opacity: 1; }
}

/* Intertitre de groupe dans un tableau : une ligne qui n'est pas une donnée,
   donc ni bordure de cellule ni survol. */
tr.groupe > td {
	padding-top: 14px;
	background: none !important;
	border-bottom: 0;
	color: var(--doux);
	font-size: 11.5px;
	text-transform: uppercase;
	letter-spacing: .04em;
}

tr.groupe:first-child > td { padding-top: 4px; }
tr.groupe:hover > td { background: none; }

/* Pastille d'écart : elle porte une infobulle, donc un curseur qui le dit et
   un contour au focus clavier. Détachée du total qu'elle commente, sinon les
   deux se lisent comme une seule ligne de chiffres. */
.b.ecart { display: inline-block; margin-top: 8px; cursor: help; }
.b.ecart:focus { outline: 2px solid var(--rouge); outline-offset: 1px; }

/* Suivi de commande chez BA : une trace, pas une conversation. Trois colonnes
   fixes, du plus ancien en bas, et rien qui invite à écrire. */
.carte.suivi { padding: 4px 0; }

.suivi .etape {
	display: grid;
	grid-template-columns: 116px minmax(0, 1fr) max-content;
	gap: 12px;
	align-items: baseline;
	padding: 7px 14px;
	font-size: 12.5px;
}

.suivi .etape + .etape { border-top: 1px solid #eef1f3; }
.suivi .quand { color: var(--doux); font-variant-numeric: tabular-nums; }
.suivi .qui { font-size: 11.5px; }
