/* /Components/Layout/MainLayout.razor.rz.scp.css */
.app-shell[b-cbxwjrofxn] {
    display: flex;
    min-height: 100vh;
    background: var(--paper);
}

.main-area[b-cbxwjrofxn] {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* ⚠️⚠️ TROIS LONGUEURS, PAS UN RACCOURCI — ET LE BAS EST DÉLIBÉRÉMENT ABSENT.
   `padding: 1.5rem` déclarait AUSSI `padding-bottom`, et cette feuille est SCOPÉE : Blazor
   lui ajoute `[b-xxxx]`, soit une spécificité (0,2,0) contre (0,1,0) pour `app.css`. La
   réserve de bas d'écran écrite en N1 (`calc(… + 61px + 56px …)`, pour que la dernière carte
   ne passe pas derrière la barre et le bouton flottant) était donc **écrasée sans un mot** :
   style calculé mesuré **24px**, et 97 px de la dernière carte vivaient derrière le FAB.

   ⭐⭐ LE REMÈDE SUPPRIME LE CONFLIT AU LIEU DE LE SURCLASSER. Un `!important`, ou un
   sélecteur à trois niveaux dans `app.css`, aurait GAGNÉ la cascade en la laissant exister —
   et un `!important` qui écrase ne résout pas un conflit, il le MASQUE. Ici `padding-bottom`
   n'est plus déclaré du tout de ce côté : la feuille globale en est **seule propriétaire**,
   base ET repli mobile, là où les gardes savent la lire.

   ⚠️ NE PAS REMETTRE LE RACCOURCI. Il est plus court, il a l'air équivalent, et il rendrait
   la réserve muette exactement comme avant — sans que rien ne le signale. */
.content-area[b-cbxwjrofxn] {
    flex: 1;
    padding-top: 1.5rem;
    padding-right: 1.5rem;
    padding-left: 1.5rem;
}

#blazor-error-ui[b-cbxwjrofxn] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-cbxwjrofxn] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

/* Sous 768px, la sidebar devient un tiroir "position: fixed" (voir Sidebar.razor.css) :
   elle sort du flux flex normal, donc .app-shell reste en ligne (pas besoin de
   flex-direction: column) et .main-area occupe naturellement toute la largeur. */
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-oloc7yezi4],
.components-reconnect-repeated-attempt-visible[b-oloc7yezi4],
.components-reconnect-failed-visible[b-oloc7yezi4],
.components-pause-visible[b-oloc7yezi4],
.components-resume-failed-visible[b-oloc7yezi4],
.components-rejoining-animation[b-oloc7yezi4] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-retrying[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-failed[b-oloc7yezi4],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-oloc7yezi4] {
    display: block;
}


#components-reconnect-modal[b-oloc7yezi4] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-oloc7yezi4 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-oloc7yezi4 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-oloc7yezi4 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-oloc7yezi4]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-oloc7yezi4 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-oloc7yezi4 {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-oloc7yezi4 {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-oloc7yezi4 {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-oloc7yezi4] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-oloc7yezi4] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-oloc7yezi4] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-oloc7yezi4] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-oloc7yezi4] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-oloc7yezi4] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-oloc7yezi4] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-oloc7yezi4 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-oloc7yezi4] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-oloc7yezi4 {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Layout/Sidebar.razor.rz.scp.css */
.app-sidebar[b-pmydz0qsy0] {
    width: 260px;
    min-width: 260px;
    height: 100vh;
    position: sticky;
    top: 0;
    display: flex;
    flex-direction: column;
    background: linear-gradient(180deg, #0c1730 0%, #101f42 100%);
    color: #cbd5e1;
    overflow: hidden;
}

.sidebar-brand[b-pmydz0qsy0] {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.15rem 1.25rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.brand-logo[b-pmydz0qsy0] {
    width: 100%;
    max-width: 190px;
    height: auto;
}

.sidebar-close[b-pmydz0qsy0] {
    display: none;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border: none;
    border-radius: var(--r-6);
    background: transparent;
    color: #cbd5e1;
    cursor: pointer;
}

    .sidebar-close:hover[b-pmydz0qsy0] {
        background: rgba(255, 255, 255, 0.12);
        color: #ffffff;
    }

.sidebar-overlay[b-pmydz0qsy0] {
    display: none;
}

.sidebar-nav[b-pmydz0qsy0] {
    flex: 1;
    padding: 0.5rem 0.75rem 1rem;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
}

    .sidebar-nav[b-pmydz0qsy0]::-webkit-scrollbar {
        width: 6px;
    }

    .sidebar-nav[b-pmydz0qsy0]::-webkit-scrollbar-thumb {
        background: rgba(255, 255, 255, 0.18);
        border-radius: var(--r-3);
    }

    .sidebar-nav[b-pmydz0qsy0]::-webkit-scrollbar-thumb:hover {
        background: rgba(255, 255, 255, 0.3);
    }

.sidebar-section-header[b-pmydz0qsy0] {
    margin: 1.15rem 0.5rem 0.4rem;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: #5ecbb3;
    text-transform: uppercase;
}

    .sidebar-section-header[b-pmydz0qsy0]::after {
        content: "";
        flex: 1;
        height: 1px;
        background: linear-gradient(90deg, rgba(94, 203, 179, 0.35), transparent);
    }

.sidebar-nav[b-pmydz0qsy0]  .sidebar-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.48rem 0.75rem 0.48rem 0.9rem;
    margin: 0.1rem 0;
    border-radius: var(--r-7);
    color: #b6c2d9;
    text-decoration: none;
    font-size: 0.87rem;
    line-height: 1.3;
    transition: background-color 0.15s ease, color 0.15s ease, padding-left 0.15s ease;
}

    .sidebar-nav[b-pmydz0qsy0]  .sidebar-link::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0.2rem;
        bottom: 0.2rem;
        width: 3px;
        border-radius: 2px;
        background: #ffffff;
        opacity: 0;
        transition: opacity 0.15s ease;
    }

.sidebar-dot[b-pmydz0qsy0] {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.5;
    flex: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.sidebar-label[b-pmydz0qsy0] {
    flex: 1;
    min-width: 0;
}

/* T9-h — badge « à venir ». Discret VOLONTAIREMENT : il informe sans crier, et ne doit pas
   attirer l'œil davantage que les modules réellement disponibles.
   ⚠️ Pas de ::deep ici : le <span> est écrit dans le markup de Sidebar.razor, il porte donc
   l'attribut de portée (comme .sidebar-label). ::deep ne sert qu'à l'élément racine rendu PAR
   le composant NavLink lui-même (piège #9). */
.sidebar-avenir[b-pmydz0qsy0] {
    flex: none;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
    color: rgba(255, 255, 255, 0.55);
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.10);
    white-space: nowrap;
}

.sidebar-nav[b-pmydz0qsy0]  .sidebar-link:hover {
    background: rgba(255, 255, 255, 0.06);
    color: #ffffff;
    text-decoration: none;
    padding-left: 1.05rem;
}

    .sidebar-nav[b-pmydz0qsy0]  .sidebar-link:hover .sidebar-dot {
        opacity: 0.9;
    }

.sidebar-nav[b-pmydz0qsy0]  .sidebar-link.active {
    background: linear-gradient(90deg, rgba(20, 163, 127, 0.9), rgba(6, 182, 212, 0.75));
    color: #ffffff;
    font-weight: 600;
    box-shadow: 0 2px 8px rgba(20, 163, 127, 0.25);
}

    .sidebar-nav[b-pmydz0qsy0]  .sidebar-link.active::before {
        opacity: 1;
    }

    .sidebar-nav[b-pmydz0qsy0]  .sidebar-link.active .sidebar-dot {
        opacity: 1;
        transform: scale(1.3);
    }

.sidebar-footer[b-pmydz0qsy0] {
    padding: 0.75rem;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.sidebar-footer[b-pmydz0qsy0]  .sidebar-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.48rem 0.75rem 0.48rem 0.9rem;
    border-radius: var(--r-7);
    text-decoration: none;
    font-size: 0.87rem;
    color: #f87171;
    transition: background-color 0.15s ease, color 0.15s ease;
}

    .sidebar-footer[b-pmydz0qsy0]  .sidebar-link .sidebar-dot {
        background: #f87171;
    }

    .sidebar-footer[b-pmydz0qsy0]  .sidebar-link:hover {
        background: rgba(248, 113, 113, 0.12);
        color: #fca5a5;
        text-decoration: none;
    }

/* Sous 768px : la sidebar devient un tiroir hors-écran ("off-canvas drawer") plutôt
   que la colonne fixe du desktop. "position: fixed" (et non plus "sticky") la sort
   entièrement du flux flex de .app-shell, donc .main-area reprend automatiquement
   toute la largeur sans qu'il soit nécessaire de changer .app-shell en colonne. */
@media (max-width: 768px) {
    .app-sidebar[b-pmydz0qsy0] {
        position: fixed;
        top: 0;
        left: 0;
        width: 80%;
        max-width: 300px;
        min-width: 0;
        height: 100vh;
        max-height: 100vh;
        z-index: 1100;
        box-shadow: 4px 0 24px rgba(0, 0, 0, 0.25);
        transform: translateX(-100%);
        transition: transform 0.25s ease;
    }

        .app-sidebar.open[b-pmydz0qsy0] {
            transform: translateX(0);
        }

    .sidebar-brand[b-pmydz0qsy0] {
        justify-content: space-between;
    }

    .sidebar-close[b-pmydz0qsy0] {
        display: flex;
    }

    .sidebar-overlay[b-pmydz0qsy0] {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(12, 23, 48, 0.55);
        z-index: 1090;
    }

    .sidebar-nav[b-pmydz0qsy0]  .sidebar-link,
    .sidebar-footer[b-pmydz0qsy0]  .sidebar-link {
        min-height: 44px;
    }
}
/* /Components/Layout/TopBar.razor.rz.scp.css */
.app-topbar[b-eqn01cwto3] {
    height: 64px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 32px;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    position: sticky;
    top: 0;
    z-index: 5;
    font-family: 'Manrope', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.topbar-brand[b-eqn01cwto3] {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    flex: none;
    margin-right: 26px;
}

.brand-badge[b-eqn01cwto3] {
    width: 28px;
    height: 28px;
    border-radius: var(--r-8);
    background: var(--ink);
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Manrope', sans-serif;
    font-weight: 800;
    font-size: 15px;
}

/* ⚠️ L0 — LE LOGO EST « HORS PÉRIMÈTRE » DU REDESIGN, ET IL CHANGE POURTANT DE POLICE.
   Ce n'est pas une contradiction : sa forme, sa place, sa couleur et son texte (« PRO »,
   décidé en T9-h) ne bougent pas d'un pixel. C'est la CONSÉQUENCE MÉCANIQUE de l'arbitrage
   « les deux polices EN REMPLACEMENT, PAS EN CUMUL » — le laisser en Sora obligerait à
   charger une TROISIÈME famille pour un seul mot.
   ⚠️ Il porte la police de titre parce qu'il n'a AUCUN chiffre à aligner ; c'est aussi la
   raison pour laquelle il y a sa place et pourquoi la liste Fraunces reste courte. */
.brand-name[b-eqn01cwto3] {
    font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
    font-variation-settings: 'opsz' 96;
    font-weight: 700;
    font-size: 17px;
    letter-spacing: 0.2px;
    color: var(--ink);
}

.hamburger-btn[b-eqn01cwto3] {
    display: none;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-right: 0.5rem;
    border: none;
    border-radius: var(--r-8);
    background: transparent;
    color: #0f172a;
    cursor: pointer;
}

    .hamburger-btn:hover[b-eqn01cwto3] {
        background: #f1f5f9;
    }

.mobile-brand[b-eqn01cwto3] {
    display: none;
    flex: none;
    align-items: center;
    margin-right: auto;
    font-size: 0.95rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    color: #0f172a;
}

.top-tabs[b-eqn01cwto3] {
    display: flex;
    align-items: center;
    height: 100%;
    gap: 30px;
    margin-right: auto;
    overflow-x: auto;
}

.top-tab[b-eqn01cwto3] {
    display: flex;
    align-items: center;
    height: 100%;
    padding: 0 2px;
    color: var(--slate);
    font-size: 14.5px;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    border-bottom: 2.5px solid transparent;
}

.top-tab:hover[b-eqn01cwto3] {
    color: var(--ink);
    text-decoration: none;
}

.top-tab.active[b-eqn01cwto3] {
    color: var(--ink);
    border-bottom-color: var(--teal);
}

.topbar-user[b-eqn01cwto3] {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex: none;
}

/* ⚠️ `.icon-btn`, `.icon-btn:hover` et `.icon-btn .badge` ont été RETIRÉS D'ICI le 2026-08-26,
   avec les deux boutons morts de la barre (voir le motif dans TopBar.razor). Ce CSS était
   SCOPÉ : il ne servait QUE ces deux boutons, et plus aucun élément de ce composant ne porte
   la classe.
   ⚠️⚠️ NE PAS CONFONDRE AVEC LA RÈGLE GLOBALE `.icon-btn` D'`app.css` — celle-là est employée
   par une centaine d'écrans (crayon, corbeille, catalogue) et elle est AUTONOME : sa propre
   taille (2rem), son propre rayon, son propre fond. Rien de ce qui est parti d'ici ne la
   touchait, et le retrait ne pouvait donc pas l'atteindre. */
.user-chip[b-eqn01cwto3] {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding-left: 0.85rem;
    margin-left: 0.3rem;
    border-left: 1px solid var(--line);
}

.avatar[b-eqn01cwto3] {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--blue);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 0.9rem;
}

.user-meta[b-eqn01cwto3] {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
}

    .user-meta strong[b-eqn01cwto3] {
        color: var(--ink);
        font-size: 13.5px;
        font-weight: 600;
    }

    .user-meta small[b-eqn01cwto3] {
        display: flex;
        align-items: center;
        gap: 0.3rem;
        color: var(--green);
        font-size: 11px;
        font-weight: 500;
    }

.status-dot[b-eqn01cwto3] {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--green);
}

/* Sous 768px : ligne 1 = hamburger + marque compacte + zone utilisateur réduite ;
   ligne 2 (forcée par flex-wrap + "order") = les onglets, défilables horizontalement
   plutôt qu'empilés verticalement. Choix fait plutôt que de les déplacer dans le
   tiroir : ils restent accessibles en un seul geste (glisser), sans le tap
   supplémentaire qu'il faudrait pour ouvrir le tiroir juste pour changer d'onglet. */
@media (max-width: 768px) {
    .app-topbar[b-eqn01cwto3] {
        flex-wrap: wrap;
        height: auto;
        min-height: 3.75rem;
        padding: 0.4rem 0.75rem;
        row-gap: 0.35rem;
    }

    .hamburger-btn[b-eqn01cwto3] {
        display: inline-flex;
    }

    .mobile-brand[b-eqn01cwto3] {
        display: inline-flex;
    }

    .topbar-brand[b-eqn01cwto3] {
        display: none;
    }

    .top-tabs[b-eqn01cwto3] {
        order: 3;
        flex: 1 1 100%;
        height: 2.4rem;
        gap: 0.25rem;
    }

    .top-tab[b-eqn01cwto3] {
        padding: 0 0.6rem;
        font-size: 0.85rem;
    }

    .topbar-user[b-eqn01cwto3] {
        gap: 0.4rem;
    }

    /* ⚠️ Ce bloc était un sélecteur GROUPÉ : `.icon-btn[aria-label="Messages"], .user-meta`.
       Seule la première moitié est partie avec le bouton mort — `.user-meta` DOIT rester
       cachée sous 768 px (le nom et « En ligne » ne tiennent pas à côté de l'avatar).
       ⭐ Retirer la règle entière aurait ramené le nom au mobile : un retrait qui en emporte
       un autre, invisible au build et invisible aux tests. */
    .user-meta[b-eqn01cwto3] {
        display: none;
    }

    .user-chip[b-eqn01cwto3] {
        padding-left: 0;
        margin-left: 0;
        border-left: none;
    }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   T-FICHEDOC-f — LE BOUTON RETOUR DE LA BARRE DU HAUT

   Il occupe la place de `.mobile-brand` et n'existe qu'en mobile : au bureau, l'écran de
   document garde son bouton « Retour » dans sa propre barre d'actions, où la place ne
   manque pas — cette tranche ne touche pas le bureau.

   ⚠️ La géométrie CALQUE `.hamburger-btn` (2,75 rem = 44 px, même rayon, même fond
   transparent) : deux boutons voisins de tailles différentes se liraient comme deux
   niveaux d'importance, alors qu'ils sont tous deux de la navigation.
   ⭐ 44 px est le plancher de cible du dépôt — *elle se touche en marchant, et elle n'a
   pas de second chemin* (le motif de `.navmob-tab`).
   ══════════════════════════════════════════════════════════════════════════════════════ */
.topbar-retour[b-eqn01cwto3] {
    display: none;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-right: auto;
    border: none;
    border-radius: var(--r-8);
    background: transparent;
    color: #0f172a;
    cursor: pointer;
}

    .topbar-retour:hover[b-eqn01cwto3] {
        background: #f1f5f9;
    }

@media (max-width: 768px) {
    .topbar-retour[b-eqn01cwto3] {
        display: inline-flex;
    }
}
/* /Components/Pages/DocumentPublic.razor.rz.scp.css */
/* LIENDOC — la page publique.

   ⚠️⚠️ CSS ISOLÉ (.razor.css), jamais une feuille globale : c'est la SEULE page du dépôt servie
      à un anonyme, et la leçon T-UI a été payée DEUX FOIS — styler un conteneur partagé
      (`.btn-filtres`, puis `.crud-toolbar-actions`) avait cassé des écrans que la tranche ne
      touchait même pas. Ici la fuite est IMPOSSIBLE par construction.

   ⚠️ Et rien ici ne cible une BALISE NUE : un préfixe protège les classes, pas les balises — les
      composants d'impression sont rendus DANS cette page et hériteraient de tout sélecteur large.
      ⭐ Leur mise en page (`pf-*`) doit rester EXACTEMENT celle de l'impression interne : c'est le
      point de toute la tranche — le destinataire reçoit LE MÊME document, jamais une variante. */

.docpub-etat[b-rx9tt64qtc] {
    max-width: 34rem;
    margin: 6rem auto;
    padding: 0 1.25rem;
    text-align: center;
}

/* ⚠️ Ces états ne sont PAS des erreurs techniques : ce sont des états NORMAUX (lien expiré,
   document retiré, jeton inconnu). Le ton reste sobre — un cadre rouge ferait croire à une panne
   du navigateur du client, alors que le message DIT déjà quoi faire. */
.docpub-msg[b-rx9tt64qtc] {
    font-size: 1.0625rem;
    line-height: 1.6;
    color: var(--ink, #14171F);
}

/* ⚠️ Aucune marge ni aucun fond ici : le document doit occuper la page comme à l'impression. */
.docpub-doc[b-rx9tt64qtc] {
    margin: 0;
}

/* =============================================================================
   T-DOCPUB — LA PAGE PUBLIQUE : LE FOND, LE TELEPHONE, ET LE BOUTON D IMPRESSION

   (*)(*) TOUT CE BLOC EST BORNE A `@media screen`, ET C EST LA GARANTIE CENTRALE DE LA
   TRANCHE : le destinataire doit recevoir LE MEME document que celui qu on imprime en
   interne. Le rendu IMPRIME ne doit pas bouger d un pixel -- et il ne le peut pas, puisque
   rien ici ne s applique a l impression. C est PROUVE par t113 (le bouton disparait sous
   emulateMedia('print')) et par t97, qui compte les lignes rendues des onze impressions.

   ---------------------------------------------------------------------------------------
   1. LE FOND ETAIT ANCRE A LA FENETRE, PAS A LA FEUILLE.
   `app.css` pose `.papier-fond { position: fixed; inset: 0; width/height: 100% }`. A
   L IMPRESSION c est JUSTE : le viewport EST la feuille. A L ECRAN, le viewport est la
   FENETRE -- et `object-fit` vaut `fill` par defaut, donc l image est DEFORMEE, pas recadree.
   MESURE : fond 1920x900 = ratio 2,133 sur un papier dessine pour une A4 (0,707), soit
   TROIS FOIS trop large ; et 390x844 = 0,462 sur telephone. La feuille, elle, etait deja
   correcte (794 px, centree).
   (!)(!) LE DEFAUT EST PREEXISTANT ET PARTAGE PAR LES VINGT PAGES D IMPRESSION. S il
   n apparait que MAINTENANT, c est que `AutoImprimer="false"` n existe QUE dans cette page
   (mesure : 7 occurrences, un seul fichier) : les vingt autres vont DIRECTEMENT a
   window.print() et personne ne regarde jamais leur apercu a l ecran. CETTE PAGE EST LA
   SEULE DU DEPOT OU L ON CONSULTE UN DOCUMENT.
   (!) LE REMEDE EST DONC BORNE A ELLE : le poser dans `app.css` toucherait vingt pages pour
   un gain NUL, et ce depot a paye DEUX FOIS le prix d un style pose sur un conteneur
   partage (T-UI : .btn-filtres, puis .crud-toolbar-actions).
   (!) ET CE N EST PAS LE REMEDE DE T-MARGES : celui-la corrigeait une MARGE (une longueur
   physique qui ne suivait pas le format). Ici la marge va bien -- le contenu est deja borne
   a 210 mm et centre. C est le FOND qui est accroche au mauvais conteneur.
   ============================================================================= */
@media screen {

    /* `.pf-root` est le PARENT COMMUN de l image et de la feuille (structure mesuree :
       .pf-root > img.papier-fond + div.pf-sheet). On en fait un conteneur de position AU
       FORMAT D UNE A4 : le fond s y ancre alors exactement comme il s ancre a la feuille
       lors de l impression. */
    .docpub-doc[b-rx9tt64qtc]  .pf-root {
        position: relative;
        width: 210mm;
        max-width: 100%;
        min-height: 297mm;
        margin: 16px auto;
    }

    .docpub-doc[b-rx9tt64qtc]  .pf-fmt-a5 .pf-root,
    .docpub-doc[b-rx9tt64qtc]  .pf-root.pf-fmt-a5 {
        width: 148mm;
        min-height: 210mm;
    }

    /* (*)(*) `contain` ET NON `fill` : un papier a en-tete est une IMAGE REELLE, et un
       en-tete etire est bien pire qu un bas de page blanc. Avec `contain` le papier garde
       TOUJOURS son ratio ; `object-position: top` le laisse en haut, la ou l en-tete se
       lit. Sur un document plus long qu une page, le bas reste blanc -- c est la limite,
       elle est DITE, et elle vaut mieux qu un logo deforme. */
    .docpub-doc[b-rx9tt64qtc]  .papier-fond {
        position: absolute;
        object-fit: contain;
        object-position: top center;
    }

    /* La feuille remplit son conteneur : c est lui qui porte desormais la largeur. */
    .docpub-doc[b-rx9tt64qtc]  .pf-sheet {
        margin: 0;
        max-width: none;
        min-height: 0;
    }
}

/* =============================================================================
   2. LE TELEPHONE -- LE DOCUMENT DEBORDAIT DE LA PAGE.
   MESURE a 390 px : scrollWidth 445 pour un viewport de 390, et le coupable est le TABLEAU
   DES LIGNES (`.pf-lines`, 400 px de large). Le client devait faire defiler HORIZONTALEMENT
   pour lire les montants de sa facture -- sur l appareil ou il ouvre son courriel.
   (!)(!) ET LE VRAI GASPILLAGE N EST PAS LE TABLEAU, C EST LA MARGE DU PAPIER : elle est
   dessinee pour une A4 (12 mm de chaque cote, soit ~90 px) et mange 23 % d un ecran de
   390 px. On la reduit A L ECRAN ETROIT SEULEMENT -- l impression garde ses marges reglees
   (T-MARGES), puisque tout ce bloc est en `@media screen`.
   (!) ON NE MET PAS LE DOCUMENT A L ECHELLE (`transform: scale`) : il deviendrait illisible,
   et ce serait troquer un defaut contre un autre.
   (*) LE PATRON DU DEPOT : un contenu large defile dans SON PROPRE cadre, la PAGE jamais.
   ============================================================================= */
@media screen and (max-width: 768px) {

    .docpub-doc[b-rx9tt64qtc]  .pf-root {
        width: auto;
        min-height: 0;
        margin: 0;
    }

    /* Les marges du papier, ramenees a ce qu un ecran etroit peut offrir. */
    .docpub-doc[b-rx9tt64qtc]  .pf-sheet {
        padding-left: 10px !important;
        padding-right: 10px !important;
    }

    /* (*) LE TABLEAU DEFILE DANS SON CADRE -- et il ne peut plus pousser la page. */
    .docpub-doc[b-rx9tt64qtc]  .pf-lines {
        display: block;
        overflow-x: auto;
        max-width: 100%;
        -webkit-overflow-scrolling: touch;
    }

    /* (!) `display: block` sur un <table> detache ses parties : on les remet en tableau
       DANS le cadre, sinon les colonnes ne s alignent plus. */
    .docpub-doc[b-rx9tt64qtc]  .pf-lines > thead,
    .docpub-doc[b-rx9tt64qtc]  .pf-lines > tbody,
    .docpub-doc[b-rx9tt64qtc]  .pf-lines > tfoot {
        display: table;
        width: 100%;
        min-width: 340px;
    }

    /* (*)(*) LA MESURE QUI A IMPOSE CETTE REGLE, ET LA COLONNE QUI MANQUAIT ETAIT LA PIRE :
       apres le reste du correctif, SIX colonnes sur SEPT tenaient dans 390 px -- et la
       septieme, absente de 9 px, etait « NET TTC », c est-a-dire LE MONTANT DE LA LIGNE.
       Celle que le client regarde.
       (!) LE PADDING DES CELLULES COUTE 12 px PAR COLONNE, soit 84 px sur sept : le reduire
       rend bien plus que les 9 px manquants, SANS toucher a la taille du texte -- il reste
       donc aussi lisible qu avant. (*) ET ON NE MASQUE AUCUNE COLONNE : ce serait modifier
       LE DOCUMENT, alors que toute la tranche tient dans « le destinataire recoit LE MEME
       document ». */
    .docpub-doc[b-rx9tt64qtc]  .pf-lines th,
    .docpub-doc[b-rx9tt64qtc]  .pf-lines td {
        padding-left: 3px;
        padding-right: 3px;
    }
}

/* =============================================================================
   3. LE BOUTON D IMPRESSION -- LA PROMESSE DU LIEN ETAIT « consulter ET IMPRIMER », et les
   six textes de courriel le disent au destinataire. Rien ne le lui indiquait.
   (*)(*) IL EST EN HTML PUR (`onclick="window.print()"`), JAMAIS EN `@onclick` BLAZOR, ET
   C EST UNE DECISION MESUREE : `window.print` est une fonction du navigateur, pas un service
   Blazor. Un `@onclick` EXIGERAIT le circuit POUR TOUJOURS et alourdirait la dette (B) --
   celle de rendre les vingt pages d impression STATIQUES. En HTML pur, ce bouton continuera
   de fonctionner le jour ou cette dette sera payee. Une forme qui PRESERVE une dette future
   plutot que de l alourdir.
   (!) LA PAGE EST DEJA INTERACTIVE (`@rendermode InteractiveServer`, ligne 3) : le bouton ne
   rouvre AUCUNE decision. Ce qui empeche la boite de s ouvrir seule n est pas la staticite,
   c est `AutoImprimer="false"`, passe aux sept composants.
   ============================================================================= */
.docpub-actions[b-rx9tt64qtc] {
    max-width: 210mm;
    margin: 16px auto 0;
    padding: 0 12px;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.docpub-imprimer[b-rx9tt64qtc] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 38px;
    padding: 0 16px;
    border: 1px solid var(--line, #E7E9EC);
    border-radius: var(--r-6);
    background: var(--surface, #FFFFFF);
    color: var(--ink, #14171F);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
}

.docpub-imprimer:hover[b-rx9tt64qtc] {
    background: var(--teal-soft, #E4F3F1);
    border-color: var(--teal, #0E8F84);
}

/* (*)(*) « ENREGISTRER » ET « IMPRIMER » NE SONT PAS LE MEME GESTE, et la page ne promet
   que ce qu elle sait faire. La MEME boite d impression porte « Enregistrer au format PDF »
   sur Chrome, Edge, Firefox et Safari : on le DIT, au lieu d offrir un bouton
   « Telecharger » qui promettrait un fichier que ce depot ne sait PAS produire (l arbitrage
   PDF est ouvert, mesure trois fois -- aucun package de generation). C est la regle du
   ticket de caisse : on ecarte ce qui AFFIRME. */
.docpub-aide[b-rx9tt64qtc] {
    font-size: 12.5px;
    color: var(--slate, #6E7787);
    line-height: 1.5;
}

/* (!)(!) LE BOUTON NE S IMPRIME PAS. C est le genre de detail qui se decouvre sur la
   feuille du client -- il est donc ASSERTE, sous emulateMedia('print'). */
@media print {
    .docpub-actions[b-rx9tt64qtc] {
        display: none !important;
    }
}
/* /Components/Pages/ImpressionCheques.razor.rz.scp.css */
/* T9-0 — page « Impression Chèques » : l'iframe occupe toute la hauteur restante.
   La hauteur vient d'un calc() sur la hauteur de vue moins la navbar (64px) et les marges
   du contenu — pas d'un pourcentage, qui ne fonctionnerait pas sans chaîne de parents
   en hauteur fixe. min-height garde la page utilisable sur un écran très bas. */
.chq-page[b-h0zzf6l5ih] {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.chq-head[b-h0zzf6l5ih] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

/* Repris à l'identique du stub qu'on remplace (ModuleStub.razor.css). */
.chq-breadcrumb[b-h0zzf6l5ih] {
    color: #64748b;
    font-size: 0.85rem;
    margin-bottom: 0.35rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.chq-titre[b-h0zzf6l5ih] {
    margin: 0;
}

.chq-frame[b-h0zzf6l5ih] {
    width: 100%;
    height: calc(100vh - 190px);
    min-height: 480px;
    border: 1px solid var(--line, #e2e8f0);
    border-radius: var(--r-10);
    background: #ffffff;
}

@media (max-width: 768px) {
    .chq-frame[b-h0zzf6l5ih] {
        height: calc(100vh - 230px);
        min-height: 420px;
    }
}
/* /Components/Pages/ModuleStub.razor.rz.scp.css */
.stub-page[b-sbgtjjr4so] {
    background: #ffffff;
    border: 1px dashed #cbd5e1;
    border-radius: var(--r-10);
    padding: 2.5rem;
}

.stub-breadcrumb[b-sbgtjjr4so] {
    color: #64748b;
    font-size: 0.85rem;
    margin-bottom: 0.35rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.stub-message[b-sbgtjjr4so] {
    color: #64748b;
}

/* T9-h — pastille « à venir » accolée au titre, même vocabulaire visuel que le badge du menu :
   l'utilisateur retrouve le même mot au même endroit, du clic à la page.

   ⚠⚠ T-BLV3 / J — ELLE NE TENAIT PAS CETTE PROMESSE, ET C'EST LA MESURE QUI L'A DIT. Elle
   posait `--paper` / `--slate` ; le badge du menu (`.avenir-badge`) porte `--amber-soft` /
   `--amber-dark`. *Le commentaire décrivait une intention que la règle ne servait pas* —
   famille « un nombre juste sous un mauvais nom ».
   ⚠⚠ ET J'AI FAILLI LA CORRIGER POUR UNE RAISON FAUSSE. J'avais d'abord écrit que `--paper`
   était fautif parce qu'il vaut le fond de l'application. **MESURE : 73 règles du dépôt posent
   `--paper` comme fond** — champs désactivés, encarts, pastilles, boutons fantômes. C'est une
   CONVENTION établie pour un bloc neutre posé sur du blanc, pas un défaut.
   ⭐ Le seul motif qui tient est celui-ci : **la règle ne servait pas la référence que son
   propre commentaire déclare.** Rien d'autre. *Une observation exacte — « ce fond vaut le fond
   de la page » — peut porter sur autre chose que la question posée.*
   ⚠ MESURÉ AVANT DE CORRIGER, parce que deux hypothèses rendaient le même pixel : la règle
   scopée S'APPLIQUE bien (attribut `b-sbgtjjr4so` présent, fond calculé = `rgb(238,241,237)`).
   Le défaut était la VALEUR, pas la portée — l'inverse aurait appelé un autre remède.
   ⚠ NON BORNÉ AU MOBILE, et c'est dit : le bornage du 01/09 vise l'AJOUT de fonds blancs au
   bureau. Ici on rend à une pastille le couple de sa référence déclarée ; une pastille qui
   changerait de couleur selon la largeur de l'écran serait le défaut, pas le remède.
   ⭐ CONTRASTE : `--amber-dark` sur `--amber-soft` rend **5,35**, et ce couple est DÉJÀ dans
   `CombinaisonsCourantes` de `PaletteTests` — surveillé à chaque run. */
.stub-pill[b-sbgtjjr4so] {
    display: inline-block;
    vertical-align: middle;
    margin-left: 0.5rem;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    color: var(--amber-dark);
    background: var(--amber-soft);
    border: 1px solid var(--line);
}
/* /Components/Pages/Preferences.razor.rz.scp.css */
.pref-head[b-ysgz95d4cf] {
    margin-bottom: 18px;
}

.pref-head .page-eyebrow[b-ysgz95d4cf] {
    display: block;
}

.pref-head h1[b-ysgz95d4cf] {
    font-family: 'Manrope', 'Segoe UI', sans-serif;
    font-size: 28px;
    font-weight: 800;
    color: var(--ink);
    margin: 2px 0 4px;
}

/* Carte de section (page qui défile). */
.pref-section[b-ysgz95d4cf] {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--r-16);
    padding: 18px 20px;
    margin-bottom: 16px;
    max-width: 880px;
}

.pref-section-head[b-ysgz95d4cf] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px;
}

.pref-section-head svg[b-ysgz95d4cf] {
    flex: none;
    color: var(--teal);
}

.pref-section-title[b-ysgz95d4cf] {
    font-family: 'Manrope', 'Segoe UI', sans-serif;
    font-size: 15.5px;
    font-weight: 700;
    color: var(--ink);
}

.pref-section-actif[b-ysgz95d4cf] {
    margin-left: auto;
    padding: 2px 9px;
    border-radius: var(--r-10);
    background: var(--green-soft);
    color: var(--green-dark);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* Le badge « à venir » (.avenir-badge, global) se pousse à droite ici. */
.pref-section-head .avenir-badge[b-ysgz95d4cf] {
    margin-left: auto;
}

.pref-section-desc[b-ysgz95d4cf] {
    font-size: 13px;
    color: var(--slate);
    line-height: 1.5;
    margin-bottom: 14px;
}

.pref-grid[b-ysgz95d4cf] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

/* Section grisée pour signaler « non fonctionnel ». */
.pref-section-avenir[b-ysgz95d4cf] {
    background: #fcfcfd;
}

.pref-section-avenir .pref-section-title[b-ysgz95d4cf] {
    color: var(--slate);
}

.pref-case-hint[b-ysgz95d4cf] {
    font-size: 11px;
    color: var(--slate);
    margin-left: 6px;
}

.pref-apercu[b-ysgz95d4cf] {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin: 16px 0 4px;
    padding: 12px 14px;
    background: var(--teal-soft);
    border-radius: var(--r-10);
}

.pref-apercu-label[b-ysgz95d4cf] {
    font-size: 12px;
    font-weight: 600;
    color: var(--teal-dark);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.pref-apercu-value[b-ysgz95d4cf] {
    font-family: var(--num-font);
    font-variant-numeric: tabular-nums;
    font-size: 20px;
    font-weight: 600;
    color: var(--ink);
    letter-spacing: 0.02em;
}

/* RT2 — une carte par PIÈCE FISCALE (facture / avoir client) : masque, départ, aperçu. */
.pref-series[b-ysgz95d4cf] {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.pref-serie[b-ysgz95d4cf] {
    border: 1px solid var(--line);
    border-radius: var(--r-12);
    padding: 14px;
    background: var(--paper);
}

.pref-serie-titre[b-ysgz95d4cf] {
    font-family: 'Manrope', 'Segoe UI', sans-serif;
    font-size: 14px;
    font-weight: 700;
    color: var(--ink);
    margin-bottom: 10px;
}

/* ═══════════════ T-PREFS — LA BARRE D'ACTIONS DE L'ONGLET, COLLANTE ═══════════════
   ⭐⭐ C'EST ELLE QUI RÉPOND À LA MESURE : avant cette tranche, enregistrer depuis le bas de la
   page affichait le message À 928 px DU BOUTON CLIQUÉ (mesuré). La barre collante garde le
   bouton dans la vue, et le toast passe en BAS À DROITE : l'écart tombe à ~28 px (mesuré sur la
   maquette). Le message n'était pas absent — il était hors du champ du geste. */
.pref-actions[b-ysgz95d4cf] {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 14px;
    position: sticky;
    bottom: 0;
    z-index: 5;
    padding: 12px 0 10px;
    /* Le dégradé évite que le contenu passe « sous » la barre sans transition. */
    background: linear-gradient(180deg, rgba(255,255,255,0), var(--paper, #F5F7FA) 38%);
}

.pref-dirty[b-ysgz95d4cf] {
    margin-right: auto;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--amber, #B06F00);
}

.pref-dirty--calme[b-ysgz95d4cf] {
    font-weight: 500;
    color: var(--slate, #6E7787);
}

/* ═══════════════════════ T-PREFS — LA BARRE D'ONGLETS ═══════════════════════ */
.pref-onglets[b-ysgz95d4cf] {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--line, #E5E9F0);
    padding-bottom: 10px;
    margin-bottom: 18px;
}

.pref-onglet[b-ysgz95d4cf] {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--slate, #6E7787);
    padding: 7px 13px;
    border-radius: var(--r-8);
    cursor: pointer;
    font-size: 13.5px;
    white-space: nowrap;
}

.pref-onglet:hover[b-ysgz95d4cf] {
    background: var(--paper, #F5F7FA);
    color: var(--ink, #14171F);
}

.pref-onglet.on[b-ysgz95d4cf] {
    background: var(--surface, #fff);
    border-color: var(--line, #E5E9F0);
    color: var(--ink, #14171F);
    font-weight: 600;
    box-shadow: 0 1px 3px rgba(16,24,40,.07);
}

/* Une saisie laissée dans un AUTRE onglet doit se voir : sans cette pastille, on enregistre,
   on lit sa confirmation, et on ignore ce qu'on a laissé derrière soi. */
.pref-onglet-pastille[b-ysgz95d4cf] {
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--r-9);
    background: var(--amber, #B06F00);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    display: inline-grid;
    place-items: center;
}

@media (max-width: 768px) {
    .pref-head h1[b-ysgz95d4cf] {
        font-size: 23px;
    }

    .pref-section[b-ysgz95d4cf] {
        padding: 16px;
    }

    .pref-grid[b-ysgz95d4cf] {
        grid-template-columns: 1fr;
    }

    .pref-actions button[b-ysgz95d4cf] {
        flex: 1 1 auto;
    }
}

/* Slots d'images société (entête / pied / cachet). */
.pref-images[b-ysgz95d4cf] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 14px;
    margin-top: 16px;
}

.pref-image-slot[b-ysgz95d4cf] {
    border: 1px solid var(--line);
    border-radius: var(--r-12);
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.pref-image-titre[b-ysgz95d4cf] {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink);
}

.pref-image-box[b-ysgz95d4cf] {
    height: 90px;
    border: 1px dashed var(--line);
    border-radius: var(--r-8);
    background: var(--paper, #f4f6fa);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.pref-image-thumb[b-ysgz95d4cf] {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* ===== APERÇU À L'ÉCHELLE DU PAPIER (aide au réglage des marges) =====
   ⚠️⚠️ CE BLOC NE S'APPLIQUE QU'AU SLOT PAPIER. `.pref-image-box` est PARTAGÉE avec le
   cachet : lui donner le ratio d'une page changerait sa vignette sans aucune raison.
   ⭐ POURQUOI LE RATIO : sans lui la boîte fait 220x90 (ratio 2,44) quand une A4 vaut
   0,707 — en `object-fit: contain` l'image ne couvre que 29 % de la largeur, et une
   bande posée dessus traverserait 71 % de vide. Elle MENTIRAIT. Avec le ratio A4
   l'image remplit exactement, et 1 % de boîte = 1 % de page dans les deux axes.
   ⚠️ Tout est préfixé `pref-` et vit dans ce fichier SCOPED (attribut b-xxx) : aucune
   règle ne peut fuir. ⛔ AUCUN sélecteur de balise nu — un préfixe protège les
   classes, PAS les balises (leçon du lot n°13). */
.pref-image-box--page[b-ysgz95d4cf] {
    height: auto;
    aspect-ratio: 210 / 297;
    max-width: 150px;
    margin: 0 auto;
    position: relative;
    padding: 0;
}

.pref-image-box--page .pref-image-thumb[b-ysgz95d4cf] {
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: contain;
    display: block;
}

.pref-zone-marge[b-ysgz95d4cf] {
    position: absolute;
    left: 0;
    right: 0;
    background: color-mix(in srgb, var(--teal) 26%, transparent);
    border-color: var(--teal);
    border-style: dashed;
    border-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}

.pref-zone-haute[b-ysgz95d4cf] {
    top: 0;
    border-bottom-width: 1px;
}

.pref-zone-basse[b-ysgz95d4cf] {
    bottom: 0;
    border-top-width: 1px;
}

.pref-zone-txt[b-ysgz95d4cf] {
    font-size: 9px;
    font-weight: 700;
    color: var(--teal-dark, var(--ink));
    background: color-mix(in srgb, var(--surface) 80%, transparent);
    padding: 0 3px;
    border-radius: var(--r-3);
    white-space: nowrap;
}

.pref-image-vide[b-ysgz95d4cf] {
    font-size: 12px;
    color: var(--slate);
    font-style: italic;
}

.pref-image-aide[b-ysgz95d4cf] {
    font-size: 11px;
    color: var(--slate);
    line-height: 1.4;
}

.pref-image-actions[b-ysgz95d4cf] {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.pref-image-btn[b-ysgz95d4cf] {
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

.pref-image-btn input[type="file"][b-ysgz95d4cf] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    font-size: 0;
}

@media (max-width: 768px) {
    .pref-images[b-ysgz95d4cf] {
        grid-template-columns: 1fr;
    }
}

/* ═══════════ Toast de confirmation — canal UNIQUE des neuf cartes, non bloquant ═══════════
   ⚠️⚠️ IL EST EN BAS À DROITE, ET C'EST UNE MESURE : en haut (top:76px) il s'affichait à 928 px
   du bouton cliqué quand on enregistrait depuis le bas de la page. En bas, à côté de la barre
   d'actions collante, l'écart tombe à ~28 px — le message entre dans le champ du geste.
   ⚠️ PAS de `pointer-events: none` (la maquette en a un) : il rendrait le toast invisible à
   `elementFromPoint`, donc INTESTABLE par le harnais — mesuré sur la maquette elle-même. */
.pref-toast[b-ysgz95d4cf] {
    position: fixed;
    bottom: 22px;
    right: 22px;
    z-index: 1200;
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 13px 18px;
    border-radius: var(--r-10);
    background: var(--surface, #fff);
    border: 1px solid var(--line, #E5E9F0);
    border-left: 4px solid var(--green, #1E9E6B);
    color: var(--ink, #14171F);
    font-size: 13.5px;
    box-shadow: 0 8px 26px rgba(16,24,40,.16);
    animation: pref-toast-in-b-ysgz95d4cf .18s ease-out;
    max-width: min(92vw, 430px);
}

.pref-toast.err[b-ysgz95d4cf] {
    border-left-color: var(--red, #dc2626);
}

.pref-toast-ico[b-ysgz95d4cf] {
    width: 22px;
    height: 22px;
    flex: none;
    border-radius: 50%;
    background: var(--green, #1E9E6B);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 13px;
    line-height: 1;
}

.pref-toast.err .pref-toast-ico[b-ysgz95d4cf] {
    background: var(--red, #dc2626);
}

.pref-toast-txt[b-ysgz95d4cf] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.pref-toast-titre[b-ysgz95d4cf] {
    font-weight: 640;
}

.pref-toast-detail[b-ysgz95d4cf] {
    color: var(--slate, #6E7787);
    font-size: 12.5px;
    line-height: 1.45;
}

@keyframes pref-toast-in-b-ysgz95d4cf {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (max-width: 768px) {
    .pref-toast[b-ysgz95d4cf] {
        left: 12px;
        right: 12px;
        bottom: 12px;
        max-width: none;
    }

    /* ⚠️⚠️ ONGLETS DÉFILABLES, JAMAIS UNE LISTE DÉROULANTE (tranché par Walid) : une liste CACHE
       ce qui existe, des onglets défilables le MONTRENT. Et le patron existe déjà — c'est celui
       de la barre d'onglets du haut (`.top-tabs`), défilable depuis la tranche mobile. */
    .pref-onglets[b-ysgz95d4cf] {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        margin-left: -4px;
        margin-right: -4px;
        padding-left: 4px;
        padding-right: 4px;
    }

    .pref-onglets[b-ysgz95d4cf]::-webkit-scrollbar {
        display: none;
    }

    .pref-onglet[b-ysgz95d4cf] {
        flex: none;
    }

    /* La barre d'actions garde ses deux boutons atteignables au pouce ; le compteur de
       modifications passe sous eux plutôt que de les comprimer. */
    .pref-actions[b-ysgz95d4cf] {
        flex-wrap: wrap;
        padding-bottom: 12px;
    }

    .pref-dirty[b-ysgz95d4cf] {
        order: 3;
        width: 100%;
        margin-right: 0;
        text-align: right;
    }
}

.pref-switch[b-ysgz95d4cf] {
    padding: 4px 0;
}

.pref-switch .form-check-input[b-ysgz95d4cf] {
    width: 2.4em;
    height: 1.3em;
    margin-top: 0.1em;
    cursor: pointer;
}

.pref-switch .form-check-label[b-ysgz95d4cf] {
    cursor: pointer;
    font-size: 13.5px;
    color: var(--ink);
}

.pref-switch-hint[b-ysgz95d4cf] {
    font-size: 12px;
    color: var(--slate);
}

/* T-INTERRUPTEURS — la SEULE règle ajoutée : le message de réversibilité de `gestion_variantes`
   quand du stock est DÉJÀ ventilé. ⚠️ Ambre et non rouge : ce n'est pas une erreur, c'est un
   coût — éteindre resterait POSSIBLE, mais ferait diverger les deux niveaux (INV29). */
.pref-switch-hint.pref-hint-alerte[b-ysgz95d4cf] {
    color: var(--amber);
    font-weight: 600;
}

/* ENVOI-MAIL - la rangee du courriel de test : bouton + explication cote a cote. */
.pref-envoi-test[b-ysgz95d4cf] {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 10px;
    flex-wrap: wrap;
}

/* ENVOI-MAIL - paragraphe d'intro du bloc SMTP. Classe DEDIEE (pas pref-section-desc :
   t107 cible la description de la carte par cette classe - un 2e element la portant
   casserait son selecteur en strict mode). Meme rendu, plus l'ecart du haut. */
.pref-smtp-desc[b-ysgz95d4cf] {
    font-size: 13px;
    color: var(--slate);
    line-height: 1.5;
    margin-top: 14px;
    margin-bottom: 14px;
}

/* ENVOI-MAIL - le mot de passe enregistre : des POINTS et deux gestes explicites,
   jamais un champ pre-rempli (le secret dechiffre ne transite pas vers le navigateur). */
.pref-mdp-garde[b-ysgz95d4cf] {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.pref-mdp-points[b-ysgz95d4cf] {
    font-size: 18px;
    letter-spacing: 3px;
    color: var(--ink);
    line-height: 1;
}

/* =============================================================================
   T-CPPREF — LE SELECTEUR DE CLIENT DU POINT DE VENTE, HABILLE POUR CET ECRAN

   LE DEFAUT, ET SA CAUSE MESUREE : le composant ClientPicker n'a, dans son propre
   CSS scope, que sa STRUCTURE (position, z-index, max-height). Tout son habillage
   -- fond, bordure, ombre, hauteurs, la croix -- vit dans doc-v2.css SOUS `.docv2`.
   Or PREFERENCES est le SEUL des NEUF ecrans qui l'utilisent a ne PAS porter cette
   classe (mesure : 3-3-3-2-3-3-3-2 pour les huit documents, 0 pour Preferences).
   Le composant y est donc NU, et les TROIS plaintes n'en font qu'UNE :

     .cp-panel    -> background rgba(0,0,0,0), border 0px, shadow none
     .cp-selected -> background rgba(0,0,0,0), border 0px, display BLOCK
     .cp-clear    -> border 2px OUTSET, background rgb(240,240,240)  = bouton NATIF

   (*)(*) CE N'EST NI UN PROBLEME DE PLAN DE SUPERPOSITION, NI DE FLUX. Mesure :
   le panneau est en `position: absolute; z-index: 30` et `elementFromPoint` a son
   centre rend bien une SUGGESTION -- il est au-dessus et il recoit les clics. Sortir
   du flux est le comportement VOULU d'un menu deroulant, et le texte du dessous n'a
   jamais « remonte » : il etait deja la. CE QUI MANQUE, C'EST QUE LE PANNEAU LE
   MASQUE. Il est transparent, donc ce qui vit dessous TRANSPARAIT a travers -- et
   c'est cela qui se lit comme un chevauchement.

   (*) L'ALIGNEMENT SE FAIT SUR LE CHAMP VOISIN DE CET ECRAN, PAS SUR LE SKIN DES
   DOCUMENTS : la plainte est « ne ressemble a aucun autre champ DE L'ECRAN ». Le
   <select> d'a cote a ete mesure -- 38 px de haut, bordure 1px, rayon 6px, fond
   blanc -- et c'est lui la reference.

   (!)(!) POURQUOI `::deep`, ET POURQUOI C'EST MIEUX QU'UN PREFIXE : un CSS scope
   n'atteint PAS un composant enfant (erreur #9 du depot -- le scope attribute n'est
   pose que sur les elements ecrits dans CE fichier). `::deep` le traverse, et le
   selecteur compile devient `[data-testid=...][b-xxx] .cp-panel` : la fuite vers un
   AUTRE ecran est IMPOSSIBLE PAR CONSTRUCTION, pas par discipline.
   (!) ET ON NE TOUCHE NI LE COMPOSANT NI SES CLASSES : ClientPicker et
   FournisseurPicker PARTAGENT le meme vocabulaire `cp-` (mesure : les 9 classes,
   identiques des deux cotes), et ils servent 9 + 8 = DIX-SEPT ecrans. Redessiner
   `cp-` les toucherait tous.
   ============================================================================= */
@media (min-width: 769px) {

    /* (!) BORNE AU DESKTOP : sous 768 px la feuille T11-a pose deja son propre fond
       opaque (`body .cp-wrap.cp-sheet { background: var(--surface) }`, mesure) et
       remet le panneau en flux. C'est un correctif cherement acquis -- on n'y touche
       pas, et le defaut ne s'y produit pas. */

    /* 1. LE PANNEAU DE SUGGESTIONS -- le fond qui manquait. */
    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-panel {
        background: var(--surface);
        border: 1px solid var(--line);
        border-radius: var(--r-6);
        box-shadow: 0 10px 24px rgba(15, 23, 42, 0.12);
        overflow: hidden;
    }

    /* 1-bis. LES SUGGESTIONS se distinguent les unes des autres. */
    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-item {
        padding: 8px 11px;
        cursor: pointer;
        border-bottom: 1px solid var(--line);
        border-left: 3px solid transparent;
    }

    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-item:last-child {
        border-bottom: none;
    }

    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-item:hover,
    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-item.cp-active {
        background: var(--teal-soft);
        border-left-color: var(--teal);
    }

    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-item-nom {
        font-weight: 500;
        color: var(--ink);
        font-size: 13px;
    }

    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-item-sub {
        font-size: 11px;
        color: var(--slate);
        margin-top: 2px;
    }

    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-vide {
        padding: 12px;
        text-align: center;
        color: var(--slate);
        font-size: 12.5px;
    }

    /* 2. LE CLIENT CHOISI -- le JUMEAU du <select> voisin : 38 px, bordure 1px,
       rayon 6px, fond blanc (les quatre valeurs sont MESUREES sur lui). */
    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-selected {
        display: flex;
        align-items: center;
        gap: 8px;
        height: 38px;
        padding: 0 6px 0 10px;
        border: 1px solid var(--line);
        border-radius: var(--r-6);
        background: var(--surface);
    }

    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-selected-nom {
        flex: 1;
        min-width: 0;
        font-size: 13px;
        color: var(--ink);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* 3. LA CROIX -- elle cesse d'etre le bouton NATIF du navigateur (mesure :
       `border: 2px outset` et fond gris 240, c'est-a-dire aucun style du tout). */
    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-clear {
        width: 24px;
        height: 24px;
        border: none;
        background: transparent;
        color: var(--slate);
        border-radius: var(--r-6);
        cursor: pointer;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
    }

    [data-testid="pref-pos-client-champ"][b-ysgz95d4cf]  .cp-clear:hover {
        background: var(--red-soft);
        color: var(--red);
    }
}
/* /Components/Pages/TarifDocument.razor.rz.scp.css */
/* =====================================================================================
   DESIGN-3 — LA MISE EN PAGE DE L'ÉCRAN « TARIF », ET RIEN D'AUTRE.

   ⚠️⚠️ POURQUOI UN FICHIER SCOPÉ ET NON `app.css` : ces règles ne servent qu'à cet écran.
   Les poser globalement les mettrait à portée des 117 autres, et c'est le défaut T-UI que
   le dépôt a déjà payé deux fois. Ce qui EST partagé — `doc-card`, `docf-section`,
   `crud-list`, `crud-empile`, `form-control`, `btn*`, `alert*` — n'est pas redéfini ici :
   il est EMPLOYÉ.

   ⚠️ PIÈGE #9 — le scope (`b-xxxxx`) ne se pose QUE sur les éléments écrits dans le `.razor`
   de cet écran. `DocTeteCarte` est un composant ENFANT : son markup ne le porte PAS, donc
   aucune règle ci-dessous ne le vise. C'est voulu — sa mise en forme vit dans `app.css`,
   avec les onze documents qui l'emploient. *Une règle qui viserait `.docf-section-tete` ici
   ne s'appliquerait à rien, en silence.*

   ⚠️ AUCUNE COULEUR EN DUR : tokens `:root` uniquement (règle ① des gabarits).
   ===================================================================================== */

.tarifdoc-attente[b-qaf99gwpkj] {
    color: var(--slate);
    padding: 18px 0;
}

/* ---------------------------------------------------------------------------------------
   ⭐ LA GRILLE — CE QUE LA FORME B ACHÈTE, ET SA SEULE RAISON D'ÊTRE :
   les quatre sections coexistent au lieu d'être empilées dans une fenêtre. C'est ce qui
   rend « Pour qui » VISIBLE pendant qu'on travaille sur les produits — l'affectation
   manquante de DESIGN-2 vivait au bas d'une étape qu'on ne regardait pas.
   ⚠️ `align-items: start` : sans lui, une carte courte s'étirerait à la hauteur de la plus
   haute, et son fond blanc dessinerait un vide que rien ne remplit.
   --------------------------------------------------------------------------------------- */
/* ⭐⭐ GRIEF ② — UNE SEULE COLONNE, ET C'EST LA MAQUETTE QUI LE DIT :
   `.col{display:flex;flex-direction:column;gap:16px}`. DESIGN-3 avait choisi DEUX colonnes
   pour faire coexister quatre sections ; la maquette empile, et la relecture vit dans le
   rail de droite. ⚠️ La cinquième section (« Période ») n'a donc plus à être placée : un
   `grid-column` en dur l'aurait envoyée ailleurs EN SILENCE, ce que l'ancienne note disait
   déjà. */
.tarifdoc-grille[b-qaf99gwpkj] {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* ⚠️ `.tarifdoc-large` ne place plus rien : la classe reste sur les deux sections qui la
   portaient pour ne pas toucher leur markup, mais elle n'a plus d'effet de grille. */
.tarifdoc-large[b-qaf99gwpkj] {
    min-width: 0;
}

.tarifdoc-corps[b-qaf99gwpkj] {
    padding: 0 16px 14px;
}

/* ---- Champs ------------------------------------------------------------------------- */
.tarifdoc-champs[b-qaf99gwpkj] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 11px;
}

.tarifdoc-champ[b-qaf99gwpkj] {
    display: block;
    min-width: 0;
}

.tarifdoc-champ > span[b-qaf99gwpkj] {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--slate);
    margin-bottom: 3px;
}

.tarifdoc-champ--large[b-qaf99gwpkj] {
    grid-column: 1 / -1;
}

.tarifdoc-champ--case[b-qaf99gwpkj] {
    display: flex;
    align-items: center;
    gap: 8px;
    align-self: end;
    padding-bottom: 8px;
}

.tarifdoc-champ--case > span[b-qaf99gwpkj] {
    margin: 0;
    color: var(--ink);
    font-size: 14px;
}

.tarifdoc-ligne[b-qaf99gwpkj] {
    display: flex;
    flex-wrap: wrap;
    gap: 9px;
    align-items: flex-end;
    margin-top: 11px;
}

.tarifdoc-ligne .tarifdoc-champ[b-qaf99gwpkj] {
    flex: 1 1 180px;
}

/* ⚠️ Le bouton s'aligne sur le BAS des champs, jamais sur leur milieu : un bouton flottant
   au centre d'une ligne de champs se lit comme s'il appartenait à autre chose. */
.tarifdoc-ajouter[b-qaf99gwpkj] {
    flex: 0 0 auto;
    align-self: flex-end;
}

.tarifdoc-note[b-qaf99gwpkj] {
    margin: 11px 0 0;
    padding: 9px 11px;
    background: var(--amber-soft);
    border: 1px solid var(--line);
    border-radius: var(--r-10);
    color: var(--amber-dark);   /* 4,78 sur --amber-soft — AA */
    font-size: 12px;
    line-height: 1.45;
}

.tarifdoc-note--large[b-qaf99gwpkj] {
    grid-column: 1 / -1;
}

/* ---- L'ÉTAT VIDE — LE PORTEUR QUI DIT LE MANQUE **AVANT** TOUTE TENTATIVE ------------
   ⚠️⚠️ Il ne fait PAS double emploi avec le refus de la barre, et la distinction compte :
   le refus est la réponse à un GESTE (« Enregistrer »), l'état vide est un CONSTAT permanent.
   Deux états, deux porteurs — c'est la règle du dépôt, et c'est ce qui permet à la barre de
   se taire tant que personne n'a rien demandé. */
.tarifdoc-vide[b-qaf99gwpkj] {
    margin: 11px 0 0;
    padding: 11px 13px;
    border: 1px dashed var(--line);
    border-radius: var(--r-10);
    background: var(--surface-alt);
    color: var(--slate);        /* 5,29 sur --surface-alt — AA */
    font-size: 12px;
}

/* ---- LE RACCOURCI D'ÉCRAN (deux boutons, quatre portées derrière) -------------------- */
/* ---- LES PASTILLES — un objet manipulable, pas un inventaire ------------------------- */
.tarifdoc-pastilles[b-qaf99gwpkj] {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    margin-top: 11px;
}

.tarifdoc-pastille[b-qaf99gwpkj] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 6px 5px 11px;
    border-radius: 999px;
    background: var(--brand-softer);
    border: 1px solid var(--brand-soft);
    color: var(--brand-dark);   /* 7,74 sur --brand-softer — AAA */
    font-size: 12px;
    font-weight: 600;
    min-height: 32px;
}

.tarifdoc-pastille--large[b-qaf99gwpkj] {
    background: var(--blue-soft);
    border-color: var(--blue-soft);
    color: var(--blue-dark);    /* 4,65 sur --blue-soft — AA */
}

.tarifdoc-x[b-qaf99gwpkj] {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    font-size: 13px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.tarifdoc-x:hover[b-qaf99gwpkj] {
    background: var(--line-soft);
}

.tarifdoc-compte[b-qaf99gwpkj] {
    font-size: 12px;
    color: var(--slate);
    align-self: center;
}

/* ---- LES TABLEAUX : DES COLONNES QUI NE SE TOUCHENT PAS -----------------------------
   ⚠️⚠️ MESURÉ SUR L'ÉCRAN D'AVANT, ET C'EST LE DÉFAUT QUE WALID A VU : les cellules du
   tableau de choix rendaient `padding: 1px` — c'est-à-dire le DÉFAUT DU NAVIGATEUR, aucune
   règle ne les atteignait — et `border-spacing: 2px`. Les quatre colonnes se touchaient.
   ⭐ La règle est posée ICI, sur une classe à nous, plutôt que corrigée dans `.crud-list` :
   cette table-là vivait dans une modale et n'était pas atteinte ; toucher la règle globale
   changerait les 80 écrans qui portent une collection pour réparer celui-ci.
   ⚠️ Les en-têtes sont PEINTS : sans fond, une ligne d'intitulés se lit comme une rangée. */
.tarifdoc-tbl[b-qaf99gwpkj] {
    border-collapse: collapse;
    width: 100%;
    margin-top: 11px;
}

.tarifdoc-tbl th[b-qaf99gwpkj] {
    padding: 9px 12px;
    background: var(--surface-alt);
    border-bottom: 1px solid var(--line);
    color: var(--slate);        /* 5,29 sur --surface-alt — AA */
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    text-align: left;
    white-space: nowrap;
}

.tarifdoc-tbl td[b-qaf99gwpkj] {
    padding: 9px 12px;
    border-bottom: 1px solid var(--line-soft);
    vertical-align: middle;
}

.tarifdoc-tbl tbody tr:last-child td[b-qaf99gwpkj] {
    border-bottom: 0;
}

/* ---- LES PALIERS : la valeur ET son unité ------------------------------------------- */
.tarifdoc-avecunite[b-qaf99gwpkj] {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

.tarifdoc-avecunite .form-control[b-qaf99gwpkj] {
    max-width: 140px;
}

.tarifdoc-unite[b-qaf99gwpkj] {
    color: var(--slate);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}

/* ---- LA BARRE D'ACTIONS — **COLLÉE EN HAUT** (grief ④) -------------------------------
   Relevé dans la maquette : `.topbar{position:sticky;top:0;z-index:40;border-bottom:…}`.
   ⚠️⚠️ `position: sticky` MEURT EN SILENCE si un ancêtre porte `overflow` autre que
   `visible` — c'est la famille « une règle présente, servie et SANS EFFET ». Aucune lecture
   de source ne peut le dire : seul `t164/G1` le mesure, au navigateur, après un défilement
   réel.
   ⚠️⚠️ `z-index` — LA MAQUETTE DISAIT 40, ET LE MOTIF ÉCRIT ICI ÉTAIT FAUX : « elle reste
   SOUS la navigation (50) ». **MESURÉ en DESIGN-8 : la navigation qui compte en haut d'un
   écran de BUREAU est `.app-topbar`, et elle vaut 5** — le 50 est celui de la barre
   d'onglets MOBILE, un autre objet. À 40, cette barre passait donc AU-DESSUS du menu.
   ⭐ Ça ne se VOYAIT pas : collée à `top: 64px`, elle ne recouvre géométriquement rien.
   *Une valeur juste sous un motif faux passe toutes les gardes* — et c'est `GB12`, qui
   confronte les TROIS porteurs à un contrat unique, qui l'a nommée.
   ⇒ **4**, comme `.doc-header` et `.art-hd` : sous le menu (5), au-dessus de l'en-tête de
   colonnes (1). Rien du périmètre tarif ne vit entre 4 et 40 — le panneau du sélecteur est
   à 1000, les voiles de modale à 1050/1060, tous au-dessus. */
.tarifdoc-barre[b-qaf99gwpkj] {
    position: sticky;
    /* ⚠️⚠️ ÉCART ③ — `top: 0` LA COLLAIT PAR-DESSUS LE MENU DE L'APPLICATION : on lisait
       « PRO / Accueil » à gauche et « Administrateur » à droite, derrière elle. La barre de
       l'application fait **64 px**, et c'est la convention ÉCRITE du dépôt (« le `top` collant
       vaut 64 px, hauteur de la navbar ») — on la CITE, on ne la redécouvre pas. */
    top: 64px;
    z-index: 4;
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 14px;
    padding: 12px 16px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-14);
}

.tarifdoc-refus[b-qaf99gwpkj] {
    flex: 1;
    min-width: 0;
    margin: 0;
    text-align: left;
    font-size: 13px;
}

.tarifdoc-refus ul[b-qaf99gwpkj] {
    margin: 5px 0 0;
    padding-left: 17px;
}

.tarifdoc-refus li + li[b-qaf99gwpkj] {
    margin-top: 3px;
}

.tarifdoc-aller[b-qaf99gwpkj] {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-weight: 700;
    color: inherit;
    text-decoration: underline;
    cursor: pointer;
}

.tarifdoc-barre-btns[b-qaf99gwpkj] {
    display: flex;
    justify-content: flex-end;
    gap: 9px;
    margin-left: auto;
}

/* =====================================================================================
   ≤ 768 px — UNE COLONNE, LA BARRE COLLÉE, ET LA RÉSERVE DE FIN DE PAGE.
   ⭐ Les sections se replient : c'est `SectionsRepliables` + `DocTeteCarte`, exactement
   comme les onze documents. Aucun second markup n'est écrit — la même section est empilée.
   ===================================================================================== */
@media (max-width: 768px) {
    .tarifdoc-grille[b-qaf99gwpkj] {
        grid-template-columns: 1fr;
        gap: 8px;
    }

    /* ⚠️ Le placement en colonne 2 n'a plus de sens sur une colonne unique, et le laisser
       enverrait la carte dans une piste qui n'existe pas. */
    .tarifdoc-large[b-qaf99gwpkj],
    .tarifdoc-grille > .doc-card:not(.tarifdoc-large)[b-qaf99gwpkj] {
        grid-column: 1;
    }

    .tarifdoc-corps[b-qaf99gwpkj] {
        padding: 0 14px 12px;
    }

    .tarifdoc-champs[b-qaf99gwpkj] {
        grid-template-columns: 1fr;
        gap: 9px;
    }

    .tarifdoc-ligne .tarifdoc-champ[b-qaf99gwpkj] {
        flex: 1 1 100%;
    }

    .tarifdoc-ajouter[b-qaf99gwpkj] {
        width: 100%;
    }

    .tarifdoc-avecunite .form-control[b-qaf99gwpkj] {
        max-width: none;
    }

    /* ---- LA BARRE D'ACTIONS RESTE COLLÉE **EN HAUT** EN MOBILE AUSSI -----------------
       ⚠️⚠️ CE QUI VIVAIT ICI : `position: fixed; bottom: calc(var(--navmob-h) + …)`, la barre
       FIXE EN BAS de MOBILE-4b. Elle part avec le grief ④ — Walid la veut EN HAUT — et son
       départ ferme du même coup le recouvrement que MOBILE-4b avait dû réserver : *il n'y a
       plus rien qui flotte au bas de cet écran, sauf la navigation*.
       ⭐ UNE SEULE barre à toutes les largeurs : la maquette en met une seconde, fixe en bas,
       sous 880 px. Deux jeux de boutons porteraient le MÊME `data-testid`, et un parcours
       cliquerait celui qui est masqué — *un porteur par largeur, jamais deux*. */
    .tarifdoc-barre[b-qaf99gwpkj] {
        flex-direction: column;
        align-items: stretch;
        gap: 9px;
        padding: 10px 14px;
        margin-bottom: 10px;
    }

    .tarifdoc-barre-btns[b-qaf99gwpkj] {
        margin-left: 0;
    }

    .tarifdoc-barre-btns .btn[b-qaf99gwpkj] {
        flex: 1;
        min-height: 48px;
    }

    /* ⚠️ Le refus peut être long : on le borne, sinon il chasse les boutons hors de l'écran
       — et le geste qu'il demande deviendrait inatteignable. */
    .tarifdoc-refus[b-qaf99gwpkj] {
        font-size: 12px;
        max-height: 34vh;
        overflow-y: auto;
    }

    /* ⭐⭐ LA RÉSERVE DE FIN DE PAGE — ELLE RESTE, ET SON TERME `+ 56px` PART AVEC LA BARRE.
       ⚠️⚠️ Elle ne réservait pas pour UNE chose mais pour DEUX : la navigation basse (61 px,
       fixe, TOUJOURS là) et la barre d'action (56 px, qui vient de monter en haut). Retirer
       la réserve ENTIÈRE aurait laissé la dernière commande sous la navigation — le défaut
       MOBILE-4b, repris par l'autre bout. On retire le terme de la barre, PAS celui de la
       navigation, et les deux restent CITÉS pour qu'on voie ce qu'on réserve. */
    .tarifdoc[b-qaf99gwpkj] {
        padding-bottom: calc(1.1rem + var(--navmob-h) + env(safe-area-inset-bottom, 0px));
    }
}

/* ⚠️ Les cibles bornées par le POINTEUR, jamais par la largeur : un écran tactile n'a pas
   de survol, et c'est `hover: none` qui le dit. Une fenêtre réduite à 390 px reste pilotée
   à la souris — lui imposer 44 px gâcherait la place sans rien gagner. */
@media (hover: none) {
    .tarifdoc-x[b-qaf99gwpkj] {
        width: 40px;
        height: 40px;
    }

    .tarifdoc-aller[b-qaf99gwpkj] {
        display: inline-block;
        min-height: 40px;
        line-height: 40px;
    }
}


/* =====================================================================================
   DESIGN-4 — LA MAQUETTE `docs/maquettes/digistorm_editeur_tarif.html`, PARTIE VISUELLE.

   ⚠️ TOKENS `:root` UNIQUEMENT, et chaque accent coloré pose SON FOND avec sa couleur :
   la « zone aveugle du contraste » du dépôt compte 539 règles qui posent l'un sans l'autre,
   et on n'en ajoute pas.

   ⚠️ PIÈGE #9 — rien ici ne vise `DocTeteCarte` ni `.docf-section-resume` : ce sont des
   composants ENFANTS, leur markup ne porte pas le scope de cet écran, et une règle qui les
   viserait ne s'appliquerait à RIEN, en silence. C'est pourquoi la « pastille de compteur »
   de la maquette n'est pas dessinée ici — voir le commentaire de `ResumePourQui`.
   ===================================================================================== */

/* ---- R1 : l'état « modifié », annoncé dans l'en-tête de page ------------------------- */
.tarifdoc-modifie[b-qaf99gwpkj] {
    display: inline-flex;
    align-items: center;
    height: 26px;
    padding: 0 10px;
    border-radius: var(--r-6);
    background: var(--clay-soft);
    color: var(--clay-dark);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}

/* ---- R10 : deux colonnes — le formulaire, et la relecture --------------------------- */
/* ⭐ GRIEF ② — LES VALEURS SONT CELLES DE LA MAQUETTE :
   `.grid{grid-template-columns:minmax(0,1fr) 340px;gap:20px}` et son point de bascule à
   880 px (le dépôt bornait à 1180, et le rail à 320). */
.tarifdoc-colonnes[b-qaf99gwpkj] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 20px;
    align-items: start;
}

/* ⭐ La colonne de relecture SUIT le défilement : une règle se relit pendant qu'on la saisit,
   pas seulement quand on arrive au bas de la page. */
.tarifdoc-aside[b-qaf99gwpkj] {
    position: sticky;
    top: 78px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

/* ⚠️ 1180 px, et non 768 : au-dessous, les deux colonnes du formulaire ET la colonne de
   relecture ne tiennent plus côte à côte — la relecture passe sous le formulaire bien avant
   que l'écran ne devienne un téléphone. */
@media (max-width: 880px) {
    .tarifdoc-colonnes[b-qaf99gwpkj] {
        grid-template-columns: 1fr;
    }

    /* ⚠️⚠️ `position: sticky` + une hauteur pensée pour un layout EN LIGNE recouvre le contenu
       une fois EMPILÉ, de façon invisible sur une capture (piège #13, payé par `.app-sidebar`).
       On la neutralise dans le même media query que l'empilement. */
    .tarifdoc-aside[b-qaf99gwpkj] {
        position: static;
        top: auto;
    }
}

/* ---- R2 : la phrase, et la liste de contrôle ---------------------------------------- */
.tarifdoc-resume[b-qaf99gwpkj] {
    background: var(--brand-softer);
    border-color: var(--brand-soft);
}

.tarifdoc-resume-corps[b-qaf99gwpkj] {
    padding: 14px 16px;
}

.tarifdoc-resume-titre[b-qaf99gwpkj] {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--brand-dark);
    background: transparent;
}

.tarifdoc-phrase[b-qaf99gwpkj] {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink);
}

.tarifdoc-controles[b-qaf99gwpkj] {
    margin-top: 12px;
    padding-top: 11px;
    border-top: 1px solid var(--brand-soft);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.tarifdoc-controle[b-qaf99gwpkj] {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12.5px;
    color: var(--ink-soft);
}

/* ⚠️ Le marqueur porte SA COULEUR ET SON FOND : un ✓ vert sans fond sur une carte teintée
   n'a pas le même contraste qu'il aurait sur du blanc, et rien ne le dirait. */
.tarifdoc-mk[b-qaf99gwpkj] {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    display: inline-grid;
    place-items: center;
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 700;
    background: var(--green-soft);
    color: var(--green-dark);
}

.tarifdoc-mk--ko[b-qaf99gwpkj] {
    background: var(--red-soft);
    color: var(--red-dark);
}

/* ---- La carte « État » -------------------------------------------------------------- */
.tarifdoc-etat[b-qaf99gwpkj] {
    padding-top: 4px;
}

.tarifdoc-kv[b-qaf99gwpkj] {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    font-size: 13px;
    border-bottom: 1px solid var(--line-soft);
}

.tarifdoc-kv:last-child[b-qaf99gwpkj] {
    border-bottom: 0;
}

.tarifdoc-kv > span[b-qaf99gwpkj] {
    color: var(--slate);
    background: transparent;
}

.tarifdoc-kv > b[b-qaf99gwpkj] {
    font-weight: 600;
    text-align: right;
    min-width: 0;
    color: var(--ink);
}

/* ---- R11 : « Cibles retenues » + « Tout retirer » ----------------------------------- */
.tarifdoc-cibles-tete[b-qaf99gwpkj] {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 14px;
    padding-top: 11px;
    border-top: 1px solid var(--line-soft);
}

.tarifdoc-cibles-tete b[b-qaf99gwpkj] {
    flex: 1;
    font-size: 12px;
    font-weight: 600;
    color: var(--slate);
}

.tarifdoc-lien[b-qaf99gwpkj] {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--red-dark);
    text-decoration: underline;
    cursor: pointer;
}

/* ---- R15 : la cible, et l'effet de la règle sur elle -------------------------------- */
.tarifdoc-cible-nom[b-qaf99gwpkj] {
    display: block;
    font-weight: 600;
}

.tarifdoc-cible-ref[b-qaf99gwpkj] {
    display: block;
    font-size: 11px;
    color: var(--slate);
    margin-top: 2px;
}

.tarifdoc-effet[b-qaf99gwpkj] {
    display: block;
    font-size: 12.5px;
    font-weight: 600;
}

.tarifdoc-effet--prix[b-qaf99gwpkj] {
    color: var(--brand);
    font-variant-numeric: tabular-nums;
}

.tarifdoc-effet--prix s[b-qaf99gwpkj] {
    color: var(--slate);
    font-weight: 500;
    margin-right: 5px;
}

.tarifdoc-effet--offert[b-qaf99gwpkj] {
    color: var(--clay-dark);
}

/* ⚠️ Une portée non dépliée n'est pas un chiffre absent : elle le DIT, en secondaire. */
.tarifdoc-effet--portee[b-qaf99gwpkj] {
    color: var(--slate);
    font-weight: 500;
    font-style: italic;
}

/* ⭐⭐ LE SEUIL S'ÉCRIT À CÔTÉ DU RÉSULTAT — décision de Walid, 2026-09-11. Jamais une
   quantité implicite : « 33,00 DH » seul se lirait comme un prix, alors que c'est un prix
   À PARTIR DE 10. */
.tarifdoc-effet-seuil[b-qaf99gwpkj] {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    color: var(--slate);
    font-variant-numeric: tabular-nums;
}

/* ---- R7 : le palier relu en clair, sous ses champs ---------------------------------- */
.tarifdoc-palrecap-ligne td[b-qaf99gwpkj] {
    padding-top: 0;
    border-top: 0;
}

.tarifdoc-palrecap[b-qaf99gwpkj] {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--brand-dark);
}

/* Une note d'explication, sans l'alerte : le fond d'alerte est réservé aux avertissements
   métier (portée non dépliée, unité des seuils), et le banaliser les éteindrait. */
.tarifdoc-note--sobre[b-qaf99gwpkj] {
    background: var(--surface-alt);
    color: var(--slate);
    border-color: var(--line-soft);
}

@media (max-width: 768px) {
    .tarifdoc-colonnes[b-qaf99gwpkj] {
        gap: 8px;
    }

    .tarifdoc-resume-corps[b-qaf99gwpkj] {
        padding: 12px 14px;
    }

    /* ⚠️ Le lien « Tout retirer » est une CIBLE : bornée par le POINTEUR plus bas, pas ici. */
    .tarifdoc-cibles-tete[b-qaf99gwpkj] {
        margin-top: 12px;
    }
}

/* ⚠️ Les cibles bornées par le POINTEUR, jamais par la largeur (mesuré `hover: none`) : un
   écran tactile n'a pas de survol, et une fenêtre réduite à 390 px reste pilotée à la souris. */
@media (hover: none) {
    .tarifdoc-lien[b-qaf99gwpkj] {
        display: inline-block;
        min-height: 40px;
        line-height: 40px;
    }
}


/* =====================================================================================
   DESIGN-5 — L'ÉCHELLE TYPOGRAPHIQUE DE LA MAQUETTE (grief ③).

   ⚠️ RELEVÉE DANS LE HTML, PAS INTERPRÉTÉE. Chaque règle porte la valeur d'origine.
   ⚠️⚠️ UNE SUBSTITUTION DE JETON EST FAITE ET ELLE SE DIT : la maquette pose ses libellés
   en `--txt-3` = **#9CA3AF**, qui rend **2,54:1 sur `--surface`** — SOUS AA (4,50). On emploie
   `--slate`. *Un écart non reprenable se DIT ; il ne se contourne pas en silence.*
   ⚠️⚠️ ET CE CHIFFRE A ÉTÉ FAUX ICI MÊME : j'avais écrit « 2,58 », calculé à la main. `TF5` le
   RECALCULE depuis le `:root` à chaque run et rend **2,54** — *un chiffre calculé une fois ne
   garde rien, et il devient faux sans que personne ne le refasse.* Ne réécrivez pas ces
   valeurs ici : la garde est la source.
   ⚠️ Le « plancher 11 px » n'a pas été trouvé : mesuré, `app.css` porte 136 sites en
   10–11 px et AUCUNE garde n'impose de minimum. Les 10 px de la maquette sont donc rendus.
   ===================================================================================== */

/* .field label{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase} */
.tarifdoc-champ > span[b-qaf99gwpkj] {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--slate);
    margin-bottom: 6px;
}

/* .field label .opt{text-transform:none;letter-spacing:0;font-weight:500} */
.tarifdoc-opt[b-qaf99gwpkj] {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
}

/* .hintline{font-size:11.5px;color:var(--txt-3)} */
.tarifdoc-hintline[b-qaf99gwpkj] {
    font-size: 11.5px;
    color: var(--slate);
    margin: 6px 0 0;
}

.tarifdoc-hintline b[b-qaf99gwpkj] {
    color: var(--ink-soft);
    font-weight: 600;
}

/* .cbody{padding:16px} */
.tarifdoc-corps[b-qaf99gwpkj] {
    padding: 16px;
}

/* .switch — l'interrupteur « Règle active », dernier contrôle du bloc, sous un filet. */
.tarifdoc-bascule-actif[b-qaf99gwpkj] {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--line-soft);
}

.tarifdoc-bascule-actif-txt[b-qaf99gwpkj] {
    flex: 1;
    min-width: 0;
}

/* .switch .sl b{font-size:14px;font-weight:600} */
.tarifdoc-bascule-actif-txt > b[b-qaf99gwpkj] {
    display: block;
    font-size: 14px;
    font-weight: 600;
    color: var(--ink);
}

/* .switch .sl span{font-size:11.5px;color:var(--txt-3)} */
.tarifdoc-bascule-actif-txt > span[b-qaf99gwpkj] {
    display: block;
    font-size: 11.5px;
    color: var(--slate);
    margin-top: 2px;
}

.tarifdoc-bascule-actif input[b-qaf99gwpkj] {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    accent-color: var(--brand);
}

/* ⭐ GRIEF ① — le sélecteur PARTAGÉ, présenté comme un champ de l'écran. */
.tarifdoc-picker[b-qaf99gwpkj] {
    margin-top: 12px;
}

.tarifdoc-picker-lbl[b-qaf99gwpkj] {
    display: block;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--slate);
    margin-bottom: 6px;
}

/* .resume .lbl{font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase} */
.tarifdoc-resume-titre[b-qaf99gwpkj] {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

/* .phrase{font-size:15px;line-height:1.6} */
.tarifdoc-phrase[b-qaf99gwpkj] {
    font-size: 15px;
    line-height: 1.6;
}

.tarifdoc-phrase b[b-qaf99gwpkj] {
    font-weight: 700;
}

/* .check div{font-size:12.5px} */
.tarifdoc-controle[b-qaf99gwpkj] {
    font-size: 12.5px;
}

/* .kv{font-size:13px} · .kv b{font-weight:600} */
.tarifdoc-kv[b-qaf99gwpkj] {
    font-size: 13px;
    padding: 10px 0;
}

/* .tbl th{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase} */
.tarifdoc-tbl thead th[b-qaf99gwpkj] {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--slate);
}

/* .tbl td{font-size:13.5px} · .tbl .desg{font-weight:600} */
.tarifdoc-tbl tbody td[b-qaf99gwpkj] {
    font-size: 13.5px;
}

.tarifdoc-cible-nom[b-qaf99gwpkj] {
    font-size: 13.5px;
    font-weight: 600;
}

/* .palrecap{font-size:12px;color:var(--succes-t);font-weight:600} */
.tarifdoc-palrecap[b-qaf99gwpkj] {
    font-size: 12px;
    font-weight: 600;
}

/* .btn{height:44px;font-size:14px;font-weight:600;border-radius:var(--r-md)=12px} */
.tarifdoc-barre-btns .btn[b-qaf99gwpkj] {
    min-height: 44px;
    padding: 0 18px;
    font-size: 14px;
    font-weight: 600;
    border-radius: var(--r-12);
}


/* =====================================================================================
   DESIGN-6 — LE RESTE DES SIX ÉCARTS, VALEURS RELEVÉES DANS LE HTML DE LA MAQUETTE.
   ===================================================================================== */

/* ── ③ La tête dans la barre : une seule ligne, comme `.topin` de la maquette ───────── */
.tarifdoc-tete[b-qaf99gwpkj] {
    margin-bottom: 0;
    flex-wrap: nowrap;
    gap: 12px;
    align-items: center;
}

/* ⚠️ Le refus se détache de la ligne de titre : sans ce filet, les deux se touchent et l'on
   ne voit plus où finit l'en-tête. */
.tarifdoc-barre .tarifdoc-refus[b-qaf99gwpkj] {
    margin-top: 10px;
}

.tarifdoc-barre[b-qaf99gwpkj] {
    flex-direction: column;
    align-items: stretch;
}

/* ── ⑥ LES ONGLETS — `.seg` de la maquette : une PISTE grise, un onglet BLANC à texte vert.
   Relevé : `.seg{gap:3px;padding:3px;background:var(--surface-2);border:1px solid var(--trait);
   border-radius:var(--r-md);height:44px}` et
   `.seg button[aria-pressed=true]{background:#fff;color:var(--vert);box-shadow:0 1px 3px …}`.
   ⚠️ L'écran rendait l'onglet actif en PASTILLE VERTE PLEINE (`btn-nouveau`) : le contraire. */
.tarifdoc-bascule[b-qaf99gwpkj] {
    display: flex;
    gap: 3px;
    padding: 3px;
    height: 44px;
    background: var(--surface-alt);
    border: 1px solid var(--line);
    border-radius: var(--r-12);
    margin-top: 4px;
    flex-wrap: nowrap;
}

.tarifdoc-bascule-btn[b-qaf99gwpkj] {
    flex: 1;
    min-width: 0;
    border: 0;
    background: transparent;
    border-radius: var(--r-9);
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ink-soft);
    box-shadow: none;
    padding: 0 10px;
}

.tarifdoc-bascule-btn[aria-checked="true"][b-qaf99gwpkj] {
    background: var(--surface);
    color: var(--brand);
    box-shadow: var(--sh-sm);
}

/* ── ⑤ Le compteur : casse normale, et la pastille de DESIGN-5 conservée ───────────── */
.tarifdoc-compte[b-qaf99gwpkj] {
    text-transform: none;
    letter-spacing: normal;
}

/* ── ① Le sélecteur : il porte `.docv2`, donc son panneau est habillé par `doc-v2.css`.
   ⚠️ RIEN N'EST ÉCRIT ICI POUR LUI — et c'est le point : l'habillage existait déjà, il lui
   manquait son ancêtre. On borne seulement la LARGEUR du conteneur, qui est à nous. ───── */
.tarifdoc-picker[b-qaf99gwpkj] {
    position: relative;
    max-width: 520px;
}

/* ── ⑦ Le prix barré et le prix retenu gardent leurs chiffres alignés quelle que soit la
   base : `tabular-nums` est déjà posé par `.tarifdoc-effet--prix`. ─────────────────── */

@media (max-width: 768px) {
    /* ⚠️ Sous 768, la barre de l'application n'est plus la même : la navigation est EN BAS
       (`--navmob-h`) et l'en-tête mobile ne fait pas 64 px. On recolle en haut d'écran. */
    .tarifdoc-barre[b-qaf99gwpkj] {
        top: 0;
    }

    .tarifdoc-tete[b-qaf99gwpkj] {
        flex-wrap: wrap;
    }

    .tarifdoc-picker[b-qaf99gwpkj] {
        max-width: none;
    }
}
/* /Components/Shared/ClientPicker.razor.rz.scp.css */
/* ClientPicker — STRUCTURE seule (position). Les couleurs/skin docv2 vivent dans doc-v2.css
   sous .docv2 .cp-* (mêmes classes, non redéfinies ici → pas de conflit de spécificité). */
.cp-wrap[b-fm0uq4dtn2] {
    position: relative;
}

.cp-panel[b-fm0uq4dtn2] {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 5px;
    z-index: 30;
    max-height: 300px;
    overflow-y: auto;
}
/* /Components/Shared/EnvoyerCourriel.razor.rz.scp.css */
/* ENVOI-MAIL — le bouton Email et sa fenêtre. CSS SCOPED (borné à ce composant) : aucun
   sélecteur partagé n'est stylé — la leçon T-UI, payée deux fois. */

.mail-btn[b-c8h6rklpw1] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.mail-confirmation[b-c8h6rklpw1] {
    font-size: 12px;
    color: var(--teal-dark);
    margin-left: 6px;
    white-space: nowrap;
}

.mail-form[b-c8h6rklpw1] {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: min(520px, 90vw);
}

.mail-form[b-c8h6rklpw1]  textarea {
    resize: vertical;
    font-family: inherit;
    /* ⚠️⚠️ POURQUOI UNE HAUTEUR MINIMALE, ET POURQUOI rows="8" NE SUFFIT PAS.
       MESURÉ : le champ se rend à 31 px — UNE ligne — quel que soit le texte. `rows` exprime une
       hauteur PRÉFÉRÉE ; dans un conteneur `flex-direction: column`, le `flex-shrink: 1` par
       défaut laisse l'élément se comprimer jusqu'à son `min-height`, et Bootstrap pose
       `textarea.form-control-sm { min-height: calc(1.5em + .5rem + 2px) }` — soit UNE ligne.
       C'est donc le MIN qui décide, pas `rows`.
       ⚠️ Ne pas « corriger » en retirant form-control-sm (l'écran perdrait sa densité) ni en
       posant une hauteur FIXE : `resize: vertical` ne servirait plus à rien. Un MIN laisse
       l'agrandissement au poignet de l'utilisateur.
       ⚠️ Aucun sélecteur neuf : la règle EXISTAIT, elle est bornée par .mail-form (un ancêtre),
       jamais par la balise nue — un préfixe protège les classes, pas les balises. */
    min-height: 100px;
}

.mail-hint[b-c8h6rklpw1] {
    font-size: 12px;
    color: var(--slate);
    line-height: 1.45;
    margin: 0;
}

.mail-erreur[b-c8h6rklpw1] {
    font-size: 12.5px;
    color: var(--red);
    background: var(--red-soft);
    border-radius: var(--r-8);
    padding: 8px 10px;
    line-height: 1.45;
    margin: 0;
}
/* /Components/Shared/EnvoyerWhatsApp.razor.rz.scp.css */
/* ENVOI-WA — CSS SCOPÉ au composant (donc borné par construction : le scope attribute b-xxx ne
   sort pas d'ici — un préfixe protège les classes, le scoping protège même les balises).
   Aucune règle sur un conteneur partagé : la leçon T-UI (.btn-filtres puis .crud-toolbar-actions
   stylés ont cassé deux fois des écrans que la tranche ne touchait pas) reste payée. */

.wa-btn[b-fy6wc9mnfd] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    text-decoration: none;
}

.wa-wrap[b-fy6wc9mnfd] {
    position: relative;
    display: inline-flex;
}

/* Le message de refus (décision 3) : posé SOUS le bouton, détaché du flux pour ne pas déformer
   la rangée d'actions de l'en-tête. Ambre = information qui appelle un geste, pas une erreur. */
.wa-note[b-fy6wc9mnfd] {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 30;
    width: 340px;
    max-width: 82vw;
    padding: 10px 12px;
    border: 1px solid var(--amber);
    border-radius: var(--r-10);
    background: var(--amber-soft);
    color: var(--ink);
    font-size: 12.5px;
    line-height: 1.45;
    text-align: left;
    box-shadow: 0 8px 22px rgba(15, 23, 42, .12);
}

/* ══ T-FICHEDOC-l — LA FENÊTRE DE CONFIRMATION ══════════════════════════════════════════
   Le geste est en DEUX TEMPS depuis que le message porte un lien public : un lien anonyme
   naît du geste, il ne doit donc pas naître du simple affichage d'une fiche. */

.wa-dest[b-fy6wc9mnfd] {
    font-size: 14px;
    line-height: 1.5;
    color: var(--ink);
}

/* ⚠️ Le message EXACT qui partira, jamais un résumé : l'utilisateur doit reconnaître ce qu'il
   envoie. `pre` conserve les sauts de ligne du message — et `white-space: pre-wrap` évite
   qu'une URL longue déborde de la fenêtre au lieu de se replier. */
.wa-apercu[b-fy6wc9mnfd] {
    margin: 0;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-10);
    background: var(--paper);
    color: var(--ink);
    font-family: inherit;
    font-size: 13px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ⚠️⚠️ LE TON EST CELUI D'UNE INFORMATION, PAS D'UNE ALERTE — décision de Walid : le lien
   anonyme n'est pas un danger, c'est le fonctionnement. D'où `--slate` sur le fond de la
   fenêtre, et NON l'ambre de `.wa-note` (qui, lui, appelle un geste : saisir un numéro).
   ⭐ Deux tons pour deux natures : *un ton d'alerte sur un fonctionnement normal apprend à
   ignorer les alertes*. */
.wa-avis[b-fy6wc9mnfd] {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--slate);
}

/* ⚠️⚠️ DANS UNE FEUILLE, LE CONTENEUR PREND TOUTE LA LARGEUR — sans quoi la note, ancrée sur
   lui par `right: 0`, part vers la GAUCHE et sort de l'écran : mesuré à x = −208,2 px en
   390 px, texte entier mais invisible. C'est la note d'un bouton d'EN-TÊTE reprise dans une
   FEUILLE, et *un patron repris tel quel n'est juste que dans les conditions où il a été
   écrit*. Avec le conteneur pleine largeur, `right: 0` la ramène dans l'écran.
   ⚠️ Elle reste HORS FLUX : elle ne pousse aucune entrée de la feuille (mesuré — les 7
   entrées sont identiques avant et après le tap, et « E-mail » reste visible). Elle les
   RECOUVRE, ce qui est le comportement voulu d'un message qui répond à un tap. */
.wa-wrap--large[b-fy6wc9mnfd] {
    display: flex;
    width: 100%;
}
/* /Components/Shared/FichiersJoints.razor.rz.scp.css */
.fj-wrap[b-qe2nahd9ai] {
    /* ⚠️⚠️ H8-c — LE DEBORDEMENT QUE LA BARRE DU BAS A REVELE. Un item de flex porte
       `min-width: auto` par defaut : il refuse de retrecir sous la largeur de son contenu.
       Mesure a 390 px : ce bloc rendait 400 px dans un parent de 342 (302 utiles) sur le
       reglement de salaire — et le debordement etirait la barre du bas a 444 px, rendant
       le « ⋯ » NON CLIQUABLE. Sur le temoin il tenait deja a 300 px : la regle n'y change
       rien. *Un geste mort est pire qu'une absence.* */
    min-width: 0;
    max-width: 100%;
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.fj-empty[b-qe2nahd9ai] {
    margin: 0;
    color: var(--slate, #64748b);
    font-size: .9rem;
    font-style: italic;
}

.fj-list[b-qe2nahd9ai] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

.fj-item[b-qe2nahd9ai] {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .5rem .6rem;
    border: 1px solid var(--line, #e5e9f0);
    border-radius: var(--r-10);
    background: #fff;
}

.fj-thumb[b-qe2nahd9ai] {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: var(--r-8);
    border: 1px solid var(--line, #e5e9f0);
    background: var(--paper, #f4f6fa);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    padding: 0;
    cursor: pointer;
    color: var(--slate, #64748b);
}

.fj-thumb img[b-qe2nahd9ai] {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.fj-thumb-doc[b-qe2nahd9ai] {
    cursor: default;
    color: var(--red, #dc2626);
}

.fj-meta[b-qe2nahd9ai] {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.fj-nom[b-qe2nahd9ai] {
    font-weight: 600;
    font-size: .9rem;
    color: var(--ink, #0f172a);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.fj-nom:hover[b-qe2nahd9ai] { text-decoration: underline; }

.fj-sub[b-qe2nahd9ai] {
    font-size: .78rem;
    color: var(--slate, #64748b);
}

.fj-actions[b-qe2nahd9ai] {
    flex: 0 0 auto;
    display: flex;
    gap: .35rem;
}

.fj-btn[b-qe2nahd9ai] {
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-8);
    border: 1px solid var(--line, #e5e9f0);
    background: var(--paper, #f4f6fa);
    color: var(--slate, #475569);
    cursor: pointer;
    text-decoration: none;
}

.fj-btn:hover[b-qe2nahd9ai] { background: #e9edf4; }

.fj-btn-del:hover[b-qe2nahd9ai] {
    background: var(--red-soft, #fee2e2);
    color: var(--red, #dc2626);
    border-color: #fecaca;
}

.fj-upload[b-qe2nahd9ai] {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
}

.fj-add[b-qe2nahd9ai] {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .45rem .8rem;
    border-radius: var(--r-8);
    border: 1px dashed var(--teal, #14b8a6);
    color: var(--teal-dark, #0f766e);
    background: var(--teal-soft, #f0fdfa);
    font-size: .88rem;
    font-weight: 600;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}

.fj-add input[type="file"][b-qe2nahd9ai] {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    font-size: 0;
}

.fj-add-disabled[b-qe2nahd9ai] {
    opacity: .6;
    cursor: progress;
}

.fj-add-disabled input[type="file"][b-qe2nahd9ai] { cursor: progress; }

.fj-hint[b-qe2nahd9ai] {
    font-size: .78rem;
    color: var(--slate, #64748b);
}

.fj-erreurs[b-qe2nahd9ai] {
    list-style: none;
    margin: 0;
    padding: .5rem .7rem;
    border-radius: var(--r-8);
    background: var(--red-soft, #fee2e2);
    color: var(--red, #b91c1c);
    font-size: .84rem;
    display: flex;
    flex-direction: column;
    gap: .25rem;
}

.fj-apercu[b-qe2nahd9ai] {
    display: flex;
    justify-content: center;
    align-items: center;
    max-height: 70vh;
}

.fj-apercu img[b-qe2nahd9ai] {
    max-width: 100%;
    max-height: 70vh;
    object-fit: contain;
    border-radius: var(--r-8);
}

@media (max-width: 768px) {
    .fj-item[b-qe2nahd9ai] {
        flex-wrap: wrap;
    }

    .fj-meta[b-qe2nahd9ai] {
        flex: 1 1 60%;
    }

    .fj-btn[b-qe2nahd9ai] {
        width: 40px;
        height: 40px;
    }
}
/* /Components/Shared/FournisseurPicker.razor.rz.scp.css */
/* FournisseurPicker — STRUCTURE seule (position). Skin docv2 partagé via .docv2 .cp-* (doc-v2.css). */
.cp-wrap[b-mt97vprbwb] {
    position: relative;
}

.cp-panel[b-mt97vprbwb] {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 5px;
    z-index: 30;
    max-height: 300px;
    overflow-y: auto;
}
/* /Components/Shared/Modal.razor.rz.scp.css */
.modal-overlay[b-miqtfby3jo] {
    position: fixed;
    inset: 0;
    background: rgba(12, 23, 48, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1050;
    padding: 1rem;
    outline: none;
}

.modal-card[b-miqtfby3jo] {
    width: 100%;
    max-width: 560px;
    max-height: 90vh;
    overflow-y: auto;
    background: #ffffff;
    border-radius: var(--r-10);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
    animation: modal-pop-b-miqtfby3jo 0.15s ease;
}

.modal-card-wide[b-miqtfby3jo] {
    max-width: 1060px;
}

@keyframes modal-pop-b-miqtfby3jo {
    from {
        transform: translateY(-8px);
        opacity: 0;
    }

    to {
        transform: translateY(0);
        opacity: 1;
    }
}

.modal-header[b-miqtfby3jo] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.25rem;
    background: linear-gradient(90deg, #0c1730, #101f42);
    border-radius: 10px 10px 0 0;
}

.modal-title[b-miqtfby3jo] {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    color: #ffffff;
}

.modal-close[b-miqtfby3jo] {
    flex: none;
    width: 2rem;
    height: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--r-6);
    background: transparent;
    color: #cbd5e1;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

    .modal-close:hover[b-miqtfby3jo] {
        background: rgba(255, 255, 255, 0.12);
        color: #ffffff;
    }

/* ===== T-FICHES — BARRE D'ACTIONS DANS L'EN-TÊTE ==================================
   ⚠️ TOUT ce bloc est conditionné par `.modal-card--barre`, posée UNIQUEMENT quand une
   barre d'actions est fournie. Les 43 autres écrans qui utilisent `Modal` ne voient
   RIEN changer — c'est la leçon T-UI (styler un conteneur partagé a cassé deux fois
   des écrans que la tranche ne touchait pas).                                        */
.modal-header-actions[b-miqtfby3jo] {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin-left: auto;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* L'en-tête ne défile jamais : c'est l'exigence de la tranche — on ne descend plus
   chercher « Valider » au bas d'une fiche de 38 champs. */
.modal-card--barre .modal-header[b-miqtfby3jo] {
    position: sticky;
    top: 0;
    z-index: 2;
}

.modal-body[b-miqtfby3jo] {
    padding: 1.25rem;
}

.modal-footer[b-miqtfby3jo] {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    padding: 1rem 1.25rem;
    border-top: 1px solid #e5e7eb;
}

/* Mobile : la modale occupe tout l'écran plutôt que d'être une carte centrée.
   Même point de rupture (768px) que le reste du patron CRUD (voir app.css). */
@media (max-width: 768px) {
    .modal-overlay[b-miqtfby3jo] {
        padding: 0;
        align-items: stretch;
        justify-content: stretch;
    }

    .modal-card[b-miqtfby3jo] {
        width: 100%;
        max-width: none;
        height: 100%;
        max-height: none;
        border-radius: 0;
        display: flex;
        flex-direction: column;
        animation: none;
    }

    .modal-header[b-miqtfby3jo] {
        border-radius: 0;
        flex: none;
    }

    /* T-FICHES — sous 768 px l'en-tête s'empile : le titre sur une ligne, les actions
       sur la suivante, en pleine largeur. Sans cela, quatre boutons et un titre sur
       390 px se chevauchent. (Le sticky est inutile ici : `flex: none` dans une carte
       en colonne le rend déjà fixe.) */
    .modal-card--barre .modal-header[b-miqtfby3jo] {
        flex-wrap: wrap;
        position: static;
    }

    .modal-card--barre .modal-header-actions[b-miqtfby3jo] {
        width: 100%;
        margin-left: 0;
        justify-content: flex-start;
    }

    .modal-body[b-miqtfby3jo] {
        flex: 1 1 auto;
        overflow-y: auto;
    }

    .modal-footer[b-miqtfby3jo] {
        flex: none;
        position: sticky;
        bottom: 0;
        background: #ffffff;
        flex-wrap: wrap;
    }

        .modal-footer > *[b-miqtfby3jo] {
            flex: 1 1 auto;
        }

    /* ===== FICHE CLIENT MOBILE (R1) ===============================================
       ⚠️ TOUT ce bloc est conditionné par `modal-card--fiche-mob`, posée par UN seul
       écran via le paramètre additif `Classe` — les 44 autres usages de Modal ne
       voient RIEN changer (même doctrine que `--barre` ci-dessus).
       R1 : le bandeau bleu nuit disparaît sous 768 px, remplacé par la barre claire
       que l'écran rend en tête de son contenu (`.pfx-mob-bar`). Le corps perd son
       padding : les blocs mobiles gèrent le leur (et la barre colle bord à bord). */
    .modal-card--fiche-mob .modal-header[b-miqtfby3jo] {
        display: none;
    }

    .modal-card--fiche-mob .modal-body[b-miqtfby3jo] {
        padding: 0;
    }
}
/* /Components/Shared/ProduitPicker.razor.rz.scp.css */
.pp-wrap[b-j2kqn25w80] {
    position: relative;
}


.pp-panel[b-j2kqn25w80] {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 1000;
    min-width: 100%;
    width: max-content;
    max-width: min(720px, 92vw);
    max-height: 320px;
    overflow: auto;
    background: var(--paper, #f3f5f7);
    border: 1px solid var(--line, #e5e7eb);
    border-radius: var(--r-10);
    box-shadow: 0 12px 32px rgba(15, 23, 42, .16);
}

.pp-table[b-j2kqn25w80] {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.pp-table th[b-j2kqn25w80] {
    position: sticky;
    top: 0;
    background: var(--thead-bg, #fafbfc);
    text-align: left;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--slate, #64748b);
    padding: 8px 12px;
    border-bottom: 1px solid var(--line, #e5e7eb);
}

.pp-table td[b-j2kqn25w80] {
    padding: 7px 12px;
    border-bottom: 1px solid var(--line, #e5e7eb);
    white-space: nowrap;
}

.pp-table tbody tr[b-j2kqn25w80] {
    cursor: pointer;
}

.pp-table tbody tr:hover td[b-j2kqn25w80] {
    background: var(--teal-soft, #e4f3f1);
}

.pp-dh[b-j2kqn25w80] {
    font-size: 10px;
    color: var(--slate, #94a3b8);
    margin-left: 3px;
}

.pp-vide[b-j2kqn25w80] {
    padding: 14px;
    color: var(--slate, #64748b);
    font-size: 13px;
}

/* Mobile : panneau pleine largeur du champ (la rangée de saisie est déjà empilée). */
@media (max-width: 768px) {
    .pp-panel[b-j2kqn25w80] {
        width: 100%;
        max-width: 100%;

        /* ⚠️⚠️ LE PANNEAU EST BLANC EN MOBILE, ET LE MOTIF N'EST PAS COSMÉTIQUE.
           Son fond est `--paper` depuis l'import initial — le MÊME gris que le fond de
           l'application. Au BUREAU cela ne se voit pas : il flotte au-dessus du contenu
           avec une ombre et une bordure, qui le détachent. En mobile il devient une
           FEUILLE pleine largeur, sans rien derrière lui : le gris sur gris efface la
           frontière, et la liste de produits paraît posée sur le vide.
           ⭐ Défaut nommé par Walid — *les éléments transparents prennent le gris
           d'arrière-plan*. Celui-ci n'est pas transparent : il est gris DÉCLARÉ, ce qui
           revient au même à l'œil et demande le même remède.
           ⚠️ Borné au mobile : au bureau le gris joue son rôle de surface secondaire, et
           l'ombre le détache déjà. */
        background: var(--surface);
    }
}

/* Code-barres : colonne dédiée en desktop, inline sous la référence en mobile. */
.pp-cb-inline[b-j2kqn25w80] {
    display: none;
    font-size: 10px;
    color: var(--slate, #64748b);
    font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
    .pp-hide-narrow[b-j2kqn25w80] { display: none; }
    .pp-cb-inline[b-j2kqn25w80] { display: inline; }
}
/* /Components/Shared/SaisieMultipleProduits.razor.rz.scp.css */
.sm-table-wrap[b-qfonhf6der] {
    max-height: 52vh;
    overflow: auto;
}

.sm-row-added[b-qfonhf6der] {
    background: var(--green-soft, #e6f6ec) !important;
    transition: background 0.3s ease;
}

.sm-row-added[b-qfonhf6der]  .btn-nouveau {
    background: var(--green, #1e9e6b);
}

.sm-compteur[b-qfonhf6der] {
    margin-right: auto;
    font-size: 13px;
    font-weight: 600;
    color: var(--slate, #64748b);
}

@media (max-width: 640px) {
    .sm-hide-narrow[b-qfonhf6der] {
        display: none;
    }
}

/* Dans la pop-up, l'en-tête colle en haut du conteneur scrollable (le sticky
   global à top:64px surplomberait la 1ère ligne et capterait ses clics). */
.sm-table-wrap .crud-list thead th[b-qfonhf6der] {
    top: 0;
    background: var(--thead-bg, #fafbfc);
}

/* ⚠️⚠️ LE SURVOL EST RETIRÉ — demande du client, et la raison est MESURABLE : depuis
   T-BLV3/L, la rangée PRISE porte un fond `--f-succes`. Un survol `--teal-soft` posé sur les
   AUTRES rangées met alors DEUX verts pâles voisins à l'écran, qui veulent dire deux choses
   opposées — « tu as choisi ceci » et « ton pointeur passe ici ». *Deux signaux de même
   couleur pour deux sens différents ne se distinguent pas, ils se confondent.*
   ⚠️ LE BORNAGE `(hover: none)` NE SUFFISAIT PAS, et il n'était pas fautif : il éteint le
   survol sur un écran TACTILE. La capture qui l'a signalé vient d'un navigateur de BUREAU en
   fenêtre étroite — une souris, donc `(hover: none)` ne s'y applique pas. Le bornage était
   juste ; c'est la règle elle-même qui n'a plus lieu d'être.
   ⭐ On la SUPPRIME au lieu de la neutraliser : une règle éteinte par une autre laisse deux
   choses à lire là où il n'y a plus rien à dire. */

/* ⚠️⚠️ L'AVERTISSEMENT DE PLAFOND — AMBRE, JAMAIS ROUGE. Dans ce dépôt le rouge signale un
   PROBLÈME ; une liste tronquée n'en est pas un, c'est un FAIT à connaître (même arbitrage que
   le bandeau d'abonnement et que l'alerte des bons d'entrée en brouillon). Un écran qui alarme
   sur ce qui va bien apprend à ignorer ses alarmes.
   ⚠️ `--amber-dark` et non `--amber` : l'accent porte les APLATS, le ton foncé porte le TEXTE
   (L1b). --amber rend 2,63 sur --amber-soft, --amber-dark 4,78 — au-dessus du seuil DURCI de
   4,60 (L1d), et c'est `SaisieMultipleReglesTests.SM14` qui le chiffre, le harnais en étant
   aveugle.
   ⚠️⚠️ AUCUNE VALEUR DE REPLI DANS LES `var()`, ET C'EST LA GARDE G3 QUI L'A EXIGÉ : j'avais
   écrit `var(--amber-soft, #FBF1E0)`. Un repli est une SECONDE VALEUR — elle ne suivra aucun
   changement de token, et elle le fera EN SILENCE. `app.css` porte le `:root` et est chargé
   avant ce fichier sur toutes les pages : le repli était mort ET dangereux. */
.sm-tronque[b-qfonhf6der] {
    margin: 0 0 0.6rem;
    padding: 7px 10px;
    border-radius: var(--r-8);
    background: var(--amber-soft);
    color: var(--amber-dark);
    font-size: 12.5px;
    font-weight: 600;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   SM-2 — LA FORME MOBILE DE LA SAISIE MULTIPLE (< 768 px)

   ⚠️⚠️ CE QUE CE BLOC RÉPARE, ET LE MÉCANISME A UN NOM. Le tableau porte `crud-list`,
   c'est-à-dire le patron générique tableau → cartes du dépôt. Sous 768 px, `app.css` fait
   `td::before { content: attr(data-label) }` — et AUCUN `<td>` d'ici ne portait de
   `data-label`. `attr()` sur un attribut absent résout à la CHAÎNE VIDE : le pseudo-élément
   était bien créé, il occupait sa place de flex-item, et il n'affichait RIEN. Le `<td>` étant
   `justify-content: space-between; text-align: right`, chaque valeur était poussée à droite
   D'UN VIDE, `<thead>` masqué par-dessus.
   ⇒ Mesuré au navigateur AVANT : 7 cellules par rangée, **0 portant un libellé**, rangée de
     **301 px**, **2 rangées visibles** sur un iPhone 12.
   ⭐ L'écran ne s'effondrait pas : *il appliquait correctement un patron dont il n'avait jamais
     rempli la condition d'emploi.*

   ⚠️⚠️ BORNAGE — ET IL EST STRUCTUREL, PAS SEULEMENT PRUDENT. Ce fichier est un CSS SCOPÉ :
   chaque sélecteur reçoit l'attribut de portée du composant, et ne peut atteindre que des
   éléments écrits DANS `SaisieMultipleProduits.razor`. `crud-list` porte **42 tables** dont
   **27 vont bien aujourd'hui** ; `.filter-row` est partagée par **10 écrans**. Retoucher le
   bloc `@media` de `crud-list` les aurait toutes atteintes — c'est le défaut que TROIS
   tranches ont déjà commis (T-UI, `.crud-toolbar-actions`, `.doclist`).
   ⭐ Ici, aucune règle ne PEUT sortir du composant. Le bornage ne repose pas sur ma vigilance.

   ⭐ LE VOCABULAIRE VIENT DE `doc-card-edit` (7 écrans de document) — **le seul patron de
   SAISIE du dépôt** : libellé de 11 px AU-DESSUS du champ, plusieurs champs par rangée. Les
   47 écrans à `CrudCardsShell` et les 3 à `data-label` sont des formes de LECTURE : un champ
   par ligne, pleine largeur. ⚠️ Elles ne conviennent pas ici — *l'utilisateur ne LIT pas 25
   articles, il en SAISIT*, et une carte de lecture coûte 301 px là où une carte de saisie en
   coûte 130.
   ⚠️ Mais `doc-card-edit` édite UNE ligne ; ici on en parcourt 25. On lui emprunte donc son
   PRINCIPE (libellé au-dessus), pas sa grille : la désignation prend toute la largeur, les
   méta se serrent sur une ligne, et les trois gestes tiennent sur la dernière.
   ══════════════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {

    /* ── ① LE DOUBLE DÉFILEMENT — un conteneur défilant DANS un conteneur défilant ──────
       `max-height: 52vh` est écrit pour le BUREAU, où la modale est une carte centrée à
       `max-height: 90vh`. En mobile `Modal.razor.css` la met en PLEIN ÉCRAN avec
       `.modal-body { overflow-y: auto }` : les deux défilent, et le doigt ne sait plus lequel
       il pousse.
       ⚠️ Mesuré AVANT, et c'est la mesure qui a tranché : à 390×844 seule la zone défile
       (52vh = 439 px ≈ la place disponible, coïncidence de ce format) ; à **390×667 les DEUX
       défilent** (52vh = 347 px pour 261 px disponibles). Le défaut dépendait du téléphone.
       ⇒ On rend la hauteur au corps de la modale : UN seul défilement, et la zone reprend
         toute la place — davantage de rangées visibles, sans rien changer au bureau. */
    .sm-table-wrap[b-qfonhf6der] {
        max-height: none;
        overflow: visible;
    }

    /* ── ② LA RANGÉE DEVIENT UNE CARTE DE SAISIE ───────────────────────────────────────
       ⚠️ Les sélecteurs sont plus spécifiques que ceux d'`app.css` (0,3,1 + l'attribut de
       portée contre 0,1,1) : ils GAGNENT sans `!important`, et sans nommer `crud-list`
       ailleurs que sous `.sm-table-wrap`. */
    .sm-table-wrap table.crud-list tr[b-qfonhf6der] {
        display: grid;
        grid-template-columns: 1fr 1fr auto;
        /* ⚠️⚠️ LE PRIX REJOINT LA RÉFÉRENCE — demande du client, et il quitte la ligne de
           saisie. Ce qu'on lit d'un produit (ce qu'il coûte) se lit AVEC ce qui l'identifie ;
           ce qu'on y fait (la quantité, l'ajout) reste sur la ligne d'action.
           ⚠️ `cb` disparaît de la grille : le code-barres était déjà masqué sous 640 px, et
           il n'a jamais eu de place ici. Il reste dans le DOM et au bureau. */
        /* ⚠️ RANGÉE PRISE : le prix retourne à côté de la QUANTITÉ, et il y est en HT —
           précision du client. C'est le moment où l'on SAISIT, et le HT est ce que le document
           manipule. Le TTC, lui, vit sur la rangée NON prise (grille plus bas). */
        grid-template-areas:
            "des   des   des"
            "ref   ref   stock"
            "qte   pu    act";
        /* ⭐ 14 px : la même valeur que l'écart entre les blocs du document (T-BLV3/D1). */
        gap: 4px 14px;
        align-items: end;
        padding: 10px 12px;
        margin-bottom: 10px;
        border: 1px solid var(--line);
        border-radius: var(--r-10);
        background: var(--surface);
    }

    /* ⚠️⚠️ `height: auto` — ET C'EST LA MESURE AU NAVIGATEUR QUI L'A EXIGÉ, PAS LA LECTURE.
       Première tentative : la rangée tombait de 301 à 174 px seulement, et le détail par
       cellule disait pourquoi — **les TROIS lignes de la grille valaient 48 px**, y compris
       celle qui ne porte qu'une référence de 11,5 px.
       ⭐ LA CAUSE : la pop-up est rendue À L'INTÉRIEUR de la page du document, donc
       `.doc-page .crud-list tbody td { height: 48px }` l'atteint. *Une modale n'est pas un
       écran : elle hérite du CSS de la page qui l'ouvre* — et l'étape 0, qui lisait le
       composant, ne pouvait pas le voir.
       ⚠️ On neutralise la HAUTEUR, pas la règle : `.doc-page` garde ses 48 px pour ses
       propres lignes de document. */
    .sm-table-wrap table.crud-list td[b-qfonhf6der] {
        display: block;
        height: auto;
        padding: 0;
        border: none;
        background: transparent;
        text-align: left;
        min-width: 0;
    }

    /* Le libellé n'est PAS affiché sur les cellules de LECTURE : la désignation, la référence
       et le stock se reconnaissent d'eux-mêmes, et trois libellés de plus coûteraient une
       rangée. Il l'est sur les deux champs de SAISIE, où il est indispensable. */
    .sm-table-wrap table.crud-list td[b-qfonhf6der]::before {
        content: none;
    }

    .sm-table-wrap table.crud-list td.sm-c-des[b-qfonhf6der] {
        grid-area: des;
        font-weight: 600;
        font-size: 14px;
        line-height: 1.25;
        color: var(--ink);
    }

    .sm-table-wrap table.crud-list td.sm-c-ref[b-qfonhf6der] { grid-area: ref; }
    .sm-table-wrap table.crud-list td.sm-c-cb[b-qfonhf6der] { grid-area: cb; }
    .sm-table-wrap table.crud-list td.sm-c-stock[b-qfonhf6der] { grid-area: stock; text-align: right; }

    .sm-table-wrap table.crud-list td.sm-c-ref[b-qfonhf6der],
    .sm-table-wrap table.crud-list td.sm-c-cb[b-qfonhf6der],
    .sm-table-wrap table.crud-list td.sm-c-stock[b-qfonhf6der] {
        font-size: 11.5px;
        color: var(--slate);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Le stock porte son mot : « 12,00 » seul, en bout de ligne, ne se lit pas. */
    .sm-table-wrap table.crud-list td.sm-c-stock[b-qfonhf6der]::before {
        content: attr(data-label) " ";
        font-weight: 500;
    }

    /* ── ③ LES DEUX CHAMPS : LIBELLÉ AU-DESSUS (le principe de `doc-card-edit`) ─────────── */
    .sm-table-wrap table.crud-list td.sm-c-qte[b-qfonhf6der] { grid-area: qte; }
    .sm-table-wrap table.crud-list td.sm-c-pu[b-qfonhf6der] { grid-area: pu; }

    /* ⚠⚠ LE PRIX N'A PLUS DE LIBÉLLÉ AU-DESSUS, ET C'EST LA MESURE QUI L'A EXIGÉ : depuis
       qu'il a rejoint la référence, le pseudo-élément « PU TTC (DH) » le poussait 25 px PLUS
       HAUT que la référence — les deux ne s'alignaient plus, alors qu'on venait de les mettre
       côte à côte. ⭐ Et il n'apprend rien : un montant posé contre une référence de produit
       EST son prix ; c'est ce que la maquette fait (« 32,00 DH », sans titre).
       ⚠ LA QUANTITÉ GARDE LE SIEN : elle est un champ à REMPLIR, et un champ sans étiquette
       ne dit pas ce qu'on y attend. *On nomme ce qu'on demande, pas ce qu'on montre.*
       ⚠ `data-label` RESTE dans le markup : il est le repli du mécanisme générique de
       `crud-list` si ce bloc borné disparaissait un jour. */
    /* ⚠️ LE LIBELLÉ NE PARAÎT QUE SUR LA RANGÉE PRISE : `data-label` y vaut « PU HT (DH) »,
       et il est VIDE sur la non prise (le Razor le décide). `attr()` sur un attribut vide résout
       à la chaîne vide — le pseudo-élément existe et ne rend rien. *On nomme ce qu'on demande,
       pas ce qu'on montre.* */
    .sm-table-wrap table.crud-list tr.sm-row-sel td.sm-c-pu[b-qfonhf6der]::before,
    .sm-table-wrap table.crud-list td.sm-c-qte[b-qfonhf6der]::before {
        content: attr(data-label);
        display: block;
        font-size: 11px;
        font-weight: 600;
        color: var(--slate);
        margin-bottom: 2px;
    }

    .sm-table-wrap table.crud-list td.sm-c-qte input[b-qfonhf6der],
    .sm-table-wrap table.crud-list td.sm-c-pu input[b-qfonhf6der] {
        width: 100%;
    }

    /* ── ④ LE BOUTON — cible tactile pleine hauteur, aligné sur le bas des champs ──────── */
    .sm-table-wrap table.crud-list td.sm-c-act[b-qfonhf6der] {
        grid-area: act;
        text-align: right;
    }

    .sm-table-wrap table.crud-list td.sm-c-act .btn-nouveau[b-qfonhf6der] {
        min-height: 38px;
        padding: 8px 12px;
        white-space: nowrap;
    }

    .sm-table-wrap table.crud-list td.sm-c-vide[b-qfonhf6der] {
        grid-column: 1 / -1;
        text-align: center;
    }

    /* ── ⑤ LES FILTRES — 190 px MESURÉS, POUR CINQ CONTRÔLES QUI S'EMPILENT ─────────────
       `.crud-search` plafonne à 320 px et chaque `.form-select` à 220 : dans les 350 px
       utiles d'un écran de 390, ils tombent à UN PAR LIGNE — cinq lignes, 190 px, soit
       22 % de l'écran avant d'avoir vu un seul article.
       ⚠️⚠️ `.filter-row` est PARTAGÉE PAR 10 ÉCRANS : cette règle ne l'atteint que parce que
       ce fichier est SCOPÉ. Ne jamais porter l'équivalent dans `app.css`.
       ⭐ DEUX par ligne, et non trois : à trois, « Choix Sous-Famille » se tronque au point
       de ne plus distinguer les listes. On gagne deux lignes, pas trois — la troisième se
       serait payée en lisibilité. */
    .filter-row .form-select[b-qfonhf6der] {
        flex: 1 1 calc(50% - 4px);
        max-width: none;
        min-width: 0;
    }

    .filter-row .btn-filtres[b-qfonhf6der] {
        flex: 1 1 100%;
    }
}

/* ⚠️⚠️ LE CODE-BARRES ÉTAIT REDEVENU VISIBLE À 390 px — ET C'EST MA PROPRE RÈGLE QUI L'AVAIT
   RÉVEILLÉ. `.sm-hide-narrow { display: none }` pèse (0,1,0) ; mon
   `.sm-table-wrap table.crud-list td { display: block }` pèse (0,3,1) plus l'attribut de
   portée. Il gagnait, et le masquage voulu depuis toujours tombait EN SILENCE.
   ⭐ Trouvé en REGARDANT la capture, pas en relisant le CSS : les chiffres de hauteur étaient
   bons, et ils portaient sur autre chose. *Une mesure de géométrie ne dit rien de ce qui est
   AFFICHÉ dedans.*
   ⇒ Sous 640 px la référence prend les deux premières colonnes, et le code-barres disparaît
     comme prévu. */
@media (max-width: 640px) {
    .sm-table-wrap table.crud-list tr[b-qfonhf6der] {
        /* ⚠ SOUS 640 px, LA MÊME RÉPARTITION QU'AU-DESSUS : le prix reste avec la référence.
           Laisser l'ancienne grille ici aurait fait SAUTER le prix d'une ligne à l'autre selon
           la largeur — un défaut qu'aucune capture prise à 390 px n'aurait montré. */
        /* ⚠⚠ SOUS 640 px, LA MÊME GRILLE QU'AU-DESSUS — et c'est une MESURE qui l'a exigé :
           ce bloc s'applique À 390 px et il vient APRÈS, donc il ÉCRASE la grille de la rangée
           prise. Laissé à l'ancienne répartition, le prix restait collé à la référence alors
           qu'on venait de le renvoyer vers la quantité. *Une grille corrigée en un endroit et
           pas dans l'autre ne se voit qu'à la largeur où la seconde gagne.* */
        grid-template-areas:
            "des   des   des"
            "ref   ref   stock"
            "qte   pu    act";
    }

    .sm-table-wrap table.crud-list td.sm-c-cb[b-qfonhf6der] {
        display: none;
    }
}



/* ══════════════════════════════════════════════════════════════════════════════════════
   SM-3 — LE REPLI DES TROIS LISTES DÉROULANTES (mobile seulement)

   ⚠️⚠️ CE QU'ON REPLIE, ET LE MOTIF EST STRUCTUREL : la requête rend 25 articles au plus,
   sans pagination. **La RECHERCHE est le SEUL chemin vers les 2 975 autres** d'un catalogue
   de 3 000 — la replier fermerait la seule porte. Les trois listes AFFINENT ce qui est déjà
   là. *On replie ce qui affine, jamais ce qui ouvre.*

   ⭐ AUCUNE CLASSE NEUVE POUR LA BARRE : `BarreReplis` (L5, 17 écrans) est RÉEMPLOYÉE telle
   quelle, avec son badge de filtres actifs. Ce bloc ne fait que la placer et régler le
   conteneur repliable.
   ══════════════════════════════════════════════════════════════════════════════════════ */

/* ⚠️⚠️ `display: contents` — ET C'EST LA PIÈCE QUI PROTÈGE LE BUREAU. Sans elle, ce conteneur
   deviendrait un élément de la rangée flex : les trois listes et leur bouton passeraient à la
   ligne, et le bureau paierait ~73 px de plus POUR UN REPLI DONT IL N'A QUE FAIRE. Avec elle,
   les enfants restent des éléments directs de `.filter-row` — la rangée du bureau est celle
   d'avant, au pixel.
   ⭐ Mesuré : capture 1650×1000 identique OCTET POUR OCTET avant/après. */
/* ══════════════════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ CES RÈGLES ONT ÉTÉ RETIRÉES D'ICI PAR H2 — ELLES SONT DEVENUES GLOBALES, PAS SUPPRIMÉES.
   Elles vivaient sous `.sm-filtres` et `.sm-filtres--deplies`, dans ce fichier SCOPÉ. H2 a
   posé le même mécanisme pour les 8 listes qui portent `.filter-row` : deux noms pour la même
   chose auraient divergé au premier ajustement.
   ⇒ Le conteneur s'appelle désormais `.filtres-repli` / `.filtres-repli.deplie` et ses règles
     sont dans `app.css`, à côté du repli des pastilles (L5). Ce composant les CONSOMME.
   ⭐ Le modificateur passe de `--deplies` à `.deplie` : c'est la convention des trois autres
     conteneurs repliables du dépôt (`.doclist-filters.deplie`, `.doclist-kpis.deplie`,
     `.reg-champs.deplie`) — `--deplies` était l'exception, elle disparaît avec la fusion.
   ⚠️ Ce qui reste ICI est ce qui est PROPRE à la pop-up : les deux listes par ligne (⑤ plus
     haut), qui n'ont de sens que dans une modale de 350 px utiles.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* ═════════════════════════════════════════════════════════════════════
   SM-3 / T-BLV3 B5 — LA RANGÉE NE S'OUVRE QU'UNE FOIS CHOISIE (le geste de la maquette)

   ⚠⚠ MESURÉ AVANT D'ÉCRIRE : la rangée faisait **114,3 px** et l'écran en rendait 19 — six
   produits visibles à la fois. Elle rendait TOUJOURS trois lignes : désignation, puis
   référence/code-barres/stock, puis quantité/prix/bouton. Or **le prix et le bouton ne servent
   à rien tant que le produit n'est pas choisi** : on les rendait à vingt-cinq lignes pour en
   servir deux ou trois.

   ⭐ La maquette pose exactement ce geste : sa rangée est un interrupteur, et le stepper
   n'apparaît qu'une fois la ligne prise. On GARDE nos champs — le PU se saisit ici et la
   maquette ne le permet pas, *ce qu'elle ignore on le complète* — ils descendent seulement
   sous le pli tant que la ligne n'est pas sélectionnée.

   ⚠ LE STEPPER RESTE TOUJOURS VISIBLE, ET C'EST LUI QUI SÉLECTIONNE : passer de 0 à 1 fait
   entrer la ligne dans le panier. Sans un geste de sélection accessible en permanence, une
   rangée repliée serait un cul-de-sac.
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {

    /* ⚠️⚠️ RANGÉE NON PRISE : LE PRIX **TTC** REJOINT LA RÉFÉRENCE — précision du client.
       Avant de prendre, on compare ce que le produit COÛTE ; c'est le TTC qui sert, et il se
       lit contre ce qui identifie le produit.
       ⚠️ UNE COLONNE DE PLUS (quatre) : la référence garde le `1fr`, les trois autres se
       dimensionnent sur leur contenu. Le `+` reste tout à droite, là où le pouce l'attend. */
    .sm-table-wrap table.crud-list tr:not(.sm-row-sel)[b-qfonhf6der] {
        grid-template-columns: 1fr auto auto auto;
        grid-template-areas:
            "des  des   des   des"
            "ref  pu    stock qte";
        align-items: center;
    }

    /* ⚠️ `sm-c-pu` N'EST PLUS MASQUÉE : elle porte désormais le prix TTC de la rangée non
       prise. Seuls le bouton d'action et le code-barres restent cachés tant qu'on n'a pas pris. */
    .sm-table-wrap table.crud-list tr:not(.sm-row-sel) td.sm-c-cb-NEUTRALISE[b-qfonhf6der],
    .sm-table-wrap table.crud-list tr:not(.sm-row-sel) td.sm-c-act[b-qfonhf6der],
    .sm-table-wrap table.crud-list tr:not(.sm-row-sel) td.sm-c-cb[b-qfonhf6der] { display: none; }

    .sm-qte-wrap[b-qfonhf6der] { display: flex; align-items: center; gap: 4px; }

    .sm-step[b-qfonhf6der] {
        flex: 0 0 auto;
        width: 34px;
        height: 34px;
        border: 1px solid var(--line);
        border-radius: var(--r-9);
        background: var(--paper);
        color: var(--t-succes);
        font-size: 17px;
        font-weight: 600;
        line-height: 1;
    }

    .sm-step:disabled[b-qfonhf6der] { opacity: .45; }
    .sm-qte-wrap input[b-qfonhf6der] { min-width: 0; }

    .sm-vues[b-qfonhf6der] { display: flex; gap: 6px; margin-bottom: 8px; }

    .sm-vue[b-qfonhf6der] {
        padding: 7px 12px;
        border: 1px solid var(--line);
        border-radius: 999px;
        background: var(--surface);
        color: var(--slate);
        font-size: 12px;
        font-weight: 600;
    }

    .sm-vue-on[b-qfonhf6der] { background: var(--f-succes); border-color: var(--f-succes); color: var(--t-succes); }
    .sm-vue:disabled[b-qfonhf6der] { opacity: .45; }

    .sm-recap[b-qfonhf6der] {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: 6px;
        font-size: 12px;
        color: var(--slate);
        font-variant-numeric: tabular-nums;
    }

    .sm-recap-sep[b-qfonhf6der] { width: 3px; height: 3px; border-radius: 50%; background: var(--slate); }

    /* ⚠ `.sm-recap-vide` ÉTAIT UNE CLASSE FANTÔME — posée dans le markup, jamais définie ici.
       C'est la garde `V3/C1` du dépôt qui l'a dit, au premier run. *Le dépôt se garde lui-même,
       et une classe muette est indiscernable d'une classe oubliée.* */
    .sm-recap-vide[b-qfonhf6der] { font-style: italic; }

    /* ⚠ `.sm-ajouter-selection` ne peignait RIEN : la garde `H1` du dépôt l'a dit — une
       classe MARQUEUR dont une voisine (`btn-nouveau`) fait tout le travail. Elle peint
       désormais ce qui lui revient : au doigt, l'action principale prend la largeur. */
    .sm-ajouter-selection[b-qfonhf6der] { flex: 1 1 auto; min-height: 44px; }
}

/* ⚠ AU BUREAU les deux boutons du stepper N'EXISTENT PAS : le champ se remplit au clavier, et
   25 lignes × 2 cibles y coûteraient de la place pour rien. La règle est posée ICI, hors du
   média mobile, pour ne dépendre d'aucun ordre de déclaration. */
@media (min-width: 769px) {
    .sm-step[b-qfonhf6der] { display: none; }
    .sm-qte-wrap[b-qfonhf6der] { display: contents; }
}

/* ⚠ LE BADGE DE VARIANTE — il n'est PAS borné au mobile : au bureau aussi, on pouvait
   sélectionner un article à variantes sans savoir qu'il en exigeait une. 11 px, le plancher. */
.sm-badge-var[b-qfonhf6der] {
    display: inline-block;
    margin-left: 7px;
    padding: 1px 7px;
    border-radius: 5px;
    background: var(--f-bronze);
    color: var(--t-bronze);
    font-size: 11px;
    font-weight: 600;
    white-space: nowrap;
}

/* ══ T-BLV3 / L — LA RANGÉE SELON LA MAQUETTE, EN MOBILE ════════════════════════════════
   ⚠ BORNÉ AU MOBILE : au bureau le tableau reste un tableau — les colonnes y portent
   l'information mieux qu'une carte, et rien dans la demande ne vise cet écran-là. */
@media (max-width: 768px) {
    /* ── LA RANGÉE PRISE SE VOIT AU FOND, PLUS AU CADRE ──
       ⚠ `--f-succes` est le fond de succès du dépôt, employé tel quel : le vert pâle de la
       maquette n'est pas une teinte de plus à inventer. On ne pose AUCUNE encre par-dessus,
       donc aucun couple neuf à chiffrer — le texte garde la sienne (`--ink`, 14,51 sur ce
       fond, mesuré au même titre que les autres). */
    /* ══ LA RANGÉE PRISE SE VOIT AU FOND — ET L'ANCÊTRE A ÉTÉ REMONTÉ AVANT D'ÉCRIRE ═════
       ⚠⚠ DEUX ÉCRITURES ONT ÉCHOUÉ AVANT CELLE-CI, ET AUCUNE NE SE PLAIGNAIT :
       `.sm-row-sel { background }` rendait du BLANC, `tr.sm-row-sel > td { background }`
       laissait la cellule TRANSPARENTE. Je n'ai rien livré tant que je ne savais pas d'où
       venait le blanc — *une règle perdue par la cascade ne se plaint pas.*

       ⭐⭐ LA MESURE A NOMMÉ L'ANCÊTRE : c'est LA RANGÉE ELLE-MÊME. `.sm-table-wrap
       table.crud-list tr` la fait CARTE BLANCHE en mobile (fond, bordure, rayon) — c'est
       T-SM. La chaîne remonte donc d'un cran : cellule transparente, puis `<tr>` opaque.

       ⭐ ET C'EST UN COMPTE DE SPÉCIFICITÉ, DÉJÀ AU JOURNAL POUR CE FICHIER : la règle de
       T-SM pèse (0,3,2) avec l'attribut de portée ; `.sm-row-sel` seule pèse (0,2,0). Elle
       PERDAIT. On écrit donc la nôtre au même niveau, une classe plus loin — (0,4,2) — et
       elle gagne SANS `!important`, ce que le commentaire de T-SM annonce lui-même quinze
       lignes plus haut : *« ils GAGNENT sans !important »*.
       ⚠ `--f-succes` est le fond de succès du dépôt, employé tel quel : le vert pâle de la
       maquette n'est pas une teinte de plus à inventer. Aucune encre n'est posée par-dessus,
       donc aucun couple neuf à chiffrer — `--ink` y rend **14,51**. ════════════════════ */
    .sm-table-wrap table.crud-list tr.sm-row-sel[b-qfonhf6der] {
        background: var(--f-succes);
    }

    /* ── LE PRIX EN LECTURE ──
       ⚠ Il garde la chasse tabulaire des montants (`cell-mono`) : un prix qui change de
       largeur selon ses chiffres se compare mal d'une ligne à l'autre. */
    .sm-pu-lecture[b-qfonhf6der] {
        display: inline-block;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
    }

    /* ── LA RANGÉE NON PRISE NE MONTRE QUE SON « + » ──
       ⚠⚠ ELLE MASQUE LE STEPPER, PAS LE CHAMP : la quantité reste dans le DOM et garde sa
       valeur. B1 avait déjà mesuré qu'une rangée fermée sans stepper serait un cul-de-sac —
       et MA PREMIERE ECRITURE l'a cree : j'avais masque le stepper ENTIER en
       affirmant que le « + » de la colonne Action prenait ce role. MESURE : ce bouton-la est
       BUREAU SEUL, invisible en mobile (56 tentatives de clic expirees). Le stepper etait donc
       le SEUL moyen de selectionner au doigt. *Une affirmation posee sans mesure dans un
       commentaire devient un defaut dans le code.* ⇒ on ne masque que le « − » et le CHAMP ;
       le « + » reste, et c'est lui le bouton rond de la maquette.
       ⭐ C'est pourquoi on masque par le CONTENEUR (`sm-qte-wrap`) et non par le champ : le
       jour où la grille changerait, la quantité ne se retrouverait pas orpheline à l'écran. */
    tr:not(.sm-row-sel) .sm-qte-wrap [data-testid=sm-moins][b-qfonhf6der],
    tr:not(.sm-row-sel) .sm-qte-wrap input[b-qfonhf6der] {
        display: none;
    }
}

/* ══ T-BLV3 / N — LE PRIX TTC DE LA RANGÉE NON PRISE ═══════════════════════════════════
   ⚠ Il est en chasse tabulaire comme tous les montants du dépôt, et sans libellé : un
   montant posé contre une référence de produit EST son prix. */
@media (max-width: 768px) {
    .sm-pu-ttc[b-qfonhf6der] {
        display: inline-block;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
    }
}

/* ══ T-BLV3 / O — LE SURVOL VIENT DE LA PAGE, PAS D'ICI ═════════════════════════
   ⚠⚠ J'AVAIS RETIRÉ LA RÈGLE DU COMPOSANT ET LE SURVOL EST RESTÉ. La mesure l'a nommée :
   `.doc-page .crud-list tbody tr:hover td` dans `app.css` — la pop-up est rendue DANS le
   document, donc la règle de la PAGE l'atteint. C'est le piège #30 du dépôt, mot pour mot :
   *une modale hérite du CSS de la page qui l'ouvre.*
   ⭐ ET ON NE TOUCHE PAS À LA RÈGLE DE LA PAGE : elle est JUSTE pour le tableau de lignes du
   document, où le survol dit « cette ligne-là ». On neutralise la PROPRIÉTÉ, bornée au
   conteneur de la pop-up — c'est le remède que le piège #30 prescrit.
   ⚠ Le sélecteur porte `.sm-table-wrap` ET l'attribut de portée : (0,4,3) contre (0,3,2)
   pour celui de la page. Il gagne sans `!important`. ════════════════════════════ */
.sm-table-wrap .crud-list tbody tr:hover td[b-qfonhf6der] {
    background: transparent;
}

/* ⚠ LA RANGÉE PRISE GARDE SON FOND MÊME SOUS LE POINTEUR : sans cette clause, la
   neutralisation ci-dessus effacerait le vert dès qu'on survole la ligne qu'on vient de
   choisir — *un remède qui éteint aussi ce qu'il devait laisser vivre*. */
.sm-table-wrap .crud-list tbody tr.sm-row-sel:hover td[b-qfonhf6der] {
    background: transparent;
}

/* ══ LE PRIX TTC AVANT LE CHOIX — UN CRAN PLUS PETIT ══════════════════════════
   ⚠ Demande du client. 13 px : c'est la taille du LIBELLÉ de la carte de ligne du document
   (`.docf-ligne-total`), pas un chiffre inventé — le prix d'un produit qu'on n'a pas encore
   pris n'a pas à peser plus lourd que son nom. ═══════════════════════════════ */
@media (max-width: 768px) {
    .sm-pu-ttc[b-qfonhf6der] { font-size: 13px; }
}
/* /Components/Shared/TableTransfert.razor.rz.scp.css */
/* ══════════════════════════════════════════════════════════════════════════════════════════
   T-TRANSF ③ — LA FORME MOBILE DE LA TABLE DE RÉPARTITION D'UN TRANSFERT

   ⚠️⚠️ LE MÉCANISME, MESURÉ AU NAVIGATEUR AVANT D'ÊTRE CORRIGÉ (390×844, BR26000012) :
   la table porte `crud-list`, le patron générique tableau → cartes du dépôt. Sous 768 px,
   `app.css` fait `thead { display:none }` puis `td::before { content: attr(data-label) }`.
   **Aucun `<td>` ne portait de `data-label`.** `attr()` sur un attribut absent résout à la
   CHAÎNE VIDE : le pseudo-élément était bien créé, il occupait sa place de flex-item, et il
   n'affichait RIEN. Le `<td>` étant `justify-content: space-between; text-align: right`,
   chaque valeur était poussée à droite D'UN VIDE, `<thead>` masqué par-dessus.
       relevé AVANT : rangée de **301 px** (pas vertical 313), **2 rangées visibles sur 3**,
                      **0 cellule sur 6** portant un libellé, `::before` = "" partout.
   ⭐ L'écran ne s'effondrait pas : *il appliquait correctement un patron dont il n'avait jamais
     rempli la condition d'emploi.* Exactement la panne de la saisie multiple (T-SM2).

   ⭐⭐ ET LE PIÈGE #30 EST ARMÉ ICI AUSSI, MESURÉ : `.doc-page .crud-list tbody td { height: 48px }`
   (app.css l.2700) vit **hors de tout `@media`** — dernier `@media` avant elle l.2586, refermé
   l.2644. La modale est rendue À L'INTÉRIEUR de `.doc-page` : les six cellules empilées valaient
   donc 48 px chacune, y compris celle qui ne porte qu'une référence. 6 × 48 = 288, + le padding
   du `tr` (11,2) + les bordures = les 301 px relevés.
   ⚠️ On neutralise la **PROPRIÉTÉ** (`height: auto`), jamais la règle de la page : `.doc-page`
     garde ses 48 px pour les lignes de SES documents.

   ⚠️⚠️ CE QUI DIFFÈRE DE LA SAISIE MULTIPLE, ET QU'IL NE FAUT PAS COPIER :
     · **Pas de double défilement à réparer.** Mesuré : un seul conteneur défile (`.modal-body`).
       Il n'y a pas d'équivalent de `.sm-table-wrap` / `52vh` ici.
     · **Rien à replier** (T-SM3 ne se transpose pas) : cette modale n'a NI recherche NI filtre.
     · **Le geste n'est pas le même** : là-bas on CHOISIT dans un catalogue de 3 000 ; ici on
       RÉPARTIT un ensemble déjà connu et fermé — les lignes du document lui-même.
     · **Aucun plafond** : la table rend une rangée par ligne de reste > 0, sans pagination.
       Mesuré en dev : le plus gros document fait TROIS lignes — *l'environnement ne peut pas
       exprimer le cas*. À 200 lignes, l'ancienne forme demandait ~62 600 px de défilement.
   ══════════════════════════════════════════════════════════════════════════════════════════ */

/* ⚠️ Le CSS de ce fichier est SCOPÉ : chaque sélecteur reçoit l'attribut de portée du composant
   et ne peut atteindre que des éléments écrits dans `TableTransfert.razor`. Les 41 autres tables
   `.crud-list` du dépôt ne voient rien. `.tr-zone` s'y ajoute comme bornage EXPLICITE — la
   portée empêche de sortir du composant, pas d'atteindre une autre table du même écran. */

/* ⚠️⚠️ L'EN-TÊTE COLLANT DU BUREAU EST RECALÉ SUR LE CONTENEUR, PAS SUR LA BARRE DE NAVIGATION.
   `app.css` pose `.crud-list thead th { position: sticky; top: 64px }` au-dessus de 769 px — un
   décalage écrit pour la hauteur de `.app-topbar`, donc pour une PAGE. Dans une modale, le
   conteneur qui défile est `.modal-card` : l'en-tête s'y arrêterait 64 px trop bas, en
   surplombant les premières rangées et en captant leurs clics. C'est la correction que T-SM2 a
   déjà dû poser pour la pop-up de saisie multiple.
   ⚠️ SANS EFFET TANT QUE LA LISTE NE DÉFILE PAS : à trois lignes — le plus gros document de la
     dev — rien ne bouge. Mesuré : capture bureau 1650×1000 identique avant/après. Le défaut
     n'apparaît qu'au-delà, c'est-à-dire chez le client. */
@media (min-width: 769px) {
    .tr-zone .crud-list thead th[b-t7i564u3p4] {
        top: 0;
        background: var(--thead-bg);
    }
}

/* ── LA BARRE DES GESTES EN MASSE (T-TRANSF ⑤) ──────────────────────────────────────────
   ⚠️ Elle enveloppe au besoin : à 390 px le compte prend sa ligne et les deux boutons la
   suivante, plutôt que de se tronquer. `margin-right: auto` pousse les boutons à droite au
   bureau, sans media query — c'est le patron de `.sm-compteur`. */
.tr-zone .tr-barre[b-t7i564u3p4] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
}

.tr-zone .tr-compte[b-t7i564u3p4] {
    margin-right: auto;
    font-size: 13px;
    color: var(--slate);
}

.tr-zone .tr-compte b[b-t7i564u3p4] {
    color: var(--ink);
}

@media (max-width: 768px) {

    /* ── ① LA RANGÉE DEVIENT UNE CARTE DE RÉPARTITION ───────────────────────────────────
       ⭐ Le vocabulaire vient de `doc-card-edit` — le seul patron de SAISIE du dépôt : libellé
       de 11 px AU-DESSUS du champ, plusieurs champs par rangée. Les formes de LECTURE
       (`CrudCardsShell`, `data-label` nu) coûtent un champ par ligne pleine largeur, soit les
       301 px qu'on vient de mesurer.
       ⚠️ Mais on ne copie pas sa GRILLE : `doc-card-edit` édite UNE ligne ; ici on en parcourt
       autant que le document en porte. D'où trois rangées seulement — identité · contexte du
       plafond · la saisie. */
    .tr-zone table.crud-list tr[b-t7i564u3p4] {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-template-areas:
            "des  des  ref"
            "qte  deja reste"
            "sai  sai  sai";
        gap: 4px 8px;
        align-items: end;
        padding: 10px 12px;
        margin-bottom: 10px;
        border: 1px solid var(--line);
        border-radius: var(--r-10);
        background: var(--surface);
    }

    /* ⚠️ `height: auto` neutralise la PROPRIÉTÉ héritée de `.doc-page`, pas sa règle. Sans elle,
       chacune des trois lignes de la grille vaudrait 48 px — c'est le réglage que T-SM2 n'avait
       pu trouver qu'au navigateur, sa première tentative tombant à 174 px au lieu de 114. */
    .tr-zone table.crud-list td[b-t7i564u3p4] {
        display: block;
        height: auto;
        padding: 0;
        border: none;
        background: transparent;
        text-align: left;
        min-width: 0;
    }

    /* Les libellés du patron générique sont repris à la main, cellule par cellule : on les veut
       AU-DESSUS de la valeur, pas à sa gauche. */
    .tr-zone table.crud-list td[b-t7i564u3p4]::before {
        content: none;
    }

    /* ── ② L'IDENTITÉ — elle se reconnaît d'elle-même, aucun libellé ─────────────────────
       ⚠️ Étiqueter « Désignation » et « Référence » coûterait une rangée pour nommer ce que
       personne ne cherche à nommer (leçon T-SM2, ⑤). */
    .tr-zone table.crud-list td.tr-c-des[b-t7i564u3p4] {
        grid-area: des;
        font-weight: 600;
        font-size: 14px;
        line-height: 1.25;
        color: var(--ink);
    }

    .tr-zone table.crud-list td.tr-c-ref[b-t7i564u3p4] {
        grid-area: ref;
        text-align: right;
        font-size: 11.5px;
        color: var(--slate);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* ── ③ LE CONTEXTE DU PLAFOND — trois nombres qui ne se lisent QUE nommés ────────────
       ⚠️⚠️ C'est ici que le défaut coûtait le plus cher : « 100,00 · 0,00 · 100,00 » empilés
       sans un mot, sur une quantité qui engage de l'argent. `Reste` est mis en avant : c'est
       la seule des trois qui borne le geste. */
    .tr-zone table.crud-list td.tr-c-qte[b-t7i564u3p4] { grid-area: qte; }
    .tr-zone table.crud-list td.tr-c-deja[b-t7i564u3p4] { grid-area: deja; }
    .tr-zone table.crud-list td.tr-c-reste[b-t7i564u3p4] { grid-area: reste; }

    .tr-zone table.crud-list td.tr-c-qte[b-t7i564u3p4],
    .tr-zone table.crud-list td.tr-c-deja[b-t7i564u3p4],
    .tr-zone table.crud-list td.tr-c-reste[b-t7i564u3p4] {
        font-size: 12.5px;
        color: var(--ink);
        white-space: nowrap;
    }

    .tr-zone table.crud-list td.tr-c-qte[b-t7i564u3p4]::before,
    .tr-zone table.crud-list td.tr-c-deja[b-t7i564u3p4]::before,
    .tr-zone table.crud-list td.tr-c-reste[b-t7i564u3p4]::before {
        content: attr(data-label);
        display: block;
        font-size: 11px;
        font-weight: 600;
        color: var(--slate);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .tr-zone table.crud-list td.tr-c-reste[b-t7i564u3p4] {
        font-weight: 600;
        color: var(--teal-dark);
    }

    /* ── ④ LA SAISIE — pleine largeur, libellé au-dessus, cible tactile généreuse ────────
       Le champ est la raison d'être de l'écran : il prend toute la rangée. Mesuré avant :
       312×31 px, coincé à droite d'un pseudo-élément vide, sans un mot pour dire ce qu'il
       attend. */
    .tr-zone table.crud-list td.tr-c-sai[b-t7i564u3p4] {
        grid-area: sai;
        margin-top: 2px;
    }

    .tr-zone table.crud-list td.tr-c-sai[b-t7i564u3p4]::before {
        content: attr(data-label);
        display: block;
        font-size: 11px;
        font-weight: 600;
        color: var(--slate);
        margin-bottom: 3px;
    }

    .tr-zone table.crud-list td.tr-c-sai input[b-t7i564u3p4] {
        width: 100%;
        min-height: 40px;
        font-size: 15px;
    }
}

/* ⚠️⚠️ LE SURVOL N'EXISTE PAS AU DOIGT, ET IL RESTE COLLÉ. `.doc-page .crud-list tbody tr:hover td`
   peint la rangée en `--teal-soft` : juste au BUREAU, où le survol annonce un choix imminent.
   Sur un écran tactile, `:hover` demeure sur la dernière carte touchée jusqu'au tap suivant — et
   une carte peinte au milieu d'une liste se lit comme une SÉLECTION alors que rien n'est
   sélectionné. C'est la capture, pas les chiffres, qui l'avait trouvé en T-SM2.
   ⭐ `(hover: none)` cible le POINTEUR, pas la largeur : une fenêtre de bureau réduite garde son
     survol, où il est utile. Borner par `max-width` l'aurait éteint là aussi. */
@media (hover: none) {
    .tr-zone .crud-list tbody tr:hover td[b-t7i564u3p4] {
        background: transparent;
    }
}
