/* ==========================================================================
   Quincaillerie — direction visuelle « Piste C » (comptoir)
   Fond clair, panneaux blancs, accent cobalt, coins arrondis, rail d'icônes.
   ========================================================================== */

:root {
  --bg: #f3f5f9;
  --surface: #ffffff;
  --panel: #ffffff;
  --line: #e6e9f0;
  --border: #e6e9f0;
  --text: #161a22;
  --muted: #697386;
  --accent: #2b5bd7;
  --accent-dark: #1f47ad;
  --accent-soft: #e9eefc;
  --tint-a: #eef2fd;
  --tint-b: #fdf3e3;
  --tint-c: #eaf6ef;
  --ok: #1e8a5b;
  --warn: #c07a1e;
  --danger: #c0453a;
  /* « Net à payer » (facture) : gris clair neutre + texte foncé.
     Contraste #161a22 / #eef0f3 ≈ 15.3:1 et #4a5163 / #eef0f3 ≈ 6.9:1 (WCAG AA). */
  --net-bg: #eef0f3;
  --net-line: #d8dce3;
  --net-label: #4a5163;
  --rail: #101728;
  --rail-hover: #1b2540;
  --rail-icon: #7d879c;
  --ui: 'Segoe UI Variable Text', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --display: 'Segoe UI Variable Display', 'Segoe UI Semibold', 'Segoe UI', system-ui, sans-serif;
  --mono: 'Cascadia Mono', 'Consolas', 'SFMono-Regular', monospace;
  --r: 14px;
  /* Hauteur de la barre de navigation basse (mobile / tablette étroite).
     Vaut 0 sur desktop : la valeur est relevée dans le palier ≤ 900 px. Elle
     sert à réserver l'espace sous le contenu (et au-dessus de la barre). */
  --nav-h: 0px;

  /* alias historiques */
  --primary: var(--accent);
  --primary-dark: var(--accent-dark);
  --success: var(--ok);
  --warning: var(--warn);
  --radius: var(--r);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--ui);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

/* ================= Layout : rail + zone principale ================= */
#app { display: grid; grid-template-columns: 64px 1fr; min-height: 100vh; }

.rail {
  background: var(--rail);
  display: flex; flex-direction: column; align-items: center;
  padding: 14px 0; gap: 6px;
  position: sticky; top: 0; height: 100vh; z-index: 20;
  /* Écran court ou cibles tactiles agrandies : le rail défile au lieu de
     pousser les dernières entrées hors de l'écran. */
  overflow-y: auto; overflow-x: hidden;
}
.rail .logo {
  width: 38px; height: 38px; border-radius: 11px; background: var(--accent);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-family: var(--display); font-weight: 700; font-size: 17px;
  margin-bottom: 12px; flex: 0 0 auto;
}
.rail a {
  width: 42px; height: 40px; border-radius: 10px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  color: var(--rail-icon); cursor: pointer; text-decoration: none;
}
.rail a svg { width: 19px; height: 19px; display: block; }
.rail a:hover { color: #fff; background: var(--rail-hover); }
.rail a:active { color: #fff; background: var(--rail-hover); }
.rail a.active { color: #fff; background: var(--accent); }
.rail .rail-logout:hover { background: var(--danger); color: #fff; }
.rail .rail-logout:active { background: var(--danger); color: #fff; }
.rail .sp { flex: 1 1 auto; }
.rail .sep { width: 26px; height: 1px; background: #26304a; margin: 6px 0; flex: 0 0 auto; }
.rail .rail-label { display: none; }

.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  height: 64px; display: flex; align-items: center; gap: 16px;
  padding: 0 24px; border-bottom: 1px solid var(--line);
  background: var(--bg); position: sticky; top: 0; z-index: 10;
}
.topbar h1, .topbar h2 {
  font-family: var(--display); font-size: 19px; font-weight: 600; flex: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.searchbox {
  display: flex; align-items: center; gap: 8px; background: #fff;
  border: 1px solid var(--line); border-radius: 11px; padding: 8px 12px;
  width: 300px; color: var(--muted);
}
.searchbox svg { width: 15px; height: 15px; flex: 0 0 auto; }
.searchbox input { border: none; outline: none; background: none; width: 100%; font: inherit; font-size: 13.5px; color: var(--text); }
.chip { background: var(--accent-soft); color: var(--accent); font-weight: 600; font-size: 12.5px; padding: 6px 12px; border-radius: 99px; white-space: nowrap; }
.avatar {
  width: 34px; height: 34px; border-radius: 50%; background: #dfe5f2; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 13px; color: #41506b; cursor: pointer;
}
.user-menu { display: flex; align-items: center; gap: 10px; margin-left: 4px; }
.user-menu .who { font-size: 12.5px; color: var(--muted); line-height: 1.2; }
.user-menu .who b { display: block; color: var(--text); font-size: 13px; font-weight: 600; }

.content { padding: 24px; min-width: 0; }

/* ================= Tuiles / bento ================= */
.bento { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.grid { display: grid; gap: 16px; }
.grid.stats { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.grid2 { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; }

.tile, .card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: 20px; min-width: 0;
}
.tile .l { font-size: 12.5px; color: var(--muted); font-weight: 600; }
.tile .v, .stat .value {
  font-family: var(--display); font-size: 30px; font-weight: 600;
  margin-top: 10px; font-variant-numeric: tabular-nums;
  min-width: 0; overflow-wrap: break-word;
}
.tile .v em, .stat .value em { font-style: normal; font-size: 15px; color: var(--muted); margin-left: 5px; font-weight: 400; }
.tile .d, .stat .hint { font-size: 12.5px; color: var(--muted); margin-top: 8px; }
.tile .d b { color: var(--ok); }
.tile h3, .card h3 { font-family: var(--display); font-size: 15px; font-weight: 600; margin-bottom: 14px; }
.tile.a { background: var(--tint-a); border-color: #dbe4fa; grid-column: span 2; }
.tile.b { background: var(--tint-b); border-color: #f6e3c4; }
.tile.c { background: var(--tint-c); border-color: #d4ecdf; }
.tile.wide { grid-column: span 2; grid-row: span 2; }
/* Tuile large mais sur une seule rangée (« Alertes de stock ») : classe plutôt
   que style inline, pour que les paliers responsive puissent la reprendre. */
.tile.wide.solo { grid-row: span 1; }
.tile.a .big { display: flex; align-items: flex-end; gap: 14px; margin-top: 10px; }
.tile.a .big .v { margin-top: 0; font-size: 38px; }
.badge.count { background: #fff; border-radius: 9px; padding: 5px 9px; font-size: 12px; font-weight: 600; color: var(--accent); border: 1px solid #dbe4fa; }

.stat .label { color: var(--muted); font-size: 12.5px; font-weight: 600; }
.stat .value { margin-top: 10px; }

.listrow { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 11px 0; border-top: 1px solid var(--line); }
.listrow:first-of-type { border-top: none; }
.listrow .sub { color: var(--muted); font-size: 12.5px; }

/* ================= Tableaux ================= */
/* Le conteneur défile horizontalement : c'est ce qui garde les tableaux
   lisibles sur téléphone sans écraser ni masquer les colonnes. */
.table-wrap {
  overflow-x: auto; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
  -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain;
}
/* Barre de défilement fine et visible : signale que le tableau continue. */
.table-wrap { scrollbar-width: thin; scrollbar-color: #cfd6e4 transparent; }
.table-wrap::-webkit-scrollbar { height: 8px; }
.table-wrap::-webkit-scrollbar-thumb { background: #cfd6e4; border-radius: 99px; }
.table-wrap::-webkit-scrollbar-track { background: transparent; }
table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th {
  text-align: left; font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); padding: 10px 12px; font-weight: 700; background: #fafbfe;
  white-space: nowrap;
}
th:first-child { border-top-left-radius: var(--r); }
th:last-child { border-top-right-radius: var(--r); }
td { padding: 11px 12px; border-top: 1px solid var(--line); vertical-align: middle; }
tbody tr:hover td { background: #fafbfe; }
/* État pressé : visible au doigt, là où :hover n'existe pas. */
tbody tr:active td { background: #f4f6fb; }
td.right, th.right, .right { text-align: right; }
.num { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 13px; }
/* Rangée d'actions d'une ligne de tableau (factures : « Voir / Imprimer » et
   « Ticket ») : les boutons se replient au lieu de déborder quand la colonne
   se resserre, sans jamais passer sous la cible tactile de 44 px. */
.row-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }

/* ================= Badges d'état ================= */
.badge, .st {
  display: inline-block; padding: 4px 10px; border-radius: 99px;
  font-size: 11.5px; font-weight: 700; white-space: nowrap;
}
.badge.ok, .st.ok { background: var(--tint-c); color: var(--ok); }
.badge.warn, .badge.credit, .st.cr { background: var(--tint-b); color: var(--warn); }
.badge.alert, .st.out { background: #f7e6e4; color: var(--danger); }
.badge.info { background: var(--accent-soft); color: var(--accent); }

/* ================= Formulaires ================= */
.field { margin-bottom: 14px; min-width: 0; }
.field label { display: block; font-size: 12.5px; color: var(--muted); margin-bottom: 6px; font-weight: 600; }
input, select, textarea {
  width: 100%; background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; font: inherit; font-size: 14px; color: var(--text); outline: none;
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
input[readonly] { background: #f7f8fb; color: var(--muted); }
.row { display: flex; gap: 12px; flex-wrap: wrap; }
.row > * { flex: 1; min-width: 140px; }

/* ================= Permissions (page Groupes) =================
   Une case par module. Chaque ligne est une cible tactile d'au moins 44 px : la
   case garde sa taille naturelle et c'est toute la ligne qui est cliquable.
   La grille se replie d'elle-même (2-3 colonnes en large, 1 au téléphone). */
.perms { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: 6px; }
.perms .perm {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 10px; background: #fff;
  font-size: 13.5px; cursor: pointer;
}
.perms .perm:hover { background: var(--accent-soft); }
/* Spécificité supérieure à la règle mobile « input { min-height: 44px } » :
   la case elle-même reste une case, c'est la ligne qui porte la cible 44 px. */
.perms .perm input {
  width: 18px; height: 18px; min-height: 0; padding: 0; margin: 0;
  flex: 0 0 auto; accent-color: var(--accent); box-shadow: none; border-radius: 4px;
}
.perms .perm input:focus { box-shadow: 0 0 0 3px var(--accent-soft); }
.perms .perm span { min-width: 0; }

/* ================= Boutons ================= */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  background: var(--accent); color: #fff; border: 1px solid transparent;
  border-radius: 10px; padding: 10px 16px; font: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer; text-decoration: none; line-height: 1.2;
  box-shadow: 0 1px 2px rgba(43, 91, 215, .25);
}
.btn svg { width: 16px; height: 16px; }
.btn:hover { background: var(--accent-dark); }
.btn:active { background: var(--accent-dark); }
.btn.secondary { background: #fff; border-color: var(--line); color: var(--text); box-shadow: none; }
.btn.secondary:hover { background: #f4f6fb; }
.btn.secondary:active { background: #eef2fd; }
.btn.danger { background: var(--danger); box-shadow: none; }
.btn.danger:hover { background: #a63a30; }
.btn.danger:active { background: #a63a30; }
.btn.success { background: var(--ok); box-shadow: none; }
.btn.success:hover { background: #196f4a; }
.btn.success:active { background: #196f4a; }
.btn.sm { padding: 6px 11px; font-size: 12.5px; border-radius: 9px; }
.btn.block { width: 100%; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.toolbar { display: flex; gap: 10px; align-items: center; margin-bottom: 16px; flex-wrap: wrap; }
.toolbar .spacer { flex: 1; }
.toolbar input { width: auto; }

/* ================= Caisse (POS) ================= */
.pos { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; align-items: start; }
.cart-line { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.cart-line:last-child { border-bottom: none; }
.cart-line .qty { width: 72px; }
.search-results { max-height: 320px; overflow-y: auto; border: 1px solid var(--line); border-radius: 11px; margin-top: 10px; background: #fff; }
.search-results:empty { display: none; }
.search-results .item { padding: 10px 12px; border-bottom: 1px solid var(--line); cursor: pointer; font-size: 13.5px; }
.search-results .item:last-child { border-bottom: none; }
.search-results .item:hover { background: var(--accent-soft); }
.search-results .item:active { background: var(--accent-soft); }
/* Pied de panier : total + « Valider la vente ». Sur téléphone il se colle au
   bas de l'écran (voir palier ≤ 900 px) pour rester à portée de pouce. */
.pos-foot { margin-top: 0; }
/* Douchette : le champ de scan est le premier geste de la journée. Il est mis
   en avant (cadre accentué, chiffres à chasse fixe comme un code-barres) et
   reste une cible tactile confortable sur mobile (≥ 44 px). */
.scan-input {
  font-family: var(--mono); font-size: 17px; font-weight: 600; letter-spacing: .5px;
  border-color: var(--accent); background: var(--accent-soft); min-height: 46px;
}
.scan-input::placeholder {
  font-family: var(--ui); font-size: 14px; font-weight: 400; letter-spacing: 0;
}
.total-line {
  display: flex; justify-content: space-between; align-items: baseline;
  border-top: 1px solid var(--line); margin-top: 14px; padding-top: 14px;
  font-family: var(--display); font-size: 24px; font-weight: 600;
}

/* ================= Modales ================= */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(16, 23, 40, .55);
  display: flex; align-items: flex-start; justify-content: center;
  /* Défilement dans les deux axes : une fenêtre étroite doit pouvoir faire
     défiler l'aperçu horizontalement (la feuille n'est jamais réorganisée). */
  padding: 32px 16px; z-index: 50; overflow: auto;
}
.modal {
  background: #fff; border-radius: var(--r); width: 100%; max-width: 560px;
  padding: 22px; box-shadow: 0 24px 60px rgba(16, 23, 40, .28);
}
.modal h3 { font-family: var(--display); margin: 0 0 16px; font-size: 17px; }
.modal p { margin: 0 0 10px; }
.modal .actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }
.modal.large { max-width: 880px; }
/* La feuille d'aperçu garde la mise en page large A4/A5 à toute largeur de
   fenêtre : elle ne rétrécit ni ne se réorganise (mêmes positions de blocs
   qu'à l'impression). Si la fenêtre est plus étroite, la surcouche défile. */
.modal.sheet-modal {
  max-width: 210mm; background: transparent; box-shadow: none; padding: 0;
  flex: 0 0 auto; margin: 0 auto;
}
.modal.sheet-modal.format-a5 { max-width: 148mm; }
.modal.sheet-modal .actions {
  margin-top: 14px; background: #fff; border-radius: var(--r); padding: 12px;
  box-shadow: 0 12px 40px rgba(16, 23, 40, .18);
  flex-wrap: wrap; align-items: center; justify-content: flex-start;
}
.modal .actions .spacer { flex: 1; }

/* ================= Ticket de caisse (imprimante thermique 58 mm) =================
   À l'écran, l'aperçu reste proche du rouleau (58 mm, largeur de la POS-58).
   À l'impression, la zone utile descend à 48 mm (largeur réellement imprimable
   d'une POS-58) — voir le bloc @media print. */
.ticket {
  font-family: var(--mono); font-size: 12.5px; background: #fff; color: #000;
  border: 1px dashed #cbd5e1; border-radius: 10px; padding: 14px; line-height: 1.5;
  width: 58mm; max-width: 100%; margin: 0 auto;
  /* Garde-fou : aucun mot (désignation, référence) ne peut élargir le reçu. */
  overflow-wrap: break-word; word-break: break-word;
}
.ticket .center { text-align: center; }
.ticket hr { border: none; border-top: 1px dashed #cbd5e1; margin: 8px 0; }
/* Ligne du ticket : désignation à gauche (retour à la ligne propre et
   contrôlé), montant aligné à droite sur une colonne insécable. Les montants
   ne peuvent donc jamais être poussés hors de la largeur du rouleau. */
.ticket .tk-line { display: flex; align-items: baseline; gap: 6px; }
.ticket .tk-line .tk-desc {
  flex: 1 1 auto; min-width: 0;
  overflow-wrap: break-word; word-break: break-word; hyphens: auto;
}
.ticket .tk-line .tk-amt {
  flex: 0 0 auto; text-align: right; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ticket .tk-total { font-weight: 700; margin-top: 2px; }
.ticket .tk-total .tk-desc { text-transform: uppercase; letter-spacing: .04em; }
.ticket .tk-thanks { margin-top: 8px; }

/* Indication affichée au-dessus du reçu (jamais imprimée : .no-print). */
.ticket-hint {
  width: 58mm; max-width: 100%; margin: 0 auto 8px;
  color: var(--muted); font-size: 12px; line-height: 1.45; text-align: center;
}
/* Modale du reçu : les trois boutons peuvent passer à la ligne (modale 420 px). */
.modal.ticket-modal .actions { flex-wrap: wrap; }

/* ================= Toasts ================= */
/* --nav-h place les messages au-dessus de la barre de navigation basse
   (0 sur desktop) ; l'encoche iOS est également prise en compte. */
#toast-root {
  position: fixed; right: 20px; z-index: 100; display: flex; flex-direction: column; gap: 8px;
  bottom: calc(20px + var(--nav-h) + env(safe-area-inset-bottom, 0px));
}
.toast {
  background: #101728; color: #fff; padding: 12px 16px; border-radius: 11px;
  font-size: 13.5px; box-shadow: 0 12px 30px rgba(16, 23, 40, .25);
}
.toast.error { background: var(--danger); }
.toast.success { background: var(--ok); }

.empty { color: var(--muted); padding: 22px; text-align: center; font-size: 13.5px; }
.muted { color: var(--muted); }
.center { text-align: center; }

/* ================= Connexion ================= */
.login-wrap {
  grid-column: 1 / -1;
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh; width: 100%; padding: 24px; background: var(--bg);
}
.login-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 34px 30px; width: 100%; max-width: 390px;
  box-shadow: 0 18px 44px rgba(16, 23, 40, .10);
}
.login-card .brandmark {
  width: 46px; height: 46px; border-radius: 12px; background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--display); font-weight: 700; font-size: 21px; margin-bottom: 16px;
}
.login-card h1 { font-family: var(--display); margin: 0 0 4px; font-size: 22px; }
.login-card .sub { color: var(--muted); margin-bottom: 22px; font-size: 13.5px; }
.login-card .foot { margin-top: 18px; color: var(--muted); font-size: 12px; text-align: center; }

/* ==========================================================================
   Marque boutique — logo importé (Paramètres → champ « Logo »)
   Le conteneur garde la géométrie du monogramme (38 px au rail, 46 px au
   portail et dans l'en-tête des documents, 30 px en A5) : le logo s'y inscrit
   en « contain », donc jamais déformé, sur une pastille blanche — un PNG
   transparent reste lisible sur le rail sombre comme à l'impression (fond
   blanc = pas d'encre, aucun aplat indésirable). `.has-logo` n'est posée que
   si un logo est enregistré : sans elle, le monogramme et son fond accentué
   restent strictement inchangés.
   Placées après celles du rail et de la feuille, ces règles les surchargent par
   leur spécificité (3 classes contre 2), sans recourir à !important. */
.rail .logo.has-logo, .login-card .brandmark.has-logo, .sheet .mark.has-logo {
  background: #fff; border: 1px solid var(--line); padding: 3px; overflow: hidden;
}
.rail .logo.has-logo img, .login-card .brandmark.has-logo img, .sheet .mark.has-logo img {
  width: 100%; height: 100%; object-fit: contain; display: block;
}

/* Champ « Logo » des Paramètres : aperçu carré (image ou monogramme), sélecteur
   de fichier et bouton de suppression. L'aperçu reprend la pastille blanche des
   documents, pour montrer exactement ce qui sera imprimé. */
.logo-row { display: flex; align-items: flex-start; gap: 14px; }
.logo-preview {
  width: 64px; height: 64px; border-radius: 12px; border: 1px solid var(--line);
  background: #fff; padding: 4px; flex: 0 0 64px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.logo-preview img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
.logo-mono {
  width: 100%; height: 100%; border-radius: 8px; background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--display); font-weight: 700; font-size: 22px;
}
/* flex: 1 1 0 + min-width: 0 : le champ fichier se rétrécit au lieu de déborder
   sur les petits écrans (le nom du fichier choisi peut être long). */
.logo-actions { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.logo-actions input[type="file"] { width: 100%; max-width: 100%; font-size: 12.5px; color: var(--muted); }

/* ==========================================================================
   Choix du format d'impression (A4 / A5) — barre d'actions des documents
   ========================================================================== */
.fmt-picker { display: inline-flex; align-items: center; gap: 10px; margin-right: auto; }
.fmt-switch {
  display: inline-flex; border: 1px solid var(--line); border-radius: 10px;
  overflow: hidden; background: #fff;
}
.fmt-switch .fmt {
  font: inherit; font-size: 12.5px; font-weight: 700; color: var(--muted);
  background: #fff; border: none; padding: 8px 14px; cursor: pointer; line-height: 1.2;
}
.fmt-switch .fmt + .fmt { border-left: 1px solid var(--line); }
.fmt-switch .fmt:hover { background: #f4f6fb; color: var(--text); }
.fmt-switch .fmt:active { background: #eef2fd; color: var(--text); }
.fmt-switch .fmt.on { background: var(--accent); color: #fff; }
.fmt-label { color: var(--muted); font-size: 12.5px; }
.fmt-label b { color: var(--text); font-weight: 600; }

/* ==========================================================================
   Facture / proforma — feuille A4 (design « Facture pro »)
   ========================================================================== */
.sheet {
  --sheet-accent: var(--accent);
  /* Géométrie de référence : largeur = format papier, hauteur de page avec une
     marge de sécurité de 7 mm (297 − 7) pour que la feuille tienne toujours
     dans la page à l'impression. Ces valeurs sont reprises à l'identique dans
     @media print : l'aperçu est donc fidèle au tirage (WYSIWYG). */
  width: 210mm; min-height: 290mm; background: #fff; margin: 0 auto;
  box-shadow: 0 12px 40px rgba(16, 23, 40, .22);
  position: relative; overflow: hidden; display: flex; flex-direction: column;
  font-size: 12.5px; line-height: 1.5; color: var(--text);
}
.sheet .band { height: 7px; background: var(--sheet-accent); }
.sheet .inner { padding: 16mm 16mm 0; flex: 1; display: flex; flex-direction: column; }

.sheet .head { display: flex; justify-content: space-between; gap: 24px; align-items: flex-start; }
.sheet .shop { display: flex; gap: 13px; align-items: flex-start; }
.sheet .mark {
  width: 46px; height: 46px; border-radius: 11px; background: var(--sheet-accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--display); font-weight: 700; font-size: 22px; flex: 0 0 46px;
}
.sheet .shop h1 { font-family: var(--display); font-size: 19px; font-weight: 700; line-height: 1.2; }
.sheet .shop .tag { color: var(--sheet-accent); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; margin-top: 2px; }
.sheet .shop .meta { color: var(--muted); font-size: 11.5px; margin-top: 7px; line-height: 1.65; }
.sheet .shop .meta b { color: var(--text); font-weight: 600; }

.sheet .docno { text-align: right; white-space: nowrap; }
.sheet .docno .t { font-family: var(--display); font-size: 27px; font-weight: 700; letter-spacing: .08em; }
.sheet .docno .num { font-family: var(--mono); font-size: 14px; color: var(--sheet-accent); font-weight: 700; margin-top: 4px; }
.sheet .docno .dates { margin-top: 9px; font-size: 11.5px; color: var(--muted); line-height: 1.8; }
.sheet .docno .dates b { color: var(--text); font-weight: 600; }
.sheet .rule { height: 1px; background: var(--line); margin: 16px 0; }

.sheet .bill { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.sheet .block { background: #fbfbfd; border: 1px solid var(--line); border-radius: 9px; padding: 13px 15px; }
.sheet .block .lab { font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); font-weight: 700; margin-bottom: 7px; }
.sheet .block .nm { font-family: var(--display); font-size: 14.5px; font-weight: 600; }
.sheet .block .l { color: var(--muted); font-size: 12px; margin-top: 3px; }
.sheet .block.pay { background: var(--accent-soft); border-color: #d7e2fa; }
.sheet .block.pay .nm { color: var(--sheet-accent); }

.sheet table { width: 100%; border-collapse: collapse; margin-top: 20px; font-size: 12.5px; }
.sheet thead th { background: #f4f6fb; text-align: left; font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: #4a5163; font-weight: 700; padding: 11px 12px;
  border-bottom: 1px solid var(--line);
}
.sheet thead th:first-child { border-radius: 8px 0 0 0; }
.sheet thead th:last-child { border-radius: 0 8px 0 0; }
.sheet thead th.c-desc { width: auto; }
.sheet thead th.c-qty { width: 70px; }
.sheet thead th.c-unit { width: 120px; }
.sheet thead th.c-amt { width: 130px; }
.sheet td { padding: 12px; border-bottom: 1px solid #eef0f5; vertical-align: top; background: none; }
.sheet tbody tr:hover td { background: none; }
.sheet td.desc b { font-size: 13.5px; font-weight: 600; }
.sheet td.desc span { display: block; color: var(--muted); font-size: 11px; font-family: var(--mono); margin-top: 2px; }
.sheet .r { text-align: right; }
.sheet .num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

.sheet .lower { display: flex; justify-content: space-between; gap: 28px; margin-top: 22px; }
.sheet .words { flex: 1; font-size: 12px; color: var(--muted); }
.sheet .words .lab { font-size: 10px; letter-spacing: .16em; text-transform: uppercase; font-weight: 700; color: var(--muted); margin-bottom: 6px; }
.sheet .words .amt { color: var(--text); font-weight: 600; border-bottom: 1px dotted #c9cec4; padding-bottom: 3px; display: inline-block; }
.sheet .tot { width: 290px; }
.sheet .tot .row { display: flex; justify-content: space-between; padding: 7px 0; font-size: 12.5px; color: var(--muted); }
.sheet .tot .row span:last-child { color: var(--text); }
.sheet .tot .row.disc span:last-child { color: var(--warn); }
/* « Net à payer » : fond gris clair (jamais la couleur d'accent), texte foncé. */
.sheet .tot .net {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  margin-top: 10px; background: var(--net-bg); color: var(--text);
  border: 1px solid var(--net-line); border-radius: 9px; padding: 14px 16px;
}
.sheet .tot .net .k { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--net-label); font-weight: 700; }
.sheet .tot .net .v { font-family: var(--mono); font-size: 21px; font-weight: 700; color: var(--text); }

.sheet .foot { margin-top: auto; padding: 16mm 16mm 12mm; color: var(--muted); font-size: 11px; }
.sheet .sign { display: flex; justify-content: space-between; gap: 30px; align-items: flex-end; margin-bottom: 18px; }
.sheet .sign .box { flex: 1; }
.sheet .sign .box .lab { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; color: var(--muted); }
.sheet .sign .box .ln { border-bottom: 1px solid var(--line); height: 44px; }
.sheet .sign .stamp {
  width: 150px; height: 74px; border: 1.5px dashed #c9cec4; border-radius: 9px;
  display: flex; align-items: center; justify-content: center; color: #b3b9ad;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
}
.sheet .legal { border-top: 1px solid var(--line); padding-top: 11px; display: flex; justify-content: space-between; gap: 16px; line-height: 1.7; }
.sheet .legal .c { color: var(--muted); }
.sheet .thanks { color: var(--sheet-accent); font-weight: 700; font-family: var(--display); font-size: 12.5px; margin-bottom: 5px; }
.sheet .watermark {
  position: absolute; top: 46%; left: 0; right: 0; text-align: center;
  font-family: var(--display); font-size: 62px; font-weight: 700; letter-spacing: .12em;
  color: rgba(43, 91, 215, .07); transform: rotate(-18deg); pointer-events: none;
}
.sheet .doc-notes {
  margin-top: 16px; padding: 11px 13px; border: 1px solid var(--line);
  border-radius: 9px; background: #fbfbfd; color: var(--muted); font-size: 12px;
}

/* ==========================================================================
   Format A5 (148 × 210 mm) — même feuille, typographie et espacements réduits
   pour que le document tienne sur une seule page.
   ========================================================================== */
.sheet.format-a5 { width: 148mm; min-height: 204mm; font-size: 9px; line-height: 1.42; }
.sheet.format-a5 .band { height: 5px; }
.sheet.format-a5 .inner { padding: 9mm 9mm 0; }
.sheet.format-a5 .foot { padding: 8mm 9mm 6mm; font-size: 7.5px; }

.sheet.format-a5 .head { gap: 12px; }
.sheet.format-a5 .shop { gap: 8px; }
.sheet.format-a5 .mark { width: 30px; height: 30px; border-radius: 7px; font-size: 14px; flex: 0 0 30px; }
.sheet.format-a5 .shop h1 { font-size: 13px; }
.sheet.format-a5 .shop .tag { font-size: 7.5px; letter-spacing: .1em; }
.sheet.format-a5 .shop .meta { font-size: 8px; margin-top: 4px; line-height: 1.5; }
.sheet.format-a5 .docno .t { font-size: 17px; letter-spacing: .06em; }
.sheet.format-a5 .docno .num { font-size: 10px; margin-top: 2px; }
.sheet.format-a5 .docno .dates { font-size: 8px; margin-top: 5px; line-height: 1.6; }
.sheet.format-a5 .rule { margin: 9px 0; }

.sheet.format-a5 .bill { gap: 9px; }
.sheet.format-a5 .block { padding: 8px 9px; border-radius: 6px; }
.sheet.format-a5 .block .lab { font-size: 7px; letter-spacing: .1em; margin-bottom: 4px; }
.sheet.format-a5 .block .nm { font-size: 10px; }
.sheet.format-a5 .block .l { font-size: 7.5px; margin-top: 2px; }

.sheet.format-a5 table { margin-top: 11px; font-size: 8.5px; }
.sheet.format-a5 thead th { padding: 6px 7px; font-size: 7px; letter-spacing: .08em; }
.sheet.format-a5 thead th.c-qty { width: 34px; }
.sheet.format-a5 thead th.c-unit { width: 62px; }
.sheet.format-a5 thead th.c-amt { width: 68px; }
.sheet.format-a5 td { padding: 6px 7px; }
.sheet.format-a5 td.desc b { font-size: 9px; }
.sheet.format-a5 td.desc span { font-size: 7px; margin-top: 1px; }

.sheet.format-a5 .lower { gap: 14px; margin-top: 12px; }
.sheet.format-a5 .words { font-size: 8px; }
.sheet.format-a5 .words .lab { font-size: 7px; margin-bottom: 4px; }
.sheet.format-a5 .tot { width: 190px; }
.sheet.format-a5 .tot .row { padding: 4px 0; font-size: 8.5px; }
.sheet.format-a5 .tot .net { margin-top: 6px; gap: 8px; padding: 8px 10px; border-radius: 6px; }
.sheet.format-a5 .tot .net .k { font-size: 7px; letter-spacing: .1em; }
.sheet.format-a5 .tot .net .v { font-size: 13px; }

.sheet.format-a5 .sign { gap: 16px; margin-bottom: 10px; }
.sheet.format-a5 .sign .box .lab { font-size: 7px; }
.sheet.format-a5 .sign .box .ln { height: 26px; }
.sheet.format-a5 .sign .stamp { width: 88px; height: 44px; font-size: 7px; border-radius: 6px; }
.sheet.format-a5 .legal { padding-top: 7px; gap: 10px; line-height: 1.5; }
.sheet.format-a5 .thanks { font-size: 9px; margin-bottom: 3px; }
.sheet.format-a5 .doc-notes { margin-top: 9px; padding: 7px 8px; font-size: 8px; border-radius: 6px; }

/* ==========================================================================
   Responsive — paliers
     ≥ 1024 px : desktop, mise en page de référence (rail 64 px, bento 4 col.)
     768–1023 px : tablette (rail conservé au-delà de 900 px), bento 2 col.
     < 900 px : le rail vertical devient une barre de navigation basse
     < 768 px : téléphone — bento 1 col., modales plein écran, champs 16 px
     < 420 px : petits téléphones (360–414 px)
   Les paliers mobile sont en « screen and » : le rendu imprimé (A5, 148 mm de
   large) ne doit jamais hériter des règles plein écran.
   ========================================================================== */

/* Cibles tactiles : pointeur grossier (doigt) — sans effet sur un poste à
   souris, où la mise en page desktop reste strictement identique. */
@media (pointer: coarse) {
  .rail a { min-width: 46px; min-height: 46px; }
  .btn, .btn.sm { min-height: 44px; }
  .fmt-switch .fmt { min-height: 44px; }
  input, select, textarea { font-size: 16px; }
  .search-results .item { min-height: 48px; }
}

/* ---------- ≤ 1200 px : la recherche de la barre supérieure se resserre ---------- */
@media (max-width: 1200px) {
  .searchbox { width: 220px; }
}

/* ---------- ≤ 1023 px : tablette — grilles empilées, bento sur 2 colonnes ---------- */
@media screen and (max-width: 1023px) {
  .bento { grid-template-columns: repeat(2, 1fr); }
  .tile.a, .tile.wide { grid-column: span 2; }
  .tile.wide { grid-row: span 1; }
  .grid2, .pos { grid-template-columns: 1fr; }
  .searchbox { width: 200px; }
  .content { padding: 18px; }
}

/* ---------- ≤ 900 px : le rail devient une barre de navigation basse ----------
   Toutes les entrées restent présentes (y compris Paramètres / Utilisateurs) :
   la barre défile horizontalement au lieu d'en masquer. Cibles ≥ 44 px, zone
   sûre iOS respectée (env(safe-area-inset-bottom)). */
@media screen and (max-width: 900px) {
  :root { --nav-h: 62px; }

  /* Repli sans env() : la barre basse est déjà haute de --nav-h. */
  #app {
    display: block;
    padding-bottom: var(--nav-h);
    padding-bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px));
  }
  .main { min-height: 60vh; }

  .rail {
    position: fixed; inset: auto 0 0 0; top: auto;
    width: 100%; height: auto;
    flex-direction: row; align-items: center; justify-content: flex-start;
    gap: 2px; padding: 6px 8px;
    padding: 6px 8px calc(6px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid #1b2540; z-index: 30;
    overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .rail::-webkit-scrollbar { display: none; }
  .rail .logo { display: none; }
  .rail .sp { display: none; }
  .rail .sep { width: 1px; height: 26px; margin: 0 6px; flex: 0 0 auto; }
  .rail a {
    flex: 0 0 auto;
    flex-direction: column; gap: 2px; justify-content: center;
    width: auto; min-width: 56px; min-height: 48px; height: 48px;
    padding: 5px 7px; border-radius: 11px;
  }
  .rail a svg { width: 19px; height: 19px; }
  .rail .rail-label {
    display: block; font-size: 10px; font-weight: 600; line-height: 1;
    white-space: nowrap;
  }

  /* Le titre de page reste dans la barre supérieure, simplement allégée. */
  .topbar { height: 56px; padding: 0 14px; gap: 10px; }
  .topbar h1, .topbar h2 { font-size: 17px; }

  /* Messages au-dessus de la barre de navigation. */
  #toast-root {
    left: 12px; right: 12px;
    bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px) + 12px);
  }

  /* « Valider la vente » colle au bas de l'écran : accessible sans faire
     défiler tout le panier. */
  .pos-foot {
    position: sticky; z-index: 5;
    bottom: calc(var(--nav-h) + env(safe-area-inset-bottom, 0px));
    background: var(--surface);
  }

  /* Les boutons d'aperçu / impression restent visibles sans traverser la
     feuille A4 : la barre d'actions du document se colle au bas de la vue. */
  .modal.sheet-modal .actions { position: sticky; bottom: 0; z-index: 2; }
}

@media (max-width: 820px) {
  /* La feuille (.sheet) et sa modale ne sont volontairement pas concernées par
     ce palier : l'aperçu conserve la mise en page large A4/A5 (fidèle au
     tirage) et c'est la surcouche (.modal-overlay, overflow: auto) qui défile
     horizontalement quand la fenêtre est plus étroite que la feuille. */
  .modal-overlay { padding: 16px 10px; }
}

/* ---------- ≤ 767 px : téléphone ---------- */
@media screen and (max-width: 767px) {
  .content { padding: 12px; }

  /* Tableau de bord : une seule colonne, tuiles jamais écrasées. */
  .bento { grid-template-columns: 1fr; gap: 12px; }
  .tile.a, .tile.wide, .tile.wide.solo { grid-column: span 1; }
  .tile.a .big { flex-wrap: wrap; gap: 8px; }
  .tile, .card { padding: 15px; }
  .tile .v, .stat .value { font-size: 23px; }
  .tile.a .big .v { font-size: 27px; }

  /* Barre supérieure : titre + devise + avatar. La recherche globale cède la
     place à celle de la page Produits (il n'y a plus la place pour les deux). */
  .searchbox { display: none; }
  .user-menu .who { display: none; }
  .chip { font-size: 11.5px; padding: 5px 10px; }

  /* Tableaux : le conteneur défile horizontalement, les colonnes ne sont pas
     écrasées et les boutons d'action gardent une cible ≥ 44 px. */
  th { padding: 9px 10px; }
  td { padding: 9px 10px; }
  .table-wrap { border-radius: 12px; }
  .btn.sm { padding: 9px 12px; min-height: 44px; }
  /* Deux actions par ligne (factures) : elles s'empilent dans une colonne
     bornée plutôt que d'élargir le tableau — « Voir / Imprimer » tient sur une
     ligne, chaque bouton garde 44 px de haut et le tableau défile moins loin. */
  .row-actions { gap: 6px; max-width: 160px; margin-left: auto; }
  .row-actions .btn { flex: 1 1 100%; }

  /* Formulaires : libellés au-dessus (règle .field label de base), champs
     pleine largeur et 16 px pour éviter le zoom automatique d'iOS. */
  input, select, textarea { font-size: 16px; padding: 11px 12px; min-height: 44px; }
  .field { margin-bottom: 12px; }
  .row { gap: 10px; }
  .row > * { min-width: 120px; }
  .toolbar { gap: 8px; }
  .toolbar input { width: 100%; max-width: none !important; }
  .toolbar .spacer { display: none; }
  .toolbar .btn { flex: 1 1 auto; }

  /* Modales plein écran. La feuille du document en est exclue : elle garde son
     format A4/A5 et c'est la surcouche qui défile. */
  .modal-overlay { padding: 0; align-items: stretch; }
  .modal:not(.sheet-modal) {
    width: 100%; max-width: none; min-height: 100vh; border-radius: 0;
    padding: 18px 15px calc(18px + env(safe-area-inset-bottom, 0px));
    box-shadow: none;
  }
  .modal:not(.sheet-modal) h3 { font-size: 16.5px; }
  /* Actions empilées, pleine largeur, action principale en tête. */
  .modal:not(.sheet-modal) .actions { flex-direction: column-reverse; gap: 8px; }
  .modal:not(.sheet-modal) .actions .btn { width: 100%; }
  .modal:not(.sheet-modal) .actions .spacer { display: none; }
  /* La feuille du document reste à la largeur de la fenêtre (donc à celle de la
     surcouche) pour que la barre d'actions Fermer / Imprimer reste visible sans
     défilement horizontal ; elle n'est ni étirée ni réorganisée. */
  .modal.sheet-modal { min-height: 0; align-self: flex-start; }
  .modal.sheet-modal .actions { border-radius: 0; }

  /* Caisse : recherche et panier confortables au doigt (padding + min-height,
     sans passer en flex, pour que le texte du résultat continue de se replier). */
  .search-results .item { padding: 12px; min-height: 48px; }
  .cart-line .qty { width: 84px; }
  .total-line { font-size: 21px; }
}

/* ---------- ≤ 420 px : petits téléphones (360–414 px) ---------- */
@media screen and (max-width: 420px) {
  .content { padding: 10px; }
  .tile, .card { padding: 14px; }
  .chip { display: none; }
  .rail a { min-width: 52px; padding: 4px 5px; }
  .rail .rail-label { font-size: 9.5px; }
  .btn { padding: 10px 12px; font-size: 13.5px; }
  .total-line { font-size: 19px; }
}

/* ==========================================================================
   Impression : seule la zone de document (facture / proforma / ticket) sort
   ========================================================================== */
@media print {
  @page { size: A4; margin: 0; }

  /* Tous les fonds et teintes (bandeau, blocs teintés, « Net à payer » gris,
     en-têtes de tableau) doivent sortir à l'impression. */
  *, *::before, *::after {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  html, body { background: #fff; padding: 0; margin: 0; }

  #app, #toast-root { display: none !important; }

  .modal-overlay {
    position: static; inset: auto; background: none; padding: 0;
    overflow: visible; display: block;
  }
  .modal {
    box-shadow: none; border-radius: 0; padding: 0; margin: 0;
    width: auto; max-width: none !important; background: #fff;
  }
  .modal.sheet-modal { background: #fff; }
  .modal.sheet-modal .actions { box-shadow: none; padding: 0; }

  .no-print { display: none !important; }

  /* Géométrie identique à l'écran (voir .sheet) : même largeur de format et
     même hauteur de page (marge de sécurité de 7 mm en A4 / 6 mm en A5) pour
     que l'aperçu corresponde au tirage — et pour ne jamais déborder sur une
     page blanche. max-width: 100 % n'est qu'un garde-fou contre les arrondis
     sous-pixel du moteur d'impression ; min-height (et non height) laisse une
     facture longue se répartir sur plusieurs pages sans être coupée. */
  .sheet, .sheet.format-a4, .sheet.format-a5 {
    width: 210mm; min-height: 290mm; max-width: 100%; margin: 0;
    box-shadow: none; border-radius: 0; overflow: visible;
  }
  .sheet.format-a5 { width: 148mm; min-height: 204mm; }

  .sheet .watermark { display: none; }
  /* En-tête de tableau : fond forcé, la règle * ci-dessus garantit déjà la
     sortie des couleurs. */
  .sheet thead th { background: #f4f6fb !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* Liste explicite des blocs teintés du document (bandeau, marque, blocs,
     « Net à payer »), également couverts par la règle * ci-dessus. */
  .sheet .band, .sheet .mark, .sheet .tot .net, .sheet .block.pay {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .sheet table { page-break-inside: auto; }
  .sheet tr { page-break-inside: avoid; }

  /* Ticket de caisse : 48 mm de zone imprimable (largeur utile d'une POS-58),
     marges et remplissage nuls, monospace serré, texte noir sur blanc et aucun
     fond ni teinte — une tête thermique est monochrome. Les séparateurs en
     pointillés restent acceptés. */
  .ticket, .ticket.format-ticket {
    width: 48mm; max-width: 48mm; margin: 0; padding: 0;
    border: none; border-radius: 0; background: #fff; box-shadow: none;
    color: #000; font-size: 9.5px; line-height: 1.35;
  }
  .ticket .muted, .ticket .tk-amt, .ticket .tk-desc { color: #000 !important; }
  .ticket hr { border-top: 1px dashed #000; margin: 5px 0; }
  .ticket .tk-line { gap: 4px; }
  .ticket .tk-thanks { margin-top: 6px; }
  /* Option secondaire : le même reçu tiré sur une page A4/A5 garde toute la
     largeur du papier. Les formats A4/A5 des factures/proformas ne sont pas
     concernés par ces règles. */
  .ticket.format-a4, .ticket.format-a5 {
    width: auto; max-width: 100%; font-size: 12px; line-height: 1.5;
  }
  .badge, .chip { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}
