@font-face {
  font-family: "Malaika Lato";
  src: url("assets/fonts/Lato-Regular-latin.woff2") format("woff2");
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Malaika Lato";
  src: url("assets/fonts/Lato-Bold-latin.woff2") format("woff2");
  font-style: normal;
  font-weight: 700;
  font-display: swap;
}

/* Structure ERP sobre, accents botaniques et terre chaude Malaika Ranch. */
:root {
  --bg: #f3f6f2;
  --bg-soft: #fafbf8;
  --panel: #ffffff;
  --panel-alt: #f1f5f0;
  --line: #dce5dc;
  --text: #26372e;
  --muted: #52645a;
  --primary: #2b684a;
  --primary-deep: #1c4935;
  --accent: #87521b;
  --accent-deep: #6f4116;
  --accent-soft: #e8c681;
  --danger: #a74335;
  --success: #2d7049;
  --warning: #a36b18;
  --focus: #174633;
  --shadow: 0 4px 18px rgba(27, 49, 36, 0.06);
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 12px;
  /* Cible tactile minimale : WCAG 2.1 SC 2.5.5, et usage terrain au Ranch. */
  --tactile: 44px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

[hidden] {
  display: none !important;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

html {
  scroll-behavior: smooth;
}

/*
 * FOCUS VISIBLE -- WCAG 2.1 SC 1.4.11, 2.4.7, 1.4.13
 * ----------------------------------------------------
 * CE QUI ETAIT FAUX, ET MESURE
 * ----------------------------
 * Aucun style :focus-visible n'existait dans l'application. Les seuls
 * contours declares etaient sur les champs de saisie :
 *
 *     input:focus { outline: 2px solid rgba(36, 92, 69, 0.18) }
 *
 * Ce vert a 18% d'opacite, compose sur du blanc, vaut 1.32:1. Le seuil
 * demande par SC 1.4.11 pour un indicateur de focus est de 3:1 : l'anneau
 * etait deux fois et demie en dessous, donc invisible a l'oeil. Les liens et
 * les boutons, eux, n'avaient AUCUN contour : sur le menu lateral comme sur
 * les boutons d'action, un utilisateur au clavier ne percevait rien du tout
 * de l'element qui avait le focus. C'est le point de blocage le plus grave
 * des trois, parce qu'il rend l'ERP inutilisable sans souris.
 *
 * LE CHOIX
 * --------
 * - :focus-visible plutot que :focus : le contour n'apparait que pour une
 *   navigation clavier et ne reste pas colle apres un clic de souris. C'est
 *   le comportement attendu, et il evite un anneau permanent sur chaque
 *   bouton presse au doigt.
 * - 3px et non les 2px du gabarit initial : 2px est le minimum du minimum
 *   de WCAG 2.2 SC 2.4.13. On s'en ecarte deliberement -- sur une dalle de
 *   8 a 10 pouces poussee dans la lumiere du Ranch, un filet de 2px se
 *   confond avec la bordure du champ. 3px reste discret sur un ecran de
 *   bureau et se voit au doigt. Cet ecart est motive par l'usage, pas par
 *   le gout.
 * - une couleur SOLIDE a 9.67:1, pas un alpha : un alpha faible reproduit
 *   exactement le defaut qu'on corrige, puisque sa valeur rendered depend
 *   du fond.
 * - outline-offset: 2px, pour que l'anneau ne colle pas a la bordure.
 *
 * REPLI POUR LES NAVIGATEURS SANS :focus-visible
 * Le @supports ci-dessous rend le contour sur :focus simple. Aucun
 * navigateur actuel ne le lira, et c'est bien l'intention : il garantit que
 * l'existence d'un contour ne depend pas d'une propriete recente.
 */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

@supports not selector(:focus-visible) {
  :focus {
    outline: 3px solid var(--focus);
    outline-offset: 2px;
  }
}

/*
 * Le menu lateral est clair. Le bandeau aubergine conserve un contour clair.
 */
.sidebar :focus-visible,
.sidebar-nav :focus-visible {
  outline-color: var(--focus);
}

.navbar :focus-visible {
  outline-color: #f5e7c7;
}

@supports not selector(:focus-visible) {
  .sidebar :focus,
  .sidebar-nav :focus {
    outline-color: var(--focus);
  }

  .navbar :focus {
    outline-color: #f5e7c7;
  }
}

body {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--text);
  font-family: "Malaika Lato", "Trebuchet MS", sans-serif;
  background:
    radial-gradient(circle at 96% -15%, rgba(126, 162, 113, 0.12), transparent 35%),
    linear-gradient(180deg, #f9faf7 0%, var(--bg) 100%);
  min-height: 100vh;
}

a {
  color: inherit;
  text-decoration: none;
}

img {
  max-width: 100%;
}

.app-shell {
  display: grid;
  grid-template-columns: 264px minmax(0, 1fr);
  min-height: 100vh;
  width: 100%;
  overflow-x: hidden;
}

.sidebar {
  background: #fcfdfa;
  color: var(--text);
  border-right: 1px solid var(--line);
  padding: 20px 14px;
  width: 264px;
  min-width: 264px;
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  color: inherit;
  padding: 4px 8px 17px;
  border-bottom: 1px solid var(--line);
}

.brand .logo,
.navbar .logo {
  width: 50px;
  min-width: 50px;
  max-width: 50px;
  height: 50px;
  object-fit: contain;
  border-radius: 8px;
  background: #fff;
  padding: 3px;
}

.brand strong {
  display: block;
  font-size: 1.08rem;
  color: var(--primary-deep);
}

.brand span {
  display: block;
  color: var(--muted);
  font-size: 0.78rem;
}

.nav-toggle {
  display: none;
}

/*
 * Voile du tiroir. Il est cree par app.js et n'existe que lorsque le menu est
 * ouvert en dessous de 1180px. Hors de cette plage il ne doit surtout pas
 * s'afficher : la regle de base ci-dessous le masque, et la requete media le
 * reactive. Sans la regle de base, un voile resterait a l'ecran sur un ecran
 * large et bloquerait toute l'application.
 */
.nav-scrim {
  display: none;
}

.sidebar-nav ul,
.navbar ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.sidebar-nav {
  overflow-x: hidden;
  overflow-y: auto;
}

.nav-group {
  margin: 4px 0 8px;
}

.nav-group summary {
  display: flex;
  align-items: center;
  min-height: var(--tactile);
  padding: 9px 12px;
  color: var(--muted);
  cursor: pointer;
  font-size: 0.73rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.nav-group summary::marker {
  color: var(--primary);
}

.sidebar-nav a,
.navbar a {
  display: flex;
  align-items: center;
  min-height: var(--tactile);
  padding: 9px 12px;
  border-radius: 7px;
  color: var(--text);
  margin-bottom: 3px;
  font-size: 0.92rem;
  transition: background 0.18s ease, color 0.18s ease;
}

.sidebar-nav a:hover,
.sidebar-nav a.active {
  background: #e8f2e9;
  color: var(--primary-deep);
  box-shadow: inset 3px 0 var(--primary);
}

.navbar a:hover,
.navbar a.active {
  background: rgba(255, 255, 255, 0.13);
  color: #fff;
}

.nav-home,
.nav-logout {
  font-weight: 700;
}

.nav-logout {
  margin-top: 14px;
  border: 1px solid var(--line);
}

.module-tabs {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  margin: -6px 0 22px;
  padding: 4px;
  scrollbar-width: thin;
}

.module-tabs a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tactile);
  flex: 0 0 auto;
  padding: 10px 16px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: #fff;
  color: var(--primary-deep);
  font-weight: 700;
}

.module-tabs a.active {
  color: #fff;
  border-color: var(--primary);
  background: var(--primary);
}

.dashboard-advanced {
  margin-top: 22px;
}

.dashboard-advanced > summary {
  color: var(--primary-deep);
  cursor: pointer;
  font-size: 1.05rem;
  font-weight: 700;
}

.dashboard-advanced[open] > summary {
  margin-bottom: 18px;
}

.app-main {
  padding: 24px 28px;
  min-width: 0;
  max-width: 100%;
}

.page-header,
.navbar,
.container,
.table-card,
.panel,
.ticket-box {
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  border-radius: var(--radius-md);
}

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
  padding: 22px 26px;
  background: #443b49;
  border-color: #443b49;
  color: #fff;
}

.page-header h1 {
  color: #fff;
  font-size: clamp(1.5rem, 2vw, 1.9rem);
  line-height: 1.2;
}

.page-header .eyebrow {
  color: #d5e8d8;
}

.page-header .page-subtitle {
  color: #e2e8e1;
}

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--accent);
  font-size: 0.78rem;
  font-weight: 700;
  margin: 0 0 8px;
}

h1,
h2,
h3 {
  margin: 0 0 8px;
  color: var(--primary-deep);
  letter-spacing: -0.015em;
}

.page-subtitle,
.muted,
small,
label small {
  color: var(--muted);
}

.user-chip {
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.26);
  border-radius: 8px;
  padding: 9px 13px;
  min-width: 140px;
  text-align: right;
  color: #fff;
}

.user-chip span,
.user-chip small {
  display: block;
}

.user-chip small {
  color: #dce6dd;
}

.container {
  padding: 26px;
}

.navbar {
  display: flex;
  gap: 16px;
  align-items: center;
  padding: 18px 22px;
  margin-bottom: 24px;
  background: #443b49;
  color: #fff;
  border: none;
}

.navbar a {
  color: #fff;
}

.navbar ul {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/*
 * GRILLES A 12 COLONNES
 * ---------------------
 * Ces quatre conteneurs partagent la meme grille de 12 colonnes. Ce qui ne
 * va pas, c'est qu'avant la Phase 4 seules trois familles d'enfants
 * recevaient une largeur : .panel-wide (8), .panel-side (4), et les cartes de
 * statistiques dans .dashboard / .stats-grid (3). Tout le reste n'avait AUCUNE
 * regle grid-column et retombait sur la valeur initiale 'auto', c'est-a-dire
 * UNE colonne sur douze.
 *
 * Mesure, avant correction, sur la caisse et sur l'expedition :
 *
 *   .split-grid  grid-template-columns: 44.5px x 12
 *                enfants : .panel = 46px   .panel panel-side = 732px
 *
 * 46 pixels de large pour le panneau de recherche d'articles et la liste des
 * articles vendables, c'est-a-dire la totalite du travail du caissier. Le
 * tableau de resultats, lui, a un min-width de 760px : il filingait a
 * l'interieur de ces 46px. Ce defaut n'etait PAS propre a la tablette : a
 * 1440px de large, le meme panneau mesurait 74px. Les six vues qui
 * emploient .split-grid -- caisse, expedition, recolte, perte, reception,
 * Pack House -- etaient concernees, donc toute la saisie terrain.
 *
 * La regle de defaut est donc ajoutee, et les intentions explicites
 * (8 + 4, et 3 pour les cartes) passent devant parce que leur specificite est
 * superieure a celle de la regle de defaut.
 */
.dashboard,
.stats-grid,
.content-grid,
.split-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 18px;
}

/* Quatre cartes de statistiques par ligne. */
.dashboard > *,
.stats-grid > *,
.split-grid > .card.stat-card {
  grid-column: span 3;
}

/* Panneau principal puis panneau lateral : 8 + 4. C'est l'intention dans
   les six vues qui emploient .split-grid. */
.split-grid > .panel:not(.panel-side),
.content-grid > .panel-wide {
  grid-column: span 8;
}

.split-grid > .panel-side,
.content-grid > .panel-side {
  grid-column: span 4;
}

/* Regle de defaut : un enfant sans classe de mise en page prend la moitie de
   la largeur, et non un dixieme. */
.content-grid > *,
.split-grid > * {
  grid-column: span 6;
}

.card,
.panel,
.table-card,
.ticket-box {
  padding: 22px;
}

.stat-card {
  position: relative;
  overflow: hidden;
  min-height: 150px;
}

.stat-card::after {
  display: none;
}

.stat-label,
.stat-hint {
  display: block;
}

.stat-label {
  font-size: 0.9rem;
  color: var(--muted);
}

.stat-value {
  display: block;
  margin: 10px 0 8px;
  font-size: 2rem;
  color: var(--primary-deep);
}

.tone-success {
  border-left: 6px solid var(--success);
}

.tone-warning {
  border-left: 6px solid var(--warning);
}

.tone-danger {
  border-left: 6px solid var(--danger);
}

form {
  display: grid;
  gap: 16px;
}

.actions-row form,
.inline-form {
  display: inline-flex;
  gap: 10px;
  align-items: center;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 16px;
}

.form-grid > * {
  grid-column: span 4;
}

.form-grid .span-6 {
  grid-column: span 6;
}

.form-grid .span-8 {
  grid-column: span 8;
}

.form-grid .span-12 {
  grid-column: 1 / -1;
}

label {
  display: block;
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--primary-deep);
}

input,
select,
textarea {
  width: 100%;
  margin-top: 8px;
  border: 1px solid var(--line);
  background: #fff;
  border-radius: 8px;
  padding: 12px 14px;
  color: var(--text);
  font: inherit;
}

textarea {
  min-height: 120px;
  resize: vertical;
}

/*
 * Le contour de focus des champs est desormais porte par le bloc global
 * :focus-visible plus haut. Celui qui etait declare ici -- un vert a 18%
 * d'opacite, mesure a 1.32:1 pour un seuil de 3:1 -- est retire : le laisser
 * ecraserait le contour global, sa specificite (0,1,1) etant superieure a
 * celle de :focus-visible (0,1,0), et l'anomalie survivrait a la correction.
 * La bordure reste changee au focus : c'est un second indice, utile quand le
 * contour est adjacent a la bordure du champ.
 */
input:focus,
select:focus,
textarea:focus {
  border-color: var(--primary);
}

/*
 * Boutons -- cible tactile
 * ------------------------
 * min-height: 44px est la cible tactile minimale (WCAG 2.1 SC 2.5.5). Elle
 * existait deja sur .btn. Elle manquait aux liens de menu, aux onglets de
 * module et aux intitules de groupe, qui sont des elements cliquables au
 * doigt au meme titre qu'un bouton : ces trois selective la recoivent aussi,
 * plus bas dans la feuille.
 */
.btn,
button,
input[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: 8px;
  padding: 10px 16px;
  min-height: var(--tactile);
  min-width: var(--tactile);
  background: var(--primary);
  color: #fff;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.18s ease, box-shadow 0.18s ease, opacity 0.18s ease;
}

.inline-form {
  display: inline-flex;
  margin: 0;
}

.btn:hover,
button:hover,
input[type="submit"]:hover {
  background: var(--primary-deep);
  box-shadow: 0 3px 10px rgba(31, 73, 51, 0.15);
}

/*
 * Les actions d'attention, de suppression et secondaires gardent leur propre
 * couleur au survol au lieu de reprendre le vert du bouton principal.
 */
.btn-warning {
  background: var(--accent);
}

.btn-danger {
  background: var(--danger);
}

.btn-secondary {
  background: #56665c;
}

.btn-warning:hover {
  background: var(--accent-deep);
}

.btn-danger:hover {
  background: #843329;
}

.btn-secondary:hover {
  background: #405247;
}

.actions-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

/*
 * ECRITURES TRES VISIBLES
 * -----------------------
 * Sur cet ERP, une validation depose un mouvement de stock, encaisse une vente
 * ou clot une reception. Ces actions n'ont pas de second essai gratuit : une
 * double validation produit un stock errone. L'utilisateur doit donc voir
 * immediatement que l'ecriture est engagee, et ne pas pouvoir la declencher
 * deux fois en tapping deux fois.
 *
 * app.js pose .btn-busy et aria-busy sur le bouton de validation d'un
 * formulaire POST. Le bouton devient non cliquable, se grise, et dit ce qu'il
 * fait. Sans cela, un tactile qui ne recoit pas de reponse en moins d'une
 * seconde re-tappe, et l'ecriture part deux fois.
 */
.btn-busy,
button[aria-busy="true"] {
  cursor: progress;
  opacity: 0.72;
  transform: none;
  box-shadow: none;
}

.btn-busy:hover,
button[aria-busy="true"]:hover {
  transform: none;
  box-shadow: none;
}

/* Le bouton qui engage l'ecriture est le plus visible de sa rangee. */
.actions-row .btn[type="submit"],
.actions-row button[type="submit"] {
  min-width: 12rem;
  letter-spacing: 0.01em;
  box-shadow: 0 3px 12px rgba(36, 92, 69, 0.2);
}

.actions-row .btn-danger[type="submit"],
.actions-row button.btn-danger[type="submit"] {
  box-shadow: 0 6px 18px rgba(184, 79, 58, 0.32);
}

/*
 * LIEN D'EVITEMENT
 * ----------------
 * Sans lui, un utilisateur au clavier doit traverser la totalite du menu
 * lateral, soit jusqu'a trente tabulations, avant d'atteindre le titre de la
 * page. Le lien est masque hors focus et devient visible des qu'il le recoit.
 */
.skip-link {
  position: absolute;
  left: 8px;
  top: -100px;
  z-index: 100;
  padding: 12px 18px;
  min-height: var(--tactile);
  display: inline-flex;
  align-items: center;
  border-radius: 0 0 14px 14px;
  background: var(--primary-deep);
  color: #fff;
  font-weight: 700;
  transition: top 0.15s ease;
}

.skip-link:focus {
  top: 0;
}

.table-card {
  padding: 0;
}

/*
 * CONTENEUR DE TABLEAUX DEFILABLES
 * --------------------------------
 * .app-shell porte overflow-x: hidden. C'est volontaire : il empeche la page
 * entiere de defilerhorizontalement a cause d'un element trop large. Mais
 * cet overflow s'applique aussi a la MASQUE que la grille fait heriter aux
 * descendants : un tableau plus large que sa colonne est donc ROGNE, et le
 * rognage n'est ni visible ni defilable. A 768px de large (iPad Mini en
 * portrait, cite dans le cahier des charges), .app-main ne laisse que
 * 732px utiles et table { min-width: 760px } : les 28px de la colonne de
 * droite, c'est-a-dire souvent le montant et la date, sortaient de l'ecran
 * sans aucun moyen de les atteindre. Le definitivement invisible.
 *
 * .table-container est le remede, et il faut qu'il soit capable de defiler
 * SEUL : overscroll-behavior-x: contain empeche le geste horizontal de
 * rafler la page entiere, ce qui est le comportement attendu sur une dalle
 * tactile ou l'on fait glisser le tableau avec le pouce.
 *
 * Ces conteneurs sont presents dans 6 pages seulement (dashboard, index,
 * suivi_lots, pertes_freintes, expedition, packhouse). Les 36 autres pages
 * produisent un <table> nu. CSS ne peut pas envelopper un element, et
 * modifier 36 gabarits a la main introduirait 36 occasions de casser une
 * page ; l'enveloppement est donc fait a l'execution par app.js, qui pose en
 * plus tabindex="0" et role="region" sur le conteneur. C'est ce qui rend la
 * zone defilable au CLAVIER, exigence WCAG 2.1 SC 1.4.10, et qu'un simple
 * overflow: auto ne satisfait pas.
 */
.table-container {
  width: 100%;
  overflow: auto;
  max-width: 100%;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
}

table {
  width: 100%;
  border-collapse: collapse;
  min-width: 760px;
}

table th {
  position: sticky;
  top: 0;
  /* Au-dessus des cellules, en dessous du bandeau hors connexion (z-index
     9999) : sans cela l'entete collant passe sous le bandeau et sous les
     cellules des lignes en dessous. */
  z-index: 1;
  background: #ecf3ed;
  color: var(--primary-deep);
  text-align: left;
  font-size: 0.88rem;
  letter-spacing: 0.02em;
}

table th,
table td {
  padding: 11px 14px;
  border-bottom: 1px solid #e7ede7;
  vertical-align: top;
}

table tr:hover td {
  background: #f5f8f4;
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 0.8rem;
  font-weight: 700;
  background: #ecf3ed;
  color: var(--primary-deep);
}

.badge-warning {
  background: #fff3d8;
  color: #8d6200;
}

.badge-danger {
  background: #f8ddd6;
  color: #8c2c19;
}

.badge-success {
  background: #dcefe3;
  color: #1f6238;
}

.alert {
  border-radius: 16px;
  padding: 14px 16px;
  margin-bottom: 16px;
  border: 1px solid transparent;
}

.alert-success {
  background: #e4f2e9;
  border-color: #b8dcc4;
  color: #205738;
}

.alert-error {
  background: #f9e3de;
  border-color: #efc0b5;
  color: #8d3423;
}

.alert-info {
  background: #ebf2f0;
  border-color: #ceded9;
  color: #264d40;
}

.hero-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 18px;
  margin-bottom: 18px;
}

.highlight-panel {
  background: linear-gradient(125deg, #1c4935, #2d6648);
  color: #fff;
}

.highlight-panel h1,
.highlight-panel h2,
.highlight-panel h3,
.highlight-panel .stat-value {
  color: #fff;
}

.highlight-panel .eyebrow {
  color: #f5e7c7;
}

.highlight-panel .page-subtitle,
.highlight-panel .stat-label,
.highlight-panel .stat-hint {
  color: rgba(255, 255, 255, 0.76);
}

.situation-panel .page-subtitle {
  color: #f0f6ef;
  font-size: 1rem;
}

.situation-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
  gap: 12px;
  margin: 20px 0 0;
}

.situation-stat {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--panel-alt);
  color: var(--primary-deep);
}

.situation-stat dt {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.35;
}

.situation-stat dd {
  flex: none;
  margin: 0;
  font-size: 1.65rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.login-page {
  display: grid;
  place-items: center;
  padding: 24px;
  background: radial-gradient(circle at 84% 8%, #e2eadf, transparent 36%), var(--bg);
}

.login-shell {
  width: min(100%, 500px);
  display: grid;
  gap: 14px;
}

.login-shell .panel {
  padding: clamp(24px, 5vw, 34px);
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 13px;
  margin-bottom: 28px;
  font-size: 1.12rem;
  font-weight: 700;
  line-height: 1.2;
}

.login-brand img {
  width: 58px;
  height: 58px;
  padding: 5px;
  object-fit: contain;
  border-radius: 8px;
  background: #fff;
}

.login-brand small {
  color: #dce9dd;
  font-size: 0.78rem;
  font-weight: 400;
}

.login-page h1 {
  font-size: clamp(1.6rem, 4vw, 2.15rem);
  line-height: 1.18;
}

.kpi-list,
.plain-list {
  display: grid;
  gap: 12px;
}

.kpi-item,
.list-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px dashed rgba(221, 214, 200, 0.9);
}

.metric-big {
  font-size: 2.4rem;
  font-weight: 800;
}

.image-thumb {
  width: 58px;
  height: 58px;
  object-fit: cover;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: #fff;
}

.ticket-box {
  max-width: 980px;
  margin: 0 auto;
}

.app-main > .panel,
.app-main > .ticket-box {
  margin-bottom: 18px;
}

.panel > :first-child,
.ticket-box > :first-child {
  margin-top: 0;
}

.ticket-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 18px;
  margin-bottom: 18px;
}

.inline-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.inline-pill {
  background: var(--panel-alt);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 10px 14px;
  color: var(--text);
}

.summary-box {
  background: #f6f4ed;
  border-radius: 18px;
  padding: 16px;
  border: 1px solid var(--line);
}

.pos-quick-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.pos-field-note,
.pos-payment-feedback {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  font-weight: 500;
  align-self: center;
}

.pos-stock-status {
  margin: 0;
  padding: 12px 16px;
  border: 1px solid #b8dcc4;
  border-radius: var(--radius-sm);
  background: #e4f2e9;
  color: var(--primary-deep);
  font-weight: 700;
}

.pos-quantity-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.pos-quantity-form input {
  width: 96px;
  min-height: var(--tactile);
  margin: 0;
  padding: 8px 10px;
}

.pos-quantity-form button {
  padding-inline: 12px;
}

.empty-state {
  padding: 18px;
  background: #f9f7f1;
  border: 1px dashed var(--line);
  border-radius: 18px;
  color: var(--muted);
}

.section-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
}

/*
 * NAVIGATION SUR TABLETTE ET TELEPHONE -- jusqu'a 1180px
 * ------------------------------------------------------
 * En dessous de 1180px, la colonne laterale de 264px ne peut plus tenir : il
 * resterait 669px de contenu a 1025px, soit moins que les 760px de largeur
 * minimale d'un tableau metier. La barre laterale devient donc une barre
 * superieure, et son menu sort du flux pour devenir un TIROIR.
 *
 * Pourquoi un tiroir plutot qu'un menu qui se deploye dans le flux
 * --------------------------------------------------------------
 * Le version d'avant (Phase 1.5) faisait passer .sidebar-nav de
 * display:none a display:block DANS le flux. Le menu ouvert repoussait donc
 * tout le contenu vers le bas, et l'utilisateur perdait la moitie de l'ecran
 * de travail pour consulter une liste. Sur une dalle de 8 pouces, c'est le
 * probleme. Le tiroir se superpose et rend la largeur integrale au contenu.
 *
 * Fermeture quand le menu est replie
 * -----------------------------------
 * visibility: hidden accompagne le translateX(-102%). Sans lui, le tiroir
 * replie resterait dans l'arbre d'accessibilite ET dans l'ordre de tabulation
 * : un utilisateur au clavier traverserait des liens invisibles avant
 * d'atteindre le contenu. visibility: hidden retire les deux, et la
 * transition differee sur visibility evite que le tiroir disparaisse avant
 * d'avoir fini de glisser.
 */
@media (max-width: 1180px) {
  body.nav-open {
    overflow: hidden;
  }
  .app-shell {
    grid-template-columns: 1fr;
  }

  .sidebar {
    position: sticky;
    top: 0;
    z-index: 40;
    width: auto;
    min-width: 0;
    height: auto;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    padding: 12px 16px;
  }

  .nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tactile);
    min-width: var(--tactile);
    margin-left: auto;
    border-radius: 8px;
    padding: 10px 16px;
    background: var(--primary);
    color: #fff;
  }

  .sidebar-nav {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 60;
    width: min(320px, 86vw);
    padding: 24px 18px;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: #fcfdfa;
    border-right: 1px solid var(--line);
    box-shadow: 10px 0 32px rgba(26, 45, 33, 0.2);
    transform: translateX(-102%);
    visibility: hidden;
    transition: transform 0.25s ease, visibility 0s linear 0.25s;
  }

  .sidebar-nav.is-open {
    transform: translateX(0);
    visibility: visible;
    transition: transform 0.25s ease, visibility 0s;
  }

  /* Voile derriere le tiroir, pose par app.js. Sans lui, le contenu reste
     cliquable sous un menu qui le recouvre. */
  .nav-scrim {
    position: fixed;
    inset: 0;
    z-index: 50;
    background: rgba(12, 20, 16, 0.5);
    border: 0;
    padding: 0;
    margin: 0;
    width: 100%;
    min-height: 100%;
    border-radius: 0;
    cursor: pointer;
  }
}

/*
 * TABLETTE -- jusqu'a 1024px
 * --------------------------
 * A cette largeur, un partage 8 + 4 donne 646px au panneau principal et 323px
 * au panneau lateral. Le panneau lateral suffit pour un panier, mais le
 * panneau principal est trop etroit pour un tableau metier : on repasse donc
 * en une seule colonne, la plus large possible. Les cartes de statistiques
 * restent a deux par ligne, et les formulaires a deux colonnes, ce qui evite
 * de n'avoir qu'un champ par ligne sur une dalle de 10 pouces.
 *
 * Les selecteurs de classe sont reapparus explicitement dans cette requete
 * media, et non seulement les selecteurs universels : leur specificite est
 * superieure, donc une regle de base comme '.split-grid > .panel-side'
 * l'emporterait sinon, et le panneau lateral resterait bloque sur 4 colonnes
 * a cote d'un panneau principal pleine largeur.
 */
@media (max-width: 1024px) {
  .app-main {
    padding: 18px 16px;
  }

  .dashboard > *,
  .stats-grid > *,
  .split-grid > .card.stat-card {
    grid-column: span 6;
  }

  .content-grid > *,
  .split-grid > *,
  .content-grid > .panel-wide,
  .split-grid > .panel-wide,
  .content-grid > .panel-side,
  .split-grid > .panel-side,
  .split-grid > .panel:not(.panel-side) {
    grid-column: 1 / -1;
  }

  .form-grid > *,
  .form-grid .span-6,
  .form-grid .span-8 {
    grid-column: span 6;
  }

  .form-grid .span-12 {
    grid-column: 1 / -1;
  }

  .hero-grid {
    grid-template-columns: 1fr;
  }

  .page-header,
  .ticket-header,
  .section-title {
    flex-wrap: wrap;
  }

  .user-chip {
    min-width: 0;
  }
}

@media (max-width: 900px) {
  .form-grid > *,
  .form-grid .span-6,
  .form-grid .span-8 {
    grid-column: 1 / -1;
  }

  .page-header,
  .ticket-header {
    grid-template-columns: 1fr;
    display: grid;
  }

  .page-header {
    padding: 20px;
  }

  .app-main {
    padding: 18px;
  }
}

/* Sous 620px, une carte de statistique pleine largeur : deux cartes a 280px
   feraient d'un nombre cle un texte illisible. */
@media (max-width: 620px) {
  label,
  input,
  select,
  textarea,
  .pos-field-note,
  .pos-payment-feedback {
    font-size: 1rem;
  }

  .dashboard > *,
  .stats-grid > *,
  .split-grid > .card.stat-card {
    grid-column: 1 / -1;
  }

  .pos-quick-links > a,
  .pos-add-form .actions-row > button,
  [data-pos-checkout] .actions-row > button {
    width: 100%;
  }

  .pos-cart-table {
    display: block;
    min-width: 0;
  }

  .pos-cart-table tbody,
  .pos-cart-table tr {
    display: block;
  }

  .pos-cart-table tr:first-child {
    display: none;
  }

  .pos-cart-table tr:not(:first-child) {
    margin: 12px;
    padding: 6px 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: #fff;
  }

  .pos-cart-table td {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    padding: 10px 0;
  }

  .pos-cart-table td::before {
    content: attr(data-label);
    flex: 0 0 90px;
    color: var(--muted);
    font-size: 0.82rem;
    font-weight: 700;
  }

  .pos-cart-table .pos-quantity-form {
    justify-content: flex-end;
  }

  .pos-cart-table .pos-quantity-form input {
    width: 86px;
  }
}

/*
 * PREFERENCE UTILISATEUR -- WCAG 2.1 SC 2.3.3 (AAA) et 2.2.2 (A)
 * ----------------------------------------------------------------
 * Le systeme a des transitions sur les liens de menu, les boutons et les
 * barres de defilement, plus un html { scroll-behavior: smooth } qui anime
 * TOUTES les ancres de la page. Sur cette derniere, un defilement anime vers
 * une ancre peut provoquer des nausees chez les personnes sensibles au
 * mouvement. Le bloc est applique tel quel a tous les elements, ce qui est la
 * forme attendue de cette media query.
 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .sidebar,
  .navbar,
  .print-zone,
  .page-header .user-chip {
    display: none !important;
  }

  .app-main,
  .container,
  .ticket-box {
    padding: 0;
    box-shadow: none;
    border: none;
    background: #fff;
  }
}

 .offline-banner{position:sticky;top:0;z-index:9999;background:#9b3d28;color:#fff;padding:10px 18px;text-align:center;font-weight:700;letter-spacing:.01em}.offline-banner[hidden]{display:none}
.finance-chart{width:100%;overflow:hidden;background:linear-gradient(180deg,#f7f8f2,#fff);border:1px solid var(--line);border-radius:14px;padding:10px;margin:12px 0 18px}.finance-chart canvas{display:block;max-width:100%}

.terrain-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr));gap:20px}
.terrain-card{min-width:0;padding:18px;border:1px solid var(--line);border-radius:14px;background:#fff}
.terrain-card h2{margin:0 0 8px}
.terrain-card p{min-height:2.5em}
.terrain-form{gap:12px}
.terrain-form label{min-width:0}
.terrain-form button{width:100%}
.terrain-extra{padding:12px;border:1px solid var(--line);border-radius:10px;background:#f7f8f2}
.terrain-extra summary{cursor:pointer;font-weight:700}
.terrain-extra label{margin-top:12px}
.terrain-intro{border-left:5px solid var(--accent)}
.terrain-intro .section-title{flex-wrap:wrap;margin-bottom:0}
.terrain-intro .section-title>div{flex:1 1 260px}
.terrain-queue{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.terrain-item{display:grid;gap:6px;padding:16px;border:1px solid var(--line);border-radius:12px;background:#fff;min-width:0}
.terrain-item small{color:var(--muted)}
.terrain-status{display:inline-block;padding:3px 8px;border-radius:999px;background:#eaf1e8;color:var(--primary-deep);font-size:.78rem;font-weight:700}
.terrain-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px}
.terrain-actions .inline-form{flex-wrap:wrap}
.terrain-actions input{max-width:210px;margin-top:0}
.cycle-report-select{display:flex;align-items:end;gap:14px;flex-wrap:wrap}
.cycle-report-select label{flex:1 1 280px}
.cycle-report-kpis{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:14px}
.cycle-report-kpis>div{display:grid;gap:8px;padding:16px;border:1px solid var(--line);border-radius:12px;background:#f7f8f2}
.cycle-report-kpis small{color:var(--muted)}
.cycle-report-kpis strong{font-size:1.25rem;color:var(--primary-deep)}
.cycle-report-note{border-left:5px solid var(--accent)}
.cycle-report-forms{display:grid;grid-template-columns:1fr 2fr;gap:24px}
.cycle-report-forms>article{min-width:0}
.cycle-report-heading{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:10px}
.cycle-report-heading h2{margin:0}
@media(max-width:1000px){.terrain-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.cycle-report-kpis{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:700px){.terrain-grid,.terrain-queue,.cycle-report-forms{grid-template-columns:1fr}.cycle-report-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}.terrain-card p{min-height:0}.terrain-actions .inline-form{width:100%}.terrain-actions input{max-width:none;flex:1}.cycle-report-heading .btn,.terrain-intro .section-title .btn{width:100%}}

.guide-hero{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(240px,1fr);gap:22px;align-items:stretch;padding:clamp(22px,4vw,38px);margin-bottom:18px;border-radius:18px;background:linear-gradient(130deg,var(--primary-deep,#1d4e38),var(--primary,#286347));color:#fff;box-shadow:0 12px 30px rgba(24,62,44,.14)}
.guide-hero h2{max-width:720px;margin:0 0 10px;font-size:clamp(1.55rem,3vw,2.25rem);line-height:1.15}
.guide-hero>div>p:last-child{max-width:680px;margin:0;color:rgba(255,255,255,.88);font-size:1.05rem;line-height:1.65}
.guide-hero .eyebrow{color:#e9c879}
.guide-hero-note{align-self:center;padding:18px 20px;border:1px solid rgba(255,255,255,.24);border-radius:14px;background:rgba(255,255,255,.1);line-height:1.55}
.guide-hero-note p{margin:7px 0 0;color:rgba(255,255,255,.9)}
.guide-hero-note code{color:#fff}
.guide-panel,.guide-section{margin-top:18px}
.guide-heading{display:flex;justify-content:space-between;align-items:end;gap:18px;margin-bottom:18px}
.guide-heading h2,.guide-bottom h2,.guide-feedback h2{margin:0}
.guide-heading>p{max-width:360px;margin:0;color:var(--muted);line-height:1.5}
.guide-tag{padding:8px 12px;border-radius:999px;background:#edf3e9;color:var(--primary-deep,#1d4e38);font-size:.84rem;font-weight:700;white-space:nowrap}
.guide-flow{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:12px;margin:0;padding:0;list-style:none}
.guide-flow li{display:grid;align-content:start;gap:9px;min-width:0;padding:16px;border:1px solid var(--line);border-radius:13px;background:#fbfcf9}
.guide-flow-number,.guide-card-number{display:grid;place-items:center;width:34px;height:34px;border-radius:50%;background:var(--primary-deep,#1d4e38);color:#fff;font-weight:800}
.guide-flow li strong{color:var(--primary-deep,#1d4e38)}
.guide-flow li>span:last-child{color:var(--muted);font-size:.91rem;line-height:1.5}
.guide-warning{display:grid;gap:5px;margin:18px 0;padding:16px 18px;border-left:5px solid #bc7b1c;border-radius:10px;background:#fff6e6;color:#493518;line-height:1.55}
.guide-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
.guide-card{position:relative;display:flex;flex-direction:column;align-items:flex-start;min-width:0;padding:20px;border:1px solid var(--line);border-radius:15px;background:#fff;box-shadow:0 5px 16px rgba(30,55,38,.045)}
.guide-card-number{width:30px;height:30px;background:#edf3e9;color:var(--primary-deep,#1d4e38);font-size:.85rem}
.guide-card h3{margin:12px 0 7px;color:var(--primary-deep,#1d4e38);font-size:1.12rem}
.guide-card p{margin:0 0 10px;line-height:1.55}
.guide-card .guide-check{margin-top:auto;padding:10px 12px;border-radius:9px;background:#f6f8f3;font-size:.93rem}
.guide-links{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.guide-links .btn{min-height:42px}
.guide-bottom{margin-top:18px}
.guide-roles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 18px;margin-top:14px}
.guide-roles p{display:grid;gap:3px;margin:0;padding:10px 0;border-bottom:1px solid var(--line);line-height:1.45}
.guide-roles strong{color:var(--primary-deep,#1d4e38)}
.guide-roles span,.guide-feedback li{color:var(--muted)}
.guide-feedback ol{padding-left:22px;line-height:1.65}
.guide-feedback .muted{line-height:1.5}
@media(max-width:1050px){.guide-flow{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:720px){.guide-hero{grid-template-columns:1fr}.guide-heading{align-items:flex-start;flex-direction:column}.guide-flow,.guide-grid,.guide-roles{grid-template-columns:1fr}.guide-tag{white-space:normal}.guide-links{width:100%}.guide-links .btn{flex:1 1 100%;justify-content:center}.guide-card{padding:17px}}
@media print{.guide-hero{background:#fff;color:#111;border:1px solid #999;box-shadow:none}.guide-hero-note{background:#fff;color:#111;border-color:#999}.guide-hero-note p,.guide-hero-note code,.guide-hero>div>p:last-child{color:#222}.guide-grid{grid-template-columns:1fr 1fr}.guide-card,.guide-flow li{break-inside:avoid;box-shadow:none}}
