/* =====================================================================
   Écran de caisse tactile — feuille de style

   CONÇUE POUR 1024×768, LE PLANCHER
     C'est la résolution des écrans de caisse 15 pouces les plus répandus. Tout
     est dimensionné pour tenir là ; sur un écran plus grand, la grille d'articles
     s'élargit d'elle-même par `auto-fill`.

   LA VRAIE CONTRAINTE EST LE DOIGT, NON LA RÉSOLUTION
     Dix millimètres au minimum, soit environ 34 px à 85 ppp. Les valeurs
     ci-dessous partent de là :

       bouton d'article    72 px de haut   confortable
       touche du pavé      64 px           frappe rapide
       bouton d'action     56 px
       ENCAISSER           80 px           le geste le plus fréquent

     Tout est en variables : si les boutons se révèlent trop petits sur ton
     matériel, une seule valeur à changer.

   AUCUN :hover
     Pas de souris. Un état de survol laisse une trace visuelle après un appui
     tactile, ce qui trouble la lecture. On utilise :active, qui correspond au
     doigt posé.

   AUCUNE ANIMATION DE TRANSITION SUR LES BOUTONS
     Sur un écran de caisse, le retour doit être instantané. Une transition de
     150 ms donne l'impression d'un poste lent.
   ===================================================================== */

/* ==================== JETONS DU POSTE ====================
   SÉPARÉS DE LA MISE EN PAGE, ET C'EST VOLONTAIRE
     Le plan de salle (/caisse/salle) emprunte au comptoir son rail, son bandeau
     et ses toasts — ces classes-là lisent --cai-*. Tant que les jetons vivaient
     dans la règle de mise en page de .caisse-plein-ecran, un deuxième écran
     n'avait d'autre choix que de recopier les douze valeurs, et deux chartes
     divergeaient à la première retouche. Les jetons sont donc déclarés une fois,
     pour les trois plein-écrans du POS ; la mise en page, elle, reste propre à
     chacun (le comptoir est une ligne rail | principal, la salle aussi, mais
     elles ne partagent pas leurs proportions).

   .MOB-APP EN TROISIÈME, ET C'EST UN CORRECTIF
     La caisse mobile annonce reprendre ces jetons et écrit partout
     `var(--cai-fond, #101418)` — mais elle ne figurait dans aucun sélecteur qui
     les déclare : AUCUN de ses trente `var()` ne résolvait, tous tombaient sur
     leur valeur de repli. Les valeurs étant identiques, rien ne se voyait ; une
     retouche de la charte du poste, ou le thème clair, l'auraient laissée seule
     de son côté. Elle les reçoit ici, comme les deux autres. */
/*  LE COMPTOIR ET L'INVENTAIRE ARRIVENT ICI APRÈS COUP, ET C'EST UN CORRECTIF
    Les deux plein-écrans de la tablette (/caisse/comptoir, /caisse/inventaire)
    annoncent dans leur feuille reprendre ces jetons — et leurs deux cents
    `var(--cai-…)` sont écrits SANS valeur de repli. Absents de ce sélecteur,
    AUCUN ne résolvait : `background: var(--cai-fond)` retombait sur la valeur
    initiale de la propriété, c'est-à-dire transparent, et le thème clair
    n'avait plus rien à redéfinir. Exactement la panne que le paragraphe
    ci-dessus raconte pour .mob-app, en pire — .mob-app avait ses replis.  */
.caisse-plein-ecran,
.salle-plein-ecran,
.cuisine-plein-ecran,
.comptoir-plein-ecran,
.inventaire-plein-ecran,
.mob-app {
    --cai-article-h: 72px;
    --cai-touche-h: 64px;
    --cai-action-h: 56px;
    --cai-encaisser-h: 80px;
    --cai-panier-l: 340px;

    --cai-fond: #101418;
    --cai-surface: #1b2229;
    --cai-surface-2: #232c35;
    --cai-bord: #2f3a45;
    --cai-texte: #eef2f6;
    --cai-texte-faible: #93a1b0;
    --cai-accent: #2d7ff9;
    --cai-valider: #1f9d55;
    --cai-danger: #d64545;

    /*  L'ENVELOPPE DU CHAMP E-MAIL, ET POURQUOI ELLE N'EST PAS --cai-accent.
        --cai-accent change de sens selon la portée : #2d7ff9 (bleu) dans les
        coquilles plein écran, mais #F26C16 (ORANGE) sous .caisse-modale-fond —
        et c'est précisément là que vit le dialogue de succès qui porte le champ.
        Une enveloppe orange y voisinerait le bouton d'engagement, qui est la
        seule chose que la charte autorise à être orange. L'icône garde donc son
        jeton, stable d'une portée à l'autre. */
    --cai-courriel: #2d7ff9;

    /*  ATTENTION — ni une erreur, ni un état normal. La caisse n'en avait pas :
        le stock bas écrivait #b7791f en dur (« ambre », plus bas). Le champ
        e-mail en a besoin pour la faute de frappe suspectée, qui est licite et
        ne doit surtout pas être rouge. */
    --cai-attention: #d8a13a;

    /*  LE DIALOGUE D'ENCAISSEMENT A SA PROPRE PALETTE.
        Il empruntait celle des panneaux : --cai-surface pour le cadre,
        --cai-surface-2 pour l'entête, les touches et les modes — soit
        exactement les valeurs du bandeau, du panier et de la grille
        d'articles. Posé par-dessus le comptoir, il n'était qu'un panneau de
        plus : rien ne disait où il commençait. Il monte donc d'une marche,
        avec ses creux et ses touches à lui, et s'annonce par un bandeau à
        l'accent. Le voile et l'ombre reprennent ceux de l'écran de verrou,
        seul autre dialogue du poste qui devait dominer. */
    --cai-modale: #26313d;
    --cai-modale-2: #33404e;
    --cai-modale-creux: #131a21;
    --cai-modale-bord: #45566a;
    --cai-modale-entete: #1c5fc4;
    --cai-voile: rgba(6, 10, 14, 0.82);
    --cai-modale-ombre: 0 28px 72px rgba(0, 0, 0, 0.62);
}

.caisse-plein-ecran {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    background: var(--cai-fond);
    color: var(--cai-texte);
    font-family: system-ui, -apple-system, "Segoe UI", sans-serif;

    /* Un double appui rapide ne doit pas zoomer : sur une caisse, c'est le geste
       naturel du caissier pressé. */
    touch-action: manipulation;
    -webkit-user-select: none;
    user-select: none;
    overflow: hidden;
}

/* ==================== THÈME CLAIR ====================
   La caisse est sombre par défaut (bloc ci-dessus). Le thème clair ne redéfinit
   que les couleurs : les cibles, elles, dépendent de la densité. */
/*  L'écran de cuisine (/caisse/cuisine) reçoit la même charte : c'est un poste
    du même métier, et un cuisinier qui lève les yeux depuis le passe doit
    retrouver le comptoir. Il emprunte bandeau et toasts, donc il lit --cai-* ;
    l'inscrire ici plutôt que recopier les valeurs dans sa feuille est
    exactement ce que le commentaire des jetons explique avoir déjà coûté une
    divergence à la caisse mobile. */
.caisse-plein-ecran[data-theme="clair"],
.salle-plein-ecran[data-theme="clair"],
.cuisine-plein-ecran[data-theme="clair"],
.comptoir-plein-ecran[data-theme="clair"],
.inventaire-plein-ecran[data-theme="clair"] {
    --cai-fond: #f4f6f8;
    --cai-surface: #ffffff;
    --cai-surface-2: #eef2f6;
    --cai-bord: #d3dbe3;
    --cai-texte: #1a2028;
    --cai-texte-faible: #5b6b7b;
    /*  Les deux jetons du champ e-mail s'assombrissent : sur --cai-fond #f4f6f8,
        #2d7ff9 tombe à 3,5:1 et #d8a13a à 1,9:1 — sous le seuil d'un objet
        graphique pour le second. */
    --cai-courriel: #1c5fc4;
    --cai-attention: #a8690a;
    /* accent / valider / danger : inchangés, ils contrastent dans les deux thèmes */

    /*  Le dialogue reste blanc — en clair, c'est le fond de page qui descend.
        Le bandeau prend le bleu de la charte ; le voile s'allège, un écran
        clair n'a pas besoin d'être noirci pour reculer. */
    --cai-modale: #ffffff;
    --cai-modale-2: #eef2f6;
    --cai-modale-creux: #e7edf3;
    --cai-modale-bord: #b9c5d2;
    --cai-modale-entete: #0a6ed1;
    --cai-voile: rgba(16, 22, 30, 0.55);
    --cai-modale-ombre: 0 28px 72px rgba(16, 24, 40, 0.30);
}

/* ==================== DENSITÉ ====================
   Seules les hauteurs de cibles changent — le reste s'adapte par les variables. */
.caisse-plein-ecran[data-densite="compact"],
.salle-plein-ecran[data-densite="compact"] {
    --cai-article-h: 60px;
    --cai-touche-h: 54px;
    --cai-action-h: 48px;
    --cai-encaisser-h: 68px;
}

.caisse-plein-ecran[data-densite="large"],
.salle-plein-ecran[data-densite="large"] {
    --cai-article-h: 88px;
    --cai-touche-h: 76px;
    --cai-action-h: 64px;
    --cai-encaisser-h: 92px;
}

/* Petit libellé sous une icône de bouton (ex. densité courante). */
.caisse-btn-mini {
    font-size: 0.62rem;
    font-weight: 600;
    display: block;
    line-height: 1;
    margin-top: 0.15rem;
    opacity: 0.85;
}

/* ==================== BANDEAU ==================== */

.caisse-bandeau {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.5rem 1rem;
    background: var(--cai-surface);
    border-bottom: 1px solid var(--cai-bord);
    min-height: 52px;
}

.caisse-titre { font-size: 1.25rem; font-weight: 600; }

.caisse-horloge {
    font-size: 1.5rem;
    font-variant-numeric: tabular-nums;
    color: var(--cai-texte-faible);
}

/* ==================== ALERTES ====================
   Elles se ferment au doigt : sur une caisse, chercher une petite croix fait
   perdre du temps. Toute la bande est cliquable. */

.caisse-alerte {
    padding: 0.75rem 1rem;
    font-size: 1.05rem;
    cursor: pointer;
}

.caisse-alerte-erreur { background: var(--cai-danger); color: #fff; }
.caisse-alerte-info { background: var(--cai-accent); color: #fff; }

/* ==================== NOTIFICATIONS (TOASTS) ==================== */
/* Pile fixe en haut à droite, AU-DESSUS des modales (z-index 1000) : un
   message posé pendant l'encaissement reste visible. */
.caisse-toasts {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    max-width: min(90vw, 460px);
    pointer-events: none;   /* le vide entre les toasts ne bloque pas la caisse */
}

.caisse-toast {
    pointer-events: auto;
    display: flex;
    align-items: center;
    padding: 0.85rem 1rem;
    border-radius: 10px;
    color: #fff;
    font-size: 1.02rem;
    font-weight: 600;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
    cursor: pointer;
    animation: caisse-toast-in .22s ease-out;
}

.caisse-toast-texte { flex: 1 1 auto; }
.caisse-toast-fermer { opacity: .7; margin-left: .6rem; font-weight: 400; }

.caisse-toast-succes { background: var(--cai-valider); }
.caisse-toast-erreur { background: var(--cai-danger); }
.caisse-toast-info { background: var(--cai-accent); }

@keyframes caisse-toast-in {
    from { transform: translateX(24px); opacity: 0; }
    to   { transform: translateX(0);    opacity: 1; }
}

/* Flash de la ligne juste ajoutée au panier : un voile vert qui s'efface. */
.caisse-ligne.flash { animation: caisse-flash .7s ease-out; }

@keyframes caisse-flash {
    0%   { box-shadow: inset 0 0 0 9999px rgba(31, 157, 85, .45); }
    100% { box-shadow: inset 0 0 0 9999px rgba(31, 157, 85, 0); }
}

/* Bouton de bascule du son, à l'état activé. */
.caisse-btn-secondaire.actif {
    border-color: var(--cai-valider);
    color: var(--cai-valider);
}

/* Action de ligne à l'état actif (ex. une remise est posée sur la ligne). */
.caisse-btn-action.actif {
    border-color: var(--cai-valider);
    color: var(--cai-valider);
}

/* Sélecteur du type de remise (pourcentage / montant). */
.caisse-remise-modes { display: flex; gap: 0.5rem; margin-bottom: 0.75rem; }

.caisse-remise-mode {
    flex: 1 1 0;
    min-height: var(--cai-action-h);
    background: var(--cai-surface-2);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1rem;
    font-weight: 600;
}

.caisse-remise-mode.actif {
    border-color: var(--cai-accent);
    background: var(--cai-surface);
    color: var(--cai-accent);
}

/* Ligne « Remises » dans le récapitulatif des totaux. */
.caisse-total-ligne.remise { color: var(--cai-valider); }

/* Note explicative sous la saisie d'une remise ticket. */
.caisse-remise-note {
    margin: 0.75rem 0 0;
    font-size: 0.8rem;
    color: var(--cai-texte-faible);
    text-align: center;
}

/* ==================== CORPS ==================== */

.caisse-corps {
    flex: 1;
    display: flex;
    min-height: 0;   /* sans lui, les enfants en overflow débordent du conteneur */
}

/* ==================== CATALOGUE ==================== */

.caisse-catalogue {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    padding: 0.75rem;
    gap: 0.75rem;
}

/* Le champ de scan : visible, et large. Le caissier doit voir ce que le scanner
   a lu, sans quoi une erreur de lecture est incompréhensible. */
.caisse-scan {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0 1rem;
    background: var(--cai-surface);
    border: 2px solid var(--cai-accent);
    border-radius: 8px;
    min-height: var(--cai-action-h);
}

.caisse-scan i { font-size: 1.4rem; color: var(--cai-accent); }

.caisse-scan-champ {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: var(--cai-texte);
    font-size: 1.2rem;
    padding: 0.5rem 0;
    -webkit-user-select: text;
    user-select: text;
}

.caisse-scan-champ::placeholder { color: var(--cai-texte-faible); }

.caisse-scan-vider {
    background: none;
    border: none;
    color: var(--cai-texte-faible);
    font-size: 1.3rem;
    padding: 0 0.5rem;
    min-width: 44px;
    min-height: 44px;
}

/* Familles : une ligne qui défile horizontalement. Sur 1024 px, six à huit
   familles tiennent ; au-delà, le défilement au doigt prend le relais. */
.caisse-familles {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-bottom: 0.25rem;
    scrollbar-width: none;
}

.caisse-familles::-webkit-scrollbar { display: none; }

.caisse-famille {
    flex: 0 0 auto;
    padding: 0.6rem 1.1rem;
    min-height: 48px;
    background: var(--cai-surface);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-bottom: 3px solid transparent;
    border-radius: 8px;
    font-size: 1rem;
    font-weight: 500;
}

.caisse-famille.actif {
    background: var(--cai-surface-2);
    border-bottom-color: var(--cai-accent);
}

.caisse-famille:active { background: var(--cai-surface-2); }

/* Grille d'articles.
   auto-fill avec un minimum de 140 px : quatre colonnes sur 1024, six ou sept
   sur 1920. Aucune valeur de résolution en dur. */
.caisse-grille {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    grid-auto-rows: var(--cai-article-h);
    gap: 0.5rem;
    overflow-y: auto;
    align-content: start;
}

.caisse-article {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 0.15rem;
    padding: 0.4rem;
    background: var(--cai-surface-2);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    text-align: center;
    position: relative;
    overflow: hidden;
}

.caisse-article:active { filter: brightness(1.35); }

.caisse-article-nom {
    font-size: 0.95rem;
    font-weight: 500;
    line-height: 1.15;
    /* Deux lignes au plus : un libellé long ne doit pas faire grandir le bouton,
       sinon la grille se désaligne. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.caisse-article-prix {
    font-size: 1.05rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Pastille de stock, coin haut-droit de la vignette. */
.caisse-article-stock {
    position: absolute;
    top: 0; right: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    background: rgba(0, 0, 0, 0.35);
    color: var(--cai-texte-faible);
    font-size: 0.65rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    padding: 0.1rem 0.35rem;
    border-bottom-left-radius: 6px;
}

.caisse-article-stock.faible { background: #b7791f; color: #fff; }   /* stock bas : ambre */
.caisse-article-stock.rupture { background: var(--cai-danger); color: #fff; }

/* RUPTURE DE SERVICE (script 1368), distincte de la rupture de STOCK ci-dessus.
   « Plus de poisson » n'est pas « plus de bouteilles » : le stock compte de la
   marchandise, la rupture dit ce que la cuisine ne peut plus faire — et un plat
   du jour n'a pas de stock du tout. Deux badges, deux teintes, parce qu'un
   caissier doit savoir laquelle des deux il regarde. */
.caisse-article-stock.epuise {
    background: var(--cai-texte);
    color: var(--cai-fond);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* La tuile reste CLIQUABLE : le refus appartient au serveur, et seulement si le
   gérant l'a réglé ainsi. Elle est barrée, pas éteinte. */
.caisse-article.epuise .caisse-article-nom { text-decoration: line-through; }
.caisse-article.epuise { opacity: 0.62; }

/* Prix et badge de promotion sur la vignette. */
.caisse-article-prix.promo { color: var(--cai-valider); }

.caisse-article-prix-init {
    font-size: 0.7rem;
    color: var(--cai-texte-faible);
    text-decoration: line-through;
}

.caisse-article-promo {
    position: absolute;
    top: 0; left: 0;
    background: var(--cai-valider);
    color: #fff;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    padding: 0.1rem 0.35rem;
    border-bottom-right-radius: 6px;
}

/* Bandeau « résultats de recherche ». */
.caisse-recherche-info {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
    padding: 0.4rem 0.7rem;
    background: var(--cai-surface-2);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    color: var(--cai-texte-faible);
    font-size: 0.95rem;
}

.caisse-recherche-clear {
    background: transparent;
    color: var(--cai-accent);
    border: none;
    font-weight: 600;
    font-size: 0.95rem;
    padding: 0.2rem 0.4rem;
}

/* ==================== PANIER ==================== */

.caisse-panier {
    flex: 0 0 var(--cai-panier-l);
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--cai-surface);
    border-left: 1px solid var(--cai-bord);
}

.caisse-panier-lignes {
    flex: 1;
    overflow-y: auto;
    min-height: 0;
}

.caisse-ligne {
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--cai-bord);
}

.caisse-ligne.selectionnee {
    background: var(--cai-surface-2);
    box-shadow: inset 4px 0 0 var(--cai-accent);
}

.caisse-ligne:active { background: var(--cai-surface-2); }

.caisse-ligne-haut {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    font-size: 1rem;
}

.caisse-ligne-nom {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.caisse-ligne-total { font-weight: 700; font-variant-numeric: tabular-nums; }

.caisse-ligne-bas {
    font-size: 0.85rem;
    color: var(--cai-texte-faible);
    margin-top: 0.15rem;
}

.caisse-ligne-remise { color: #f0a020; margin-left: 0.5rem; }

/* Actions sur la ligne sélectionnée */
.caisse-ligne-actions {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.35rem;
    padding: 0.5rem;
    background: var(--cai-surface-2);
    border-top: 1px solid var(--cai-bord);
}

.caisse-btn-action {
    min-height: var(--cai-action-h);
    background: var(--cai-surface);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1.2rem;
    font-weight: 600;
}

.caisse-btn-action:active { background: var(--cai-bord); }
.caisse-btn-action.danger { color: var(--cai-danger); }

/* Totaux */
.caisse-totaux {
    padding: 0.6rem 0.75rem;
    border-top: 1px solid var(--cai-bord);
    background: var(--cai-surface-2);
}

.caisse-total-ligne {
    display: flex;
    justify-content: space-between;
    font-size: 0.9rem;
    color: var(--cai-texte-faible);
    padding: 0.1rem 0;
    font-variant-numeric: tabular-nums;
}

.caisse-total-ttc {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 1.6rem;
    font-weight: 800;
    margin-top: 0.4rem;
    padding-top: 0.4rem;
    border-top: 1px solid var(--cai-bord);
    font-variant-numeric: tabular-nums;
}

/* Boutons principaux */
.caisse-actions { padding: 0.5rem; }

.caisse-btn-encaisser {
    width: 100%;
    min-height: var(--cai-encaisser-h);
    background: var(--cai-valider);
    color: #fff;
    border: none;
    border-radius: 10px;
    font-size: 1.35rem;
    font-weight: 800;
    letter-spacing: 0.02em;
}

.caisse-btn-encaisser:active { filter: brightness(1.2); }
.caisse-btn-encaisser:disabled { background: var(--cai-bord); color: var(--cai-texte-faible); }

.caisse-actions-secondaires { margin-top: 0.5rem; }

.caisse-btn-secondaire {
    width: 100%;
    min-height: var(--cai-action-h);
    background: var(--cai-surface-2);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1rem;
}

.caisse-btn-secondaire:active { background: var(--cai-bord); }
.caisse-btn-secondaire:disabled { color: var(--cai-texte-faible); }

/* ==================== ÉTAT VIDE ==================== */

.caisse-vide {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    min-height: 160px;
    color: var(--cai-texte-faible);
    font-size: 1.05rem;
    grid-column: 1 / -1;
}

/* ==================== MODALES ==================== */

.caisse-modale-fond {
    position: fixed;
    inset: 0;
    background: var(--cai-voile);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    z-index: 1000;
}

.caisse-modale {
    width: 100%;
    max-width: 820px;
    max-height: 100%;
    display: flex;
    flex-direction: column;
    background: var(--cai-modale);
    color: var(--cai-texte);
    border: 1px solid var(--cai-modale-bord);
    border-radius: 14px;
    overflow: hidden;

    /*  L'OMBRE FAIT LE DIALOGUE, PAS LA BORDURE. Sans elle, le cadre était à
        plat sur le comptoir : même surface, même filet, aucune profondeur. */
    box-shadow: var(--cai-modale-ombre);
}

.caisse-modale.petite { max-width: 460px; }

.caisse-modale-entete {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.85rem 1.1rem;
    background: var(--cai-modale-entete);
    color: #fff;
    font-size: 1.15rem;
    font-weight: 600;
}

.caisse-modale-total {
    font-size: 1.5rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.caisse-modale-corps {
    padding: 1rem;
    overflow-y: auto;
    min-height: 0;
}

.caisse-modale-pied {
    display: grid;
    grid-template-columns: 1fr 1.6fr;
    gap: 0.6rem;
    padding: 0.75rem 1rem;
    border-top: 1px solid var(--cai-modale-bord);
}

/*  LE PIED DU TICKET VALIDÉ PORTE QUATRE SORTIES, PAS UNE.
    Réimprimer, PDF 80 mm, Cadeau, PDF A4 — puis l'engagement seul sur sa ligne,
    pleine largeur. Les colonnes 1fr/1.6fr du pied ordinaire sont taillées pour
    un couple « annuler / valider » : à quatre secondaires elles reléguaient
    NOUVELLE VENTE dans l'étroite, alors que c'est le bouton que le caissier vise
    sans regarder.

    DEUX COLONNES PLUTÔT QUE QUATRE, ET C'EST LE LIBELLÉ QUI TRANCHE : « PDF
    80 mm » ne tient pas dans un quart des 460 px du dialogue, et le réduire à
    une icône ferait deviner au caissier lequel des deux papiers il choisit. Deux
    rangs de deux, l'ordre suivant la lecture — la sortie la plus courante à
    droite de la réimpression. */
.caisse-modale-pied.pied-succes { grid-template-columns: repeat(2, 1fr); }
.caisse-modale-pied.pied-succes .caisse-btn-valider,
.caisse-modale-pied.pied-succes .caisse-btn-pleine { grid-column: 1 / -1; }

/*  L'ENVOI PAR E-MAIL MONTRE SON ADRESSE AVANT DE PARTIR.
    Le champ vit dans le CORPS du dialogue et non dans son pied : le pied porte
    des gestes, celui-ci porte une donnée que le caissier relit à son client.
    Le bouton garde sa cible pleine hauteur, le champ prend ce qui reste. */
.caisse-succes-email {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.75rem;
    text-align: left;
}

.caisse-succes-email .caisse-champ { flex: 1 1 auto; min-width: 0; }
.caisse-succes-email .caisse-btn-secondaire { width: auto; flex: 0 0 auto; padding: 0 0.9rem; }

/*  LES ENFANTS DU DIALOGUE SUIVENT SA PALETTE, PAS CELLE DU COMPTOIR.
    Sans cette reprise, touches et modes gardaient --cai-surface-2 — la valeur
    que le cadre vient justement de quitter — et s'y seraient effacés. Tout est
    porté par .caisse-modale : hors du dialogue, le pavé et les boutons du
    comptoir ne bougent pas d'un pixel. */
.caisse-modale .caisse-pave-touche,
.caisse-modale .caisse-mode,
.caisse-modale .caisse-operateur,
.caisse-modale .caisse-btn-secondaire {
    background: var(--cai-modale-2);
    border-color: var(--cai-modale-bord);
}

.caisse-modale .caisse-pave-touche:active,
.caisse-modale .caisse-btn-secondaire:active { background: var(--cai-modale-bord); }

/* Les afficheurs sont en creux : on y lit, on n'y appuie pas. */
.caisse-modale .caisse-pave-affichage,
.caisse-modale .caisse-champ {
    background: var(--cai-modale-creux);
    border-color: var(--cai-modale-bord);
}

/* Le reste à payer garde son filet d'accent (vert une fois soldé) : seul le
   fond descend. Poser border-color ici l'aurait effacé. */
.caisse-modale .caisse-reste { background: var(--cai-modale-creux); }

.caisse-modale .caisse-operateur.actif {
    background: var(--cai-modale-creux);
    border-color: var(--cai-accent);
}

.caisse-modale .caisse-paiement { border-bottom-color: var(--cai-modale-bord); }

/*  LE PIN RESPONSABLE N'AVAIT AUCUN STYLE. .caisse-autorisation,
    .caisse-autorisation-libelle et .caisse-saisie étaient écrits dans la page
    sans exister dans cette feuille : au milieu du dialogue, le champ tombait
    sur le rendu par défaut du navigateur — boîte blanche, hauteur pensée pour
    une souris, sur un poste où l'on tape au doigt. Il devient un champ du
    dialogue, et se signale pour ce qu'il est : un verrou. */
.caisse-autorisation {
    margin: 0 1rem 0.85rem;
    padding: 0.7rem 0.85rem;
    background: rgba(214, 69, 69, 0.10);
    border: 1px solid var(--cai-danger);
    border-radius: 8px;
}

.caisse-autorisation-libelle {
    display: block;
    margin-bottom: 0.4rem;
    color: var(--cai-texte);
    font-size: 0.95rem;
    font-weight: 600;
}

.caisse-saisie {
    width: 100%;
    min-height: var(--cai-action-h);
    padding: 0.5rem 0.85rem;
    background: var(--cai-modale-creux);
    color: var(--cai-texte);
    border: 1px solid var(--cai-modale-bord);
    border-radius: 8px;
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: 0.35em;
    text-align: center;
}

.caisse-saisie::placeholder {
    letter-spacing: normal;
    font-size: 0.95rem;
    font-weight: 400;
    color: var(--cai-texte-faible);
}

.caisse-saisie:focus { outline: 2px solid var(--cai-accent); outline-offset: 1px; }

.caisse-btn-valider {
    min-height: var(--cai-encaisser-h);
    background: var(--cai-valider);
    color: #fff;
    border: none;
    border-radius: 10px;
    font-size: 1.25rem;
    font-weight: 800;
}

.caisse-btn-valider:active { filter: brightness(1.2); }
.caisse-btn-valider:disabled { background: var(--cai-bord); color: var(--cai-texte-faible); }

/* Le reste à payer : l'information la plus regardée de l'encaissement. */
.caisse-reste {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 0.85rem 1rem;
    margin-bottom: 0.85rem;
    background: var(--cai-surface-2);
    border-radius: 10px;
    border-left: 5px solid var(--cai-accent);
    font-size: 1.1rem;
}

.caisse-reste strong {
    font-size: 2rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.caisse-reste.solde { border-left-color: var(--cai-valider); }

.caisse-paiements { margin-bottom: 0.85rem; }

.caisse-paiement {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--cai-bord);
    font-variant-numeric: tabular-nums;
}

.caisse-paiement-retirer {
    background: none;
    border: none;
    color: var(--cai-danger);
    font-size: 1.2rem;
    min-width: 44px;
    min-height: 44px;
}

.caisse-modale-colonnes {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

/* Pavé numérique */
.caisse-pave { display: flex; flex-direction: column; gap: 0.5rem; }

.caisse-pave-affichage {
    padding: 0.6rem 0.85rem;
    background: var(--cai-fond);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1.8rem;
    font-weight: 700;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.caisse-pave-touches {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.4rem;
}

.caisse-pave-touche {
    min-height: var(--cai-touche-h);
    background: var(--cai-surface-2);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1.4rem;
    font-weight: 600;
}

.caisse-pave-touche:active { background: var(--cai-bord); }
.caisse-pave-touche.large { grid-column: span 3; font-size: 1.1rem; }

/* Modes de paiement */
.caisse-modes { display: flex; flex-direction: column; gap: 0.4rem; }

.caisse-mode {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.1rem;
    min-height: var(--cai-action-h);
    padding: 0.5rem 0.85rem;
    background: var(--cai-surface-2);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1.05rem;
    font-weight: 600;
    text-align: left;
}

.caisse-mode:active { background: var(--cai-accent); }

.caisse-mode-ref {
    font-size: 0.7rem;
    font-weight: 400;
    color: var(--cai-texte-faible);
}

/* Règlement par points de fidélité */
.caisse-fidelite-pave {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    margin-bottom: 0.85rem;
    padding: 0.6rem 0.75rem;
    background: rgba(214, 158, 46, 0.10);
    border: 1px solid rgba(214, 158, 46, 0.45);
    border-radius: 8px;
}

.caisse-fidelite-solde {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--cai-texte);
}

.caisse-fidelite-actif {
    font-size: 0.9rem;
    color: var(--cai-texte-faible);
}

.caisse-mode-fidelite {
    background: rgba(214, 158, 46, 0.22);
    border-color: rgba(214, 158, 46, 0.6);
    align-items: center;
    text-align: center;
}

.caisse-mode-fidelite:active { background: rgba(214, 158, 46, 0.4); }

/* Champs de saisie */
.caisse-champ-libelle {
    display: block;
    font-size: 0.9rem;
    color: var(--cai-texte-faible);
    margin-bottom: 0.3rem;
}

.caisse-champ-obligatoire {
    color: var(--cai-danger);
    font-size: 0.75rem;
    margin-left: 0.4rem;
}

.caisse-champ {
    width: 100%;
    min-height: var(--cai-action-h);
    padding: 0.5rem 0.85rem;
    background: var(--cai-fond);
    color: var(--cai-texte);
    border: 1px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1.1rem;
    -webkit-user-select: text;
    user-select: text;
}

.caisse-champ:focus { outline: 2px solid var(--cai-accent); outline-offset: -2px; }

.caisse-champ-aide {
    font-size: 0.8rem;
    color: var(--cai-texte-faible);
    margin-top: 0.35rem;
    line-height: 1.35;
}

.caisse-operateurs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    margin-bottom: 0.85rem;
}

.caisse-operateur {
    min-height: var(--cai-action-h);
    background: var(--cai-surface-2);
    color: var(--cai-texte);
    border: 2px solid var(--cai-bord);
    border-radius: 8px;
    font-size: 1.05rem;
    font-weight: 600;
}

.caisse-operateur.actif { border-color: var(--cai-accent); background: var(--cai-fond); }

/* Confirmation de vente */
.caisse-succes { font-size: 4rem; color: var(--cai-valider); }

.caisse-succes-numero {
    font-size: 1.6rem;
    font-weight: 700;
    margin-top: 0.5rem;
}

.caisse-succes-total {
    font-size: 2.4rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.caisse-succes-rendu {
    margin-top: 0.75rem;
    padding: 0.6rem;
    background: var(--cai-surface-2);
    border-radius: 8px;
    font-size: 1.2rem;
}

.caisse-succes-rendu strong { font-size: 1.8rem; }

.caisse-succes-impression {
    margin-top: 0.75rem;
    padding: 0.5rem;
    background: rgba(214, 69, 69, 0.15);
    border-radius: 8px;
    font-size: 0.9rem;
    color: #ffb0b0;
}

/* =====================================================================
   ÉCRANS PLUS PETITS QUE 1024 — une tablette en portrait, par exemple.
   Le panier passe alors sous le catalogue. Ce n'est pas la cible, mais
   l'écran ne doit pas devenir inutilisable.
   ===================================================================== */

@media (max-width: 900px) {
    .caisse-corps { flex-direction: column; }
    .caisse-panier { flex: 0 0 auto; max-height: 45%; border-left: none;
                     border-top: 1px solid var(--cai-bord); }
    .caisse-modale-colonnes { grid-template-columns: 1fr; }
}

/* =====================================================================
   AFFICHEUR CLIENT (2ᵉ écran)

   Lu à distance, par-dessus l'épaule : tout est plus grand et plus contrasté
   que sur l'écran caissier. Palette propre (les variables de la caisse sont
   portées par .caisse-plein-ecran) pour rester autonome.
   ===================================================================== */

.afficheur {
    --aff-fond: #0d1b2a;
    --aff-surface: #14263b;
    --aff-bord: #24405c;
    --aff-texte: #f4f8fc;
    --aff-faible: #9db4cc;
    --aff-accent: #4aa3ff;
    --aff-valider: #29c26e;

    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    background: linear-gradient(160deg, #0d1b2a 0%, #0a1420 100%);
    color: var(--aff-texte);
    font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
    overflow: hidden;
    -webkit-user-select: none;
    user-select: none;
}

.afficheur-entete {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 1.1rem 1.6rem;
    border-bottom: 1px solid var(--aff-bord);
}

.afficheur-logo {
    width: 46px;
    height: 46px;
    object-fit: contain;
    border-radius: 50%;
    background: #fff;
    padding: 4px;
}

.afficheur-marque {
    font-size: 1.6rem;
    font-weight: 700;
    letter-spacing: 0.5px;
}

.afficheur-client {
    margin-left: auto;
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--aff-texte);
    background: var(--aff-surface);
    border: 1px solid var(--aff-bord);
    border-radius: 999px;
    padding: 0.35rem 1rem;
}

.afficheur-client-pts {
    margin-left: 0.6rem;
    color: var(--aff-valider);
    font-weight: 700;
}

/* ---------- Vente en cours ---------- */
.afficheur-corps {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.afficheur-lignes {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 1rem 1.6rem;
}

.afficheur-ligne {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    padding: 0.7rem 0;
    font-size: 1.6rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.afficheur-ligne-qte { color: var(--aff-faible); min-width: 4.5rem; text-align: right; }
.afficheur-ligne-nom { flex: 1 1 auto; }
.afficheur-ligne-total { font-weight: 700; }

.afficheur-total {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1.4rem 1.6rem;
    background: var(--aff-surface);
    border-top: 2px solid var(--aff-accent);
}

.afficheur-total-libelle { font-size: 1.7rem; color: var(--aff-faible); }
.afficheur-total-montant { font-size: 3.4rem; font-weight: 800; }

.afficheur-remise {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.6rem 1.6rem 0;
    font-size: 1.5rem;
    color: var(--aff-valider);
    font-weight: 600;
}

/* ---------- Attente ---------- */
.afficheur-accueil {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 0.8rem;
}

.afficheur-accueil-titre { font-size: 4rem; font-weight: 800; }
.afficheur-accueil-sous { font-size: 1.5rem; color: var(--aff-faible); }

/* ---------- Validé ---------- */
.afficheur-merci {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 0.6rem;
}

.afficheur-rendu-libelle { font-size: 1.8rem; color: var(--aff-faible); }
.afficheur-rendu-montant { font-size: 5rem; font-weight: 800; color: var(--aff-valider); }
.afficheur-merci-texte { margin-top: 1rem; font-size: 2.4rem; font-weight: 700; }
.afficheur-ticket-num { font-size: 1.2rem; color: var(--aff-faible); }

/* =====================================================================
   PATCH DE CHARTE — export « EasyPOS comptoir » (août 2026)
   À AJOUTER à src/EasyERP.Web/wwwroot/css/caisse.css, en fin de fichier.
   Aucune règle existante n'est réécrite ; deux valeurs de variables changent
   (accent de charte), le reste est nouveau.
   ===================================================================== */

/* ---- 1. Accent de charte : l'orange EasyTech remplace le bleu ---- */
/*  L'écran de cuisine est dans la liste pour la même raison que les jetons
    plus haut : sans lui, il resterait sur le BLEU d'origine (#2d7ff9) déclaré
    au bloc des jetons, pendant que le comptoir et la salle passent à l'orange.
    Rien ne l'aurait signalé — la variable résout, elle résout simplement à
    l'ancienne valeur. C'est la divergence silencieuse que le commentaire des
    jetons raconte déjà pour la caisse mobile. */
.caisse-plein-ecran,
.salle-plein-ecran,
.cuisine-plein-ecran,
.comptoir-plein-ecran,
.inventaire-plein-ecran { --cai-accent: #F26C16; }

/* ---- 2. Bandeau : fin de barre et identité du caissier ---- */
.caisse-bandeau-fin { margin-left: auto; display: flex; align-items: center; gap: 0.75rem; }
.caisse-caissier    { font-size: 0.9rem; color: var(--cai-texte-faible); }

/* ---- 3. Tête du panier et numéro prévu ---- */
.caisse-panier-tete {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--cai-bord);
    font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em;
    color: var(--cai-texte-faible);
}
.caisse-panier-num { color: var(--cai-accent); font-variant-numeric: tabular-nums; }

/* ---- 4. Tarif applicable — vignette et ligne ---- */
.caisse-article-tarif {
    position: absolute; bottom: 0; left: 0; right: 0;
    padding: 0.05rem 0.25rem;
    background: rgba(242, 108, 22, 0.16);
    color: #f0a86a;
    font-size: 0.55rem; font-weight: 700; letter-spacing: 0.04em; text-align: center;
}
.caisse-ligne-tarif { color: var(--cai-accent); margin-left: 0.5rem; }
.caisse-ligne-note  { color: #8ec6ff; margin-left: 0.5rem; font-style: italic; }

/* ---- 5. Mode de service ---- */
.caisse-service { display: flex; gap: 0.4rem; padding: 0.5rem 0.5rem 0; }
.caisse-service-btn {
    flex: 1 1 0; min-height: 46px;
    background: var(--cai-surface-2); color: var(--cai-texte);
    border: 1px solid var(--cai-bord); border-radius: 8px;
    font-size: 0.78rem; font-weight: 700;
}
.caisse-service-btn.actif {
    background: rgba(242, 108, 22, 0.18);
    border-color: var(--cai-accent); color: var(--cai-accent);
}
.caisse-service-btn:disabled { color: #5d6b79; }

/* ---- 6. Bon de préparation — papier de production, sans aucun prix ----
   Gros chiffres de quantité, note soulignée : le poste lit à un mètre, debout. */
.bon-prep {
    width: 302px; padding: 16px; background: #ffffff; color: #14181c;
    font-family: 'IBM Plex Mono', monospace; font-size: 12px; line-height: 1.5;
}
.bon-prep-poste {
    text-align: center; font-size: 22px; font-weight: 700; letter-spacing: 0.18em;
    font-family: 'IBM Plex Sans', sans-serif;
}
.bon-prep-rappel {
    margin-top: 8px; padding: 4px; border: 2px solid #14181c;
    text-align: center; font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
}
.bon-prep-sep    { border-top: 1px dashed #14181c; margin: 10px 0; }
.bon-prep-ligne  { display: flex; gap: 10px; align-items: baseline; margin-bottom: 10px; }
.bon-prep-qte    { min-width: 62px; font-size: 20px; font-weight: 700; }
.bon-prep-nom    { flex: 1 1 auto; font-size: 16px; font-weight: 700; line-height: 1.25; }
.bon-prep-note   { margin-left: 72px; font-size: 13px; font-weight: 700; text-decoration: underline; }

/* ---- 7. Ticket 80 mm : bloc de certification et duplicata ----
   Le QR doit porter la charge utile renvoyée par E@syTax — ne rien dessiner sans elle. */
.ticket-cert {
    display: flex; flex-direction: column; gap: 3px;
    padding: 8px; border: 1px solid #14181c; text-align: center;
}
.ticket-cert-lbl { font-size: 9px; letter-spacing: 0.08em; font-weight: 700; }
.ticket-cert-num { font-size: 13px; font-weight: 700; }
.ticket-duplicata {
    margin-top: 8px; padding: 5px; border: 2px solid #14181c;
    text-align: center; font-size: 13px; font-weight: 700; letter-spacing: 0.16em;
}

/* =====================================================================
   REFONTE ÉCRAN DE VENTE — dossier de passation EasyPOS comptoir
   Trois zones : RAIL de navigation (gauche) + zone principale (bandeau + corps).
   Le plein écran passe donc en ligne ; la zone principale reste une colonne.
   Aucune règle existante n'est réécrite ; ces sélecteurs sont nouveaux, sauf
   les deux surcharges explicitement notées (direction du plein écran, wrap du bandeau).
   ===================================================================== */

/* ---- Surcharge : plein écran en ligne (rail | principal) ---- */
.caisse-plein-ecran { flex-direction: row; }

.caisse-principal {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

/* ---- Rail de navigation ---- */
.caisse-rail {
    flex: 0 0 210px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--cai-surface);
    border-right: 1px solid var(--cai-bord);
}

.rail-marque {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.85rem 1rem;
    font-weight: 800; font-size: 1.05rem; letter-spacing: 0.02em;
    border-bottom: 1px solid var(--cai-bord);
}

.rail-pastille {
    width: 10px; height: 10px; border-radius: 50%;
    background: var(--cai-accent);
    box-shadow: 0 0 0 3px rgba(242, 108, 22, 0.25);
}

.rail-liste {
    flex: 1; overflow-y: auto;
    padding: 0.4rem;
    display: flex; flex-direction: column; gap: 0.15rem;
    scrollbar-width: thin;
}

.rail-item {
    display: grid;
    grid-template-columns: 24px 1fr;
    grid-template-rows: auto auto;
    column-gap: 0.6rem;
    align-items: center;
    padding: 0.5rem 0.6rem;
    border-radius: 8px;
    color: var(--cai-texte);
    text-decoration: none;
    border: 1px solid transparent;
}

.rail-item i { grid-row: 1 / span 2; font-size: 1.15rem; color: var(--cai-texte-faible); }
.rail-item-t { font-size: 0.92rem; font-weight: 600; line-height: 1.1; }
.rail-item-s { font-size: 0.68rem; color: var(--cai-texte-faible); line-height: 1.1; }

.rail-item:active { background: var(--cai-surface-2); }
.rail-item.actif {
    background: var(--cai-surface-2);
    border-color: var(--cai-bord);
    box-shadow: inset 3px 0 0 var(--cai-accent);
}
.rail-item.actif i { color: var(--cai-accent); }

.rail-pied {
    padding: 0.6rem 1rem;
    border-top: 1px solid var(--cai-bord);
    font-size: 0.7rem; color: var(--cai-texte-faible); line-height: 1.4;
}

/* ---- Bandeau enrichi (identité, PDV, état, outils, caissier, verrou) ---- */
.caisse-bandeau { flex-wrap: wrap; }   /* surcharge : le bandeau peut passer sur deux lignes en 1024 */

.bandeau-lieu { display: flex; flex-direction: column; line-height: 1.15; }
.bandeau-lieu-t { font-size: 1.05rem; font-weight: 700; }
.bandeau-lieu-s { font-size: 0.72rem; color: var(--cai-texte-faible); }

.bandeau-pdv { display: flex; gap: 0.3rem; }
.pdv-chip {
    padding: 0.15rem 0.5rem; border-radius: 6px;
    font-size: 0.72rem; font-weight: 700; letter-spacing: 0.03em;
    background: var(--cai-surface-2); color: var(--cai-texte-faible);
    border: 1px solid var(--cai-bord);
}
.pdv-chip.actif { background: rgba(242, 108, 22, 0.18); color: var(--cai-accent); border-color: var(--cai-accent); }

.bandeau-etat { display: flex; align-items: center; gap: 0.5rem; }
.et-reseau {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.28rem 0.6rem; border-radius: 999px;
    font-size: 0.72rem; font-weight: 700; letter-spacing: 0.03em;
    background: transparent; border: 1px solid var(--cai-bord); color: var(--cai-texte-faible);
}
.et-reseau .et-pastille { width: 8px; height: 8px; border-radius: 50%; background: #3fbf6a; }
.et-reseau.on { color: #3fbf6a; border-color: rgba(63, 191, 106, 0.5); }
.et-reseau.off { color: var(--cai-danger); border-color: rgba(214, 69, 69, 0.5); }
.et-reseau.off .et-pastille { background: var(--cai-danger); }
.et-sync {
    font-size: 0.72rem; font-weight: 600; color: #f0a86a;
    background: rgba(242, 108, 22, 0.14); border: 1px solid rgba(242, 108, 22, 0.4);
    padding: 0.2rem 0.5rem; border-radius: 6px;
}

/* Les outils et l'identité caissier sont poussés à droite. */
.bandeau-outils { display: flex; align-items: center; gap: 0.4rem; margin-left: auto; flex-wrap: wrap; }
.bandeau-outils .caisse-btn-secondaire { width: auto; min-height: 40px; padding: 0 0.7rem; }

.bandeau-lang {
    font-size: 0.72rem; font-weight: 700; color: var(--cai-texte-faible);
    border: 1px solid var(--cai-bord); border-radius: 6px; padding: 0.15rem 0.4rem;
}

.bandeau-caissier { display: flex; flex-direction: column; line-height: 1.1; text-align: right; }
.bandeau-caissier .cai-nom { font-size: 0.85rem; font-weight: 700; }
.bandeau-caissier .cai-poste { font-size: 0.68rem; color: var(--cai-texte-faible); }

.bandeau-verrou {
    display: inline-flex; align-items: center; min-height: 40px; padding: 0 0.8rem;
    background: var(--cai-surface-2); color: var(--cai-texte);
    border: 1px solid var(--cai-bord); border-radius: 8px;
    font-size: 0.85rem; font-weight: 600;
}
.bandeau-verrou:active { background: var(--cai-bord); }

/* ---- Verrou / prise de poste (pavé PIN plein écran) ---- */
.caisse-verrou {
    position: fixed; inset: 0; z-index: 1500;
    display: flex; align-items: center; justify-content: center;
    background: rgba(6, 10, 14, 0.82);
}
.verrou-carte {
    width: min(92vw, 380px);
    background: var(--cai-surface); border: 1px solid var(--cai-bord);
    border-radius: 16px; padding: 1.5rem 1.5rem 1.75rem;
    display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
}
.verrou-marque {
    display: inline-flex; align-items: center; gap: 0.5rem;
    padding: 0.3rem 0.8rem; background: #1B2A5E; color: #fff;
    border-radius: 8px; font-weight: 800; font-size: 0.95rem;
}
.verrou-titre { font-size: 1.35rem; font-weight: 800; margin-top: 0.4rem; }
.verrou-sous { font-size: 0.85rem; color: var(--cai-texte-faible); }
.verrou-poste { font-size: 0.72rem; color: var(--cai-texte-faible); letter-spacing: 0.02em; }
.verrou-points { display: flex; gap: 0.8rem; margin: 0.6rem 0 1rem; }
.verrou-point {
    width: 16px; height: 16px; border-radius: 50%;
    border: 2px solid var(--cai-accent); background: transparent;
}
.verrou-point.plein { background: var(--cai-accent); }
.verrou-pave { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.6rem; width: 100%; }
.verrou-touche {
    min-height: 60px; background: var(--cai-surface-2); color: var(--cai-texte);
    border: 1px solid var(--cai-bord); border-radius: 12px;
    font-size: 1.4rem; font-weight: 700;
}
.verrou-touche:active { background: var(--cai-bord); }
.verrou-touche.secondaire { color: var(--cai-texte-faible); font-size: 1.1rem; }

/* ---- Petits écrans : le rail se resserre sur ses icônes ---- */
@media (max-width: 900px) {
    .caisse-rail { flex-basis: 60px; }
    .rail-marque { justify-content: center; font-size: 0; gap: 0; padding: 0.7rem 0; }
    .rail-item { grid-template-columns: 1fr; justify-items: center; text-align: center; }
    .rail-item-t, .rail-item-s, .rail-pied { display: none; }
    .rail-item i { grid-row: auto; }
}


/* =====================================================================
   CORRECTIF D'AFFICHAGE — écran de vente POS (21/08/2026)

   Deux défauts signalés en production :
     A. l'écran de règlement « pas très visible » ;
     B. la grille d'articles n'affiche qu'UNE seule rangée, le reste masqué.
   Deux autres trouvés en lisant la feuille, de la même famille :
     C. cinq boutons d'action de ligne dans une grille de quatre colonnes ;
     D. le panier n'affiche qu'une ligne, écrasé par ses propres boutons.

   Ce ne sont pas des réglages de couleur ou de hauteur : ce sont quatre causes
   structurelles, chacune reproductible, chacune corrigée ici. Trois se jouent
   sur la répartition de la hauteur entre éléments flex (B, C, D) ; la première
   sur la portée des jetons (A).

   Le défaut A exigeait EN PLUS un déplacement de balise dans Caisse.razor,
   fait : la fermeture de .caisse-plein-ecran est descendue sous la dernière
   modale (voir la note de code à cet endroit). Le CSS seul ne pouvait pas le
   régler — et le § A.2 ci-dessous ne doit surtout pas prétendre le contraire.
   ===================================================================== */


/* =====================================================================
   A. L'ÉCRAN DE RÈGLEMENT EST INVISIBLE PARCE QU'IL EST HORS DE PORTÉE
      DES JETONS

   Les jetons --cai-* sont déclarés sur .caisse-plein-ecran (et .salle-plein-ecran,
   .mob-app). Or dans Caisse.razor, TOUTES les modales sont écrites APRÈS la
   fermeture de .caisse-plein-ecran :

       <div class="caisse-plein-ecran">
           … rail, bandeau, corps, verrou …
       </div>                              ← fermeture
       @if (_encaissementOuvert) { <div class="caisse-modale-fond"> … } ← DEHORS

   La modale n'est donc pas descendante du nœud qui porte les jetons : elle
   n'hérite d'AUCUN. var(--cai-voile), var(--cai-modale), var(--cai-modale-entete),
   var(--cai-texte), var(--cai-modale-bord) et var(--cai-modale-ombre) sont tous
   invalides au calcul et retombent sur la valeur initiale de leur propriété :

       voile        → transparent   (le comptoir reste en pleine lumière derrière)
       cadre        → transparent   (le dialogue n'a plus de panneau)
       ombre        → none          (plus aucun détachement)
       entête       → transparent   (le bandeau bleu disparaît)
       texte        → couleur héritée du body
       bordures     → currentColor

   Le dialogue devient un empilement de texte flottant au-dessus de la caisse.
   C'est exactement le symptôme décrit — et c'est le MÊME défaut que la feuille
   documente déjà pour .mob-app (« AUCUN de ses trente var() ne résolvait »),
   sur une autre victime.

   A.1 — CORRECTION DE FOND, DANS Caisse.razor
   ────────────────────────────────────────────
   Déplacer la fermeture </div> de .caisse-plein-ecran APRÈS le dernier bloc de
   modale, pour que les modales redeviennent ses descendantes. Les modales sont
   en position: fixed : les imbriquer ne change RIEN à leur placement à l'écran,
   mais elles retrouvent les jetons — et, non moins important, l'attribut
   data-theme du poste, qu'un frère ne peut pas voir. Sans ce déplacement, le
   thème clair laisse les dialogues en palette sombre.

   A.2 — FILET DE SÉCURITÉ, ICI, MAIS SEULEMENT HORS DU POSTE
   ──────────────────────────────────────────────────────────
   Pour toute modale future écrite hors du plein écran par inadvertance, les
   jetons du dialogue sont redéclarés sur .caisse-modale-fond lui-même.

   MAIS CE FILET NE DOIT JAMAIS S'APPLIQUER À L'INTÉRIEUR DU POSTE, et c'est
   la seule subtilité de ce correctif. Un jeton déclaré SUR l'élément gagne
   toujours contre le même jeton hérité d'un ancêtre — la spécificité n'entre
   pas en jeu, l'héritage ne se dispute pas. Un filet écrit à plat sur
   .caisse-modale-fond figerait donc le dialogue sur la palette sombre alors
   que .caisse-plein-ecran[data-theme="clair"] lui tend la palette claire, et
   sur les hauteurs de cible de la densité normale alors que
   [data-densite="compact"] lui en tend d'autres. Le filet annulerait
   exactement ce que le déplacement du </div> vient de débloquer.

   D'où le :not(.caisse-plein-ecran *) — « une modale qui n'est PAS dans le
   poste ». Dans le poste, les jetons du poste font loi : thème et densité
   passent. Et si un navigateur trop ancien ne sait pas lire un :not()
   complexe, il jette la règle entière : le filet disparaît, le vrai correctif
   reste. L'échec est du bon côté.

   Les valeurs sont celles du bloc d'origine, à l'identique — sauf l'entête,
   voir plus bas.                                                              */

/* Toujours applicable, dans le poste comme dehors : ce ne sont pas des jetons,
   rien n'est hérité du plein écran qui puisse être écrasé ici.
   Le dialogue est un écran tactile à part entière : mêmes règles que le
   comptoir, sinon un double appui sur le pavé numérique zoome la page. */
.caisse-modale-fond {
    touch-action: manipulation;
    -webkit-user-select: none;
    user-select: none;
    font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
    color: var(--cai-texte);
}

.caisse-modale-fond:not(.caisse-plein-ecran *) {
    --cai-texte: #eef2f6;
    --cai-texte-faible: #93a1b0;
    --cai-fond: #101418;
    --cai-surface: #1b2229;
    --cai-surface-2: #232c35;
    --cai-bord: #2f3a45;
    --cai-accent: #F26C16;
    --cai-valider: #1f9d55;
    --cai-danger: #d64545;
    /*  Repris ici alors que l'accent y est orange : c'est exactement la portée
        pour laquelle le jeton existe (voir son commentaire plus haut). */
    --cai-courriel: #2d7ff9;
    --cai-attention: #d8a13a;

    --cai-modale: #26313d;
    --cai-modale-2: #33404e;
    --cai-modale-creux: #131a21;
    --cai-modale-bord: #45566a;
    --cai-modale-entete: #1B2A5E;
    --cai-voile: rgba(6, 10, 14, 0.82);
    --cai-modale-ombre: 0 28px 72px rgba(0, 0, 0, 0.62);

    --cai-touche-h: 64px;
    --cai-action-h: 56px;
    --cai-encaisser-h: 80px;
}

/* Le pavé numérique et les modes tombaient aussi sur la police par défaut du
   navigateur : un bouton hérite de `font: inherit` seulement si on le lui dit. */
.caisse-modale-fond button,
.caisse-modale-fond input {
    font-family: inherit;
}

/* L'ENTÊTE DOIT SUIVRE LA CHARTE DU POSTE.
   Le bandeau du dialogue est resté au bleu #1c5fc4 alors que tout le POS est
   passé à l'orange : sur un écran orange, un dialogue à bandeau bleu se lit
   comme un élément étranger, pas comme le sommet de la pile. Il prend le marine
   de la charte, qui est la couleur d'identité d'EasyPOS — l'orange reste réservé
   à l'action, et VALIDER en est déjà porteur.

   Le jeton est repris SUR LE POSTE et non sur la modale : porté par la modale,
   il gagnerait aussi contre le thème clair, qui donne à l'entête le bleu SAP
   #0a6ed1 de la charte — lequel se lit très bien sur une surface claire et n'a
   rien à voir avec le #1c5fc4 corrigé ici. Écrit sur .caisse-plein-ecran, il
   passe devant le bloc de jetons par-dessus lequel il est posé (même
   spécificité, plus loin dans la feuille) et s'efface devant
   [data-theme="clair"], qui en a une de plus. Le sombre prend le marine, le
   clair garde son bleu de charte. */
.caisse-plein-ecran { --cai-modale-entete: #1B2A5E; }


/* =====================================================================
   B. UNE SEULE RANGÉE D'ARTICLES : LE BANDEAU MANGE LA HAUTEUR DU CORPS

   La refonte a posé `.caisse-bandeau { flex-wrap: wrap; }` pour que le bandeau
   « puisse passer sur deux lignes en 1024 ». Mais le bandeau porte désormais
   neuf groupes : lieu, points de vente, état réseau, badge client, six outils,
   langue, horloge, identité caissier, verrou. En 1024 px, il ne passe pas sur
   deux lignes — il en prend quatre ou cinq.

   Or le bandeau est un élément flex sans déclaration `flex` : il vaut
   `flex: 0 1 auto`, et son minimum automatique le tient à la hauteur de son
   contenu — il ne se comprime donc pas. Le corps, lui, est en `flex: 1` AVEC
   `min-height: 0` : il accepte de descendre jusqu'à zéro.

   Résultat : le bandeau prend ce qu'il veut, le corps encaisse le reste. Il ne
   lui reste qu'une centaine de pixels, la grille est en
   `grid-auto-rows: var(--cai-article-h)` (72 px) et `overflow-y: auto` —
   il s'affiche donc EXACTEMENT une rangée, et le reste part sous la ligne de
   flottaison. Le panier subit le même sort, sans que cela se voie autant.

   CORRECTION — le bandeau cesse d'être élastique en hauteur.
   Les outils défilent horizontalement au lieu de se replier : c'est déjà le
   procédé retenu dans cette feuille pour la rangée des familles
   (`overflow-x: auto` + ascenseur masqué), donc un geste que le caissier
   connaît déjà sur cet écran. Rien n'est caché — tout reste atteignable au
   doigt — et le corps retrouve sa hauteur.                                    */

.caisse-bandeau {
    flex: 0 0 auto;          /* ne grandit plus au détriment du corps */
    flex-wrap: nowrap;       /* annule le repli hérité de la refonte */
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    row-gap: 0.35rem;
}

.caisse-bandeau::-webkit-scrollbar { display: none; }

/* Les groupes gardent leur largeur propre et ne se compriment pas en bouillie. */
.caisse-bandeau > * { flex: 0 0 auto; }

/* L'horloge et l'identité ne doivent pas être les premières sacrifiées :
   elles restent collées à droite, comme avant. */
.bandeau-outils { margin-left: auto; flex-wrap: nowrap; }

/* Le corps a désormais un plancher : sous cette hauteur, deux rangées
   d'articles ne tiennent plus et l'écran n'est plus une caisse. */
.caisse-corps { min-height: 260px; }


/* =====================================================================
   C. CINQ BOUTONS DANS UNE GRILLE DE QUATRE

   .caisse-ligne-actions est en `repeat(4, 1fr)` alors que la page pose cinq
   boutons : −, +, Qté, remise, corbeille. Le cinquième passe seul à la ligne
   suivante et s'étire sur toute la largeur — la corbeille devient la plus
   grande cible de la zone, juste sous le bouton « + ». Sur un écran tactile,
   c'est la suppression qui hérite du geste le plus facile.
   ===================================================================== */

.caisse-ligne-actions { grid-template-columns: repeat(5, 1fr); }

/* En densité compacte sur 1024, cinq colonnes dans 340 px de panier laissent
   des cibles trop étroites : on repasse à deux rangées ÉQUILIBRÉES (3 + 2),
   la corbeille n'étant plus jamais seule sur sa ligne.

   Le repli se joue sur SIX colonnes, pas sur trois, et c'est la seule façon
   d'obtenir vraiment 3 + 2 : les trois premiers boutons prennent deux colonnes
   (rangée 1, pleine), les deux derniers en prennent trois (rangée 2, deux
   cibles égales et larges). Sur une grille de trois colonnes, le placement
   automatique aurait mis −, +, Qté en rangée 1, la remise seule en rangée 2 et
   la corbeille en rangée 3 : le défaut C reproduit à l'identique, une rangée
   plus bas.

   Le rang est porté par nth-child et non par une classe : ce qui compte ici est
   la POSITION dans la grille, pas la nature du bouton. Cinq boutons — si un
   sixième arrive un jour, ces deux règles sont à revoir avec lui. */
@media (max-width: 1100px) {
    .caisse-ligne-actions { grid-template-columns: repeat(6, 1fr); }
    .caisse-ligne-actions > * { grid-column: span 2; }
    .caisse-ligne-actions > :nth-child(n + 4) { grid-column: span 3; }
}


/* =====================================================================
   D. LE PANIER N'AFFICHE QU'UNE LIGNE — LE BAS DU PANIER RÉSERVE
      PRÈS DE 400 PIXELS DE BOUTONS

   Cause distincte du défaut B, et qui subsiste même bandeau corrigé.

   .caisse-actions-secondaires est un bloc ordinaire, et chaque
   .caisse-btn-secondaire est en `width: 100%` avec `min-height: var(--cai-action-h)`.
   La page en pose CINQ : Préparation, En attente, Reprendre, Remise ticket,
   Annuler la vente. Soit 5 × 56 px empilés, plus ENCAISSER à 80 px et les
   gouttières : près de 400 px rien qu'en boutons.

   Ajoutons ce qui ne se comprime pas non plus dans cette colonne :
   l'entête du panier (~36 px), les totaux (jusqu'à sept lignes, ~150 px),
   le mode de service (~54 px) et, ligne sélectionnée, ses actions (~66 px).
   Total : environ 690 px de contenu incompressible dans une colonne qui, sur
   un écran de 768 px, dispose d'à peine plus.

   Dans cette colonne, .caisse-panier-lignes est le SEUL élément en `flex: 1`
   avec `min-height: 0` : c'est donc lui, et lui seul, qui absorbe le déficit.
   Il tombe à une trentaine de pixels — une ligne — quel que soit le nombre
   d'articles. Le panier n'est pas tronqué par erreur : il est écrasé par ses
   propres boutons.

   CORRECTION — les actions secondaires cessent d'être une pile.
   Elles passent sur deux colonnes : ce sont des utilitaires, pas le chemin
   principal, et rien ne justifiait qu'elles occupent chacune toute la largeur
   du panier alors qu'ENCAISSER, le geste le plus fréquent, en fait autant.
   « Annuler la vente » garde la pleine largeur : c'est la seule destructive,
   elle ne doit pas se confondre avec sa voisine dans un geste rapide.
   ===================================================================== */

.caisse-actions-secondaires {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.4rem;
}

/* Les boutons ne portent plus leur largeur : c'est la grille qui la donne. */
.caisse-actions-secondaires .caisse-btn-secondaire { width: auto; }

/* La destructive occupe sa propre rangée, en dernier. */
.caisse-actions-secondaires .caisse-btn-secondaire:last-child { grid-column: 1 / -1; }

/* Un plancher pour la zone des lignes : sous cette hauteur, le panier ne
   renseigne plus sur ce qu'il contient, et c'est sa seule raison d'être. */
.caisse-panier-lignes { min-height: 96px; }

/* SOUPAPE. Ce plancher remplace un `min-height: 0` — et ce zéro avait une
   vertu : il garantissait que la colonne du panier tienne TOUJOURS dans sa
   hauteur, en sacrifiant les lignes. Avec un plancher, une fenêtre vraiment
   basse (un navigateur non maximisé sur un portable) fait déborder la colonne,
   et c'est ENCAISSER, tout en bas, qui sort de l'écran : le geste le plus
   fréquent devient injoignable, sans même un ascenseur pour le rattraper.
   Échanger « une seule ligne visible » contre « plus de bouton d'encaissement »
   serait un mauvais marché. La colonne défile donc au besoin — la soupape ne
   s'ouvre que si le contenu dépasse, ce qui n'arrivait jamais avant ce
   plancher. */
.caisse-panier { overflow-y: auto; }

/* Les totaux se resserrent un peu : sept lignes de récapitulatif à 0,1 rem de
   part et d'autre, c'est de la hauteur prise aux articles pour aérer des
   chiffres qui se lisent très bien plus serrés. Le TOTAL, lui, ne bouge pas. */
.caisse-totaux { padding: 0.45rem 0.75rem; }
.caisse-total-ligne { padding: 0; line-height: 1.45; }

/* ---------------------------------------------------------------------
   ÉCRANS DE 768 PIXELS DE HAUT — la cible réelle du parc.
   Les utilitaires descendent à 48 px : au-dessus du minimum de 44 px que
   cette feuille s'impose, et 8 px gagnés sur trois rangées font 24 px
   rendus aux lignes du panier. ENCAISSER, lui, garde ses 80 px : on ne
   rabote pas le geste le plus fréquent.
   --------------------------------------------------------------------- */
@media (max-height: 820px) {
    .caisse-actions-secondaires .caisse-btn-secondaire { min-height: 48px; font-size: 0.92rem; }
    .caisse-actions { padding: 0.4rem; }
}

/* =====================================================================
   LE LOGO DU CLIENT SUR L'ÉCRAN DE VENTE (LogoSociete.razor, 2026-08-28)

   Il remplace la pastille orange de .rail-marque quand la société a déposé
   un logo (core.CompanyLogo, sql/1010). La pastille était décorative ; le
   logo, lui, dit chez qui l'on est — au caissier, et au client par-dessus
   son épaule. Sans logo déposé, la pastille revient : cet écran est
   strictement inchangé pour qui n'en a pas.

   28 PX ET NON 22 comme dans la barre du haut : le rail fait 210 px de
   large et n'a rien d'autre à loger sur cette ligne, alors que la barre du
   back-office porte cinq contrôles. Une caisse se regarde de plus loin
   qu'un écran de bureau — c'est la même raison qui donne 72 px aux boutons
   d'article.
   ===================================================================== */
.rail-marque .rail-logo {
    max-height: 28px;
    max-width: 130px;
}

/* SOUS 900 PX LE RAIL TOMBE À 60 PX et .rail-marque passe en font-size:0 :
   le mot « EasyPOS » disparaît, le logo reste. C'est le bon arbitrage — sur
   une tablette de service, la marque du client est ce qui identifie le
   poste, pas le nom du logiciel. Il faut seulement lui rendre la largeur
   que le rail n'a plus.

   900 ET NON 1024 : ce palier est celui que la feuille se donne déjà pour
   resserrer le rail (voir « Petits écrans » plus haut). En introduire un
   second à 1024 ferait rétrécir le logo AVANT le rail qui le contient. */
@media (max-width: 900px) {
    .rail-marque .rail-logo { max-width: 46px; max-height: 26px; }
}

/* --- Le crédit du client dans la liste de choix (panneau client) -------------
   La ligne portait le nom et les points sur une seule ligne ; l'état du crédit
   est une SECONDE information, d'une autre nature — une somme, pas une identité.
   Elle prend sa propre ligne sous le nom, dans le creux de la modale.

   Pas de couleur nouvelle : le neutre est celui des textes faibles du poste, le
   bloquant celui du danger, tous deux déjà définis. */
.caisse-client-ident { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }

.caisse-client-credit {
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
    color: var(--cai-texte-faible);
}

.caisse-client-credit.est-bloquant { color: var(--cai-danger); font-weight: 600; }

/* =====================================================================
   APERÇU AVANT IMPRESSION DU TICKET (PosApercuTicket.razor)

   Il vit dans la modale du poste — même cadre, même bandeau, même pied que
   l'encaissement : c'est le même écran qui continue, pas une fenêtre
   étrangère. Seul le corps change de nature, parce qu'il porte un document
   et non des contrôles.
   ===================================================================== */
.apercu-ticket { max-width: 900px; height: 92vh; }

/*  LE CADRE PREND TOUTE LA HAUTEUR RESTANTE, et c'est la seule façon d'obtenir
    un aperçu utile : à hauteur fixe, un ticket de vingt lignes s'affiche dans
    une fente de trois centimètres et il faut le faire défiler pour le juger —
    or le juger d'un coup d'œil est TOUT ce qu'on lui demande. */
.apercu-cadre {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    background: var(--cai-modale-creux);
}

.apercu-iframe { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }

.apercu-etat {
    flex: 1 1 auto;
    display: flex; align-items: center; justify-content: center;
    padding: 2rem; text-align: center;
    color: var(--cai-texte-faible);
}

.apercu-etat.est-erreur { color: var(--cai-danger); font-weight: 600; }

/*  Le choix du papier vit dans le BANDEAU et non dans le pied : le pied porte
    les sorties — fermer, télécharger, imprimer —, celui-ci change ce qu'on
    regarde. Mêler les deux ferait chercher « Imprimer » parmi des formats. */
.apercu-formats { display: flex; gap: 0.4rem; }

.apercu-format {
    min-height: 44px; padding: 0 0.9rem;
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    border: 1px solid transparent; border-radius: 8px;
    font-family: inherit; font-size: 0.92rem; font-weight: 600;
    white-space: nowrap;
}

.apercu-format.actif { background: var(--cai-accent); border-color: var(--cai-accent); }
.apercu-format:disabled { opacity: 0.55; }

/*  Trois sorties, pas deux : le pied ordinaire est taillé pour un couple
    « annuler / valider » (1fr 1.6fr) et reléguerait Imprimer dans l'étroite. */
.caisse-modale-pied.pied-apercu { grid-template-columns: 1fr 1fr 1.4fr; }

/*  Sur une tablette de service, la modale prend tout : un aperçu qu'on doit
    faire défiler dans une boîte de 60 % de l'écran ne se juge pas. */
@media (max-width: 900px) {
    .apercu-ticket { max-width: 100%; height: 100%; }
    .caisse-modale-pied.pied-apercu { grid-template-columns: 1fr; }
}


/* ===========================================================================
   CHAMP « CANAL » DE LA CAISSE (.cai-canal) — e-mail, téléphone, WhatsApp

   MÊME GRAMMAIRE QUE LE BACK-OFFICE, PAS LA MÊME TENUE.
   La grammaire vient du gabarit de gestion (.mx-canal, modele-erp.css §11) et
   est reprise telle quelle, parce qu'elle doit se lire pareil des deux côtés :
   enveloppe à GAUCHE, la COULEUR dit de quoi on parle puis ce qui cloche, le
   REMPLISSAGE dit si l'adresse a été jugée.

   Ce qui change est la tenue, et il le faut : le comptoir est un écran tactile lu
   à bout de bras, ses champs font 56 px (--cai-action-h) et la feuille mobile 46,
   contre 34 en gestion. Une enveloppe de 13 px y serait un grain de poussière, et
   un champ de 34 px la cible la plus difficile d'un écran fait de touches de 64.

   Le CONTRÔLE, lui, est rigoureusement le même : Services/Courriel.cs, appelé par
   le même composant ChampCourriel. Une adresse refusée au comptoir est refusée à
   l'identique sur la fiche salarié — c'est là qu'est la centralisation, pas dans
   la feuille de style.
   =========================================================================== */
.cai-canal { position: relative; display: block; }

/*  La réserve à gauche vaut le double de celle du back-office : 42 px pour une
    enveloppe de 18. Elle est portée par le champ QUEL QU'IL SOIT — le comptoir
    pose .caisse-champ, la feuille mobile un <input> nu qu'habille .mob-recu —
    d'où le sélecteur d'enfant direct plutôt qu'une classe. */
.cai-canal > input { padding-left: 42px; }

.cai-canal-ico {
    position: absolute;
    left: 14px; top: 50%; transform: translateY(-50%);
    font-size: 18px; line-height: 1;
    color: var(--cai-courriel, #2d7ff9);   /* EN COULEUR DÈS LE REPOS, comme en gestion */
    pointer-events: none;
    transition: color .12s ease;
}
/*  « est-valide » ne redéclare rien : la couleur du repos est déjà la bonne. Ce qui
    distingue le valide du repos est le GLYPHE (bi-envelope-fill), posé par le
    composant — le second canal, identique des deux côtés. */
.cai-canal.est-doute > .cai-canal-ico { color: var(--cai-attention, #d8a13a); }
.cai-canal.est-faux  > .cai-canal-ico { color: var(--cai-danger); }
.cai-canal:has(> input:disabled) > .cai-canal-ico { color: var(--cai-texte-faible); }

/*  La bordure du champ suit l'enveloppe. En gestion c'est .mx-input.est-faux qui la
    porte ; ici le champ n'a pas de classe garantie (le mobile n'en a aucune), donc
    la règle passe par l'enveloppe — qui, elle, en a toujours une. */
.cai-canal.est-faux > input { border-color: var(--cai-danger); }

/*  LA LIGNE SOUS LE CHAMP — le motif, pas seulement le rouge.
    Elle compte plus ici qu'ailleurs : le caissier a un client devant lui, et il ne
    reviendra pas sur l'écran pour comprendre pourquoi le bouton refuse de partir.
    En rem et non en px : la caisse dimensionne en rem, son texte faible est à 0,9. */
.cai-canal-sous {
    margin-top: .35rem;
    font-size: .85rem; line-height: 1.35;
    color: var(--cai-texte-faible);
}
.cai-canal-sous.est-erreur { color: var(--cai-danger); }
.cai-canal-sous.est-critique { color: var(--cai-attention, #d8a13a); }

/*  Lecture — aucun écran de caisse ne s'en sert aujourd'hui (les deux n'ouvrent le
    champ que pour envoyer), mais le composant sait la rendre : sans ces règles, un
    troisième écran de caisse hériterait d'un lien non habillé. */
.cai-canal-lien {
    display: inline-flex; align-items: center; gap: .5rem;
    color: var(--cai-courriel, #2d7ff9); font-weight: 600; text-decoration: none;
    word-break: break-all; min-height: 44px;
}
.cai-canal-lien:hover { text-decoration: underline; }
.cai-canal-mort {
    display: inline-flex; align-items: center; gap: .5rem;
    color: var(--cai-texte); word-break: break-all;
}
.cai-canal-mort > i { color: var(--cai-danger); }
.cai-vide { color: var(--cai-texte-faible); }

/*  L'enveloppe prend la place que l'<input> occupait dans la rangée en ligne :
    c'est elle qui est désormais l'enfant du conteneur, pas le champ. Sans ce
    report, le champ retombe à sa largeur naturelle et « Envoyer » part à l'autre
    bout de la modale. Deux endroits, un par écran repris. */
.caisse-succes-email .cai-canal { flex: 1 1 auto; min-width: 0; }
.mob-recu-texte .cai-canal { flex: 1 1 auto; min-width: 0; }
.mob-recu-texte .cai-canal > input { width: 100%; }
