@font-face {
    font-family: 'Nunito';
    src: url('/fonts/Nunito/Nunito-Regular.woff2') format('woff2'), url('/fonts/Nunito/Nunito-Regular.woff') format('woff');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

.cursor-pointer {
    cursor: pointer;
}

@font-face {
    font-family: 'Nunito';
    src: url('/fonts/Nunito/Nunito-Bold.woff2') format('woff2'), url('/fonts/Nunito/Nunito-Bold.woff') format('woff');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

body {
    font-family: 'Nunito', sans-serif;
    font-weight: 400;
    background-color: #ffffff;
    background-image: url("/images/bg3.jpg");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-attachment: fixed;
    min-height: 100vh;
    margin: 0;
}

html.dark-mode body {
    background-image: url("/images/bg3dark.jpg");
}

/* Taille de police globale de l'application - unique bouton de reglage. MudBlazor exprime toutes
   ses tailles de texte en rem (--mud-typography-*-size : body 1rem, grilles et boutons 0.875rem,
   legendes 0.75rem) et app.css, les CSS isolees et login.css font de meme. Changer cette seule
   valeur met donc tout le texte a l'echelle - grilles, dialogues, menus, page de connexion - sans
   deplacer la mise en page, car les paddings, hauteurs de ligne et largeurs de MudBlazor restent
   en px. 100% = taille par defaut du navigateur (16px en general), donc le reglage
   d'accessibilite du navigateur reste respecte. */
html {
    font-size: 112.5%; /* 18px au lieu de 16px : +12.5% */
}

/* Native scrollbars follow the theme. `color-scheme` is the one property the browser acts on
   directly: it repaints every scroll container at once - page, MudBlazor internals, dialogs, the
   per-page .hscroll boxes - plus native control chrome, with no ::-webkit-scrollbar overrides and
   no per-container rules to maintain. data-theme is stamped on <html> before first paint from the
   Theme cookie (App.razor), so there is no light-scrollbar flash on load. */
html {
    color-scheme: light;
}

html[data-theme="dark"] {
    color-scheme: dark;
}

.footer {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    text-align: center;
    padding: 0.35rem 1rem;
    background: var(--mud-palette-background);
    border-top: 1px solid var(--mud-palette-lines-default);
    color: grey;
    font-size: 0.8rem;
}

.dropdown-menu {
    font-size: 0.93rem;
    font-weight: 400;
}

.selected {
    background-color: #82C2E426 !important;
}

.selected-dark {
    background-color: #82C2E426 !important;
}

.mud-datagrid-row.selected .mud-typography {
    color: #1b72be !important;
}

.card {
    margin-bottom: 20px;
}

.small-font {
    font-size: 0.6rem;
}

.mark,
mark {
    padding: 0;
}

.EmailRed .mud-input-control-helper-container.px-2>div>div {
    color: red;
}

.EmailGreen .mud-input-control-helper-container.px-2>div>div {
    color: forestgreen;
}

.EmailGrey .mud-input-control-helper-container.px-2>div>div {
    color: grey;
}

/* "Format is fine but deliverability could not be confirmed" - a catch-all domain, an unknown verdict,
   or the validation service being unreachable. Amber, not red: the address is accepted and saved. */
.EmailAmber .mud-input-control-helper-container.px-2>div>div {
    color: #b26a00;
}

.no-padding {
    padding: 0;
}

.mud-table-container {
    overflow-y: hidden;
}

/* EXCEPTION à la règle ci-dessus, à poser sur TOUTE table dont la zone des lignes est
   bornée : Height="..." sur un MudTable/MudDataGrid, ou un conteneur à hauteur fixe.
   La règle globale suppose que c'est la PAGE qui défile ; dès que la zone des lignes est
   plafonnée, elle ne supprime pas un défilement inutile, elle COUPE les lignes suivantes,
   sans barre ni indice visuel. Symptôme typique : « la liste s'arrête à la 16e ligne ».
   Cas particulièrement grave avec Virtualize, qui se règle sur le scrollTop du conteneur :
   sans défilement, rien au-delà de la première fenêtre n'est jamais rendu.

   .fiche-dossier-panneau reste listé ici : c'est un conteneur (MudPaper), pas une table,
   il habille les tables de la fiche dossier d'un coup. */
.fiche-dossier-panneau .mud-table-container,
.table-scroll-y .mud-table-container {
    overflow-y: auto;
}

.lisdz-actions-cell {
    white-space: nowrap;
    width: 1px;
    justify-content: flex-start !important;
    gap: 4px !important;
}

/* Keep every action-cell control (incl. the nested .mud-menu activator, whose
   inline-flex baseline sits higher) vertically centered with its siblings. */
.lisdz-actions-cell > *,
.lisdz-actions-cell .mud-menu {
    vertical-align: middle;
}

.lisdz-actions-header {
    width: 1px;
    white-space: nowrap;
}

.mud-table-row.paillasse-row-selected,
.mud-table-row.row-selected {
    background-color: #82C2E426 !important;
}

.mud-table-row.paillasse-row-selected .mud-table-cell,
.mud-table-row.row-selected .mud-table-cell {
    background-color: transparent !important;
}

/* Ligne dont le clic vaut selection (recherche patient). Hover="true" ne change que le fond,
   nuance qui se voit mal sur une ligne dense : le texte passe a la couleur primaire pour dire
   que c'est la ligne entiere qui selectionne, et non une cellule en particulier.
   Cible aussi les descendants : MudHighlighter pose ses propres balises, qui n'heriteraient pas
   d'une couleur posee sur le seul tr. La cellule des cases a cocher est exclue - y recolorer une
   case non cochee la ferait passer pour cochee. */
.mud-table-row.ligne-cliquable:hover .mud-table-cell:not(.cellule-non-cliquable),
.mud-table-row.ligne-cliquable:hover .mud-table-cell:not(.cellule-non-cliquable) * {
    color: var(--mud-palette-primary);
}

.mud-table-dense * .mud-table-row .mud-table-cell {
    padding-inline-start: 14px;
    padding-inline-end: 6px;
}

html[data-theme="dark"] .mud-table-striped .mud-table-container .mud-table-root .mud-table-body:not(.mud-table-body-virtualized) .mud-table-row:nth-of-type(odd) {
    background-color: #1e1e1e !important;
}

.mud-toolbar {
    height: 48px !important;
    gap: 6px;
}

/* Export buttons (Excel/PDF, MudIconStatusButton): quarter of the toolbar gap. The negative margin
   subtracts from the 6px above rather than replacing it - `gap` cannot be overridden per item. */
.lisdz-export-btn {
    margin-left: -4.5px;
}

.mud-grid-spacing-xs-2>.mud-grid-item {
    padding-top: 0px;
}

/* Une alerte ANNONCE ce qui suit - elle ne doit pas coller au premier champ.
   La règle ci-dessus supprime toute gouttière verticale dans les grilles Spacing="2" : un
   MudAlert posé dans un MudItem touchait donc le champ suivant, et le bandeau se lisait comme
   la première ligne du formulaire au lieu de l'introduire. Le décalage est donné ici une fois
   pour toutes, plutôt que rappelé à la main sur chaque alerte - il l'était dans une douzaine
   d'écrans, avec quatre valeurs différentes, et oublié dans une quinzaine d'autres.
   Rien sur la dernière alerte du bloc : elle ne présente plus rien, elle conclut, et une marge
   basse ne ferait qu'éloigner les boutons.
   Une classe mb-N / my-N posée à la main reste prioritaire - les utilitaires d'espacement
   MudBlazor sont en !important - ce qui laisse régler les cas particuliers au cas par cas. */
.mud-grid-item:not(:last-child) > .mud-alert,
.mud-dialog-content > .mud-alert:not(:last-child) {
    margin-bottom: 12px;
}

.mud-divider.mud-divider-fullwidth {
    margin-top: 16px;
    margin-bottom: 16px;
}

/* Un trait DANS UN MENU n'est pas un séparateur de section de page. FullWidth étant le type par
   défaut de MudDivider, la règle ci-dessus s'appliquait aussi aux menus et creusait 32 px entre
   deux entrées denses - plus haut que les entrées elles-mêmes. Ici le trait ne fait que grouper,
   quelques pixels suffisent.
   Trois classes (0,3,0) pour passer devant la règle globale (0,2,0). */
.mud-menu-list .mud-divider.mud-divider-fullwidth {
    margin-top: 4px;
    margin-bottom: 4px;
}

/* mud-grid-item: margin:0  and  mud-grid-spacing-xs-N: margin:-Npx
   both override spacing utilities at equal specificity (0,1,0).
   Double-class rules win (0,2,0) and restore the intended values. */

/* mt-N / mb-N / my-N on MudItem */
.mud-grid-item.mt-1 {
    margin-top: 4px;
}

.mud-grid-item.mt-2 {
    margin-top: 8px;
}

.mud-grid-item.mt-3 {
    margin-top: 12px;
}

.mud-grid-item.mt-4 {
    margin-top: 16px;
}

.mud-grid-item.mt-5 {
    margin-top: 20px;
}

.mud-grid-item.mb-1 {
    margin-bottom: 4px;
}

.mud-grid-item.mb-2 {
    margin-bottom: 8px;
}

.mud-grid-item.mb-3 {
    margin-bottom: 12px;
}

.mud-grid-item.mb-4 {
    margin-bottom: 16px;
}

.mud-grid-item.my-1 {
    margin-top: 4px;
    margin-bottom: 4px;
}

.mud-grid-item.my-2 {
    margin-top: 8px;
    margin-bottom: 8px;
}

.mud-grid-item.my-3 {
    margin-top: 12px;
    margin-bottom: 12px;
}

.mud-grid-item.my-4 {
    margin-top: 16px;
    margin-bottom: 16px;
}

/* mt-N / mb-N / my-N on MudGrid (mud-grid-spacing-xs-N sets margin:-Npx shorthand) */
.mud-grid.mt-1 {
    margin-top: 4px;
}

.mud-grid.mt-2 {
    margin-top: 8px;
}

.mud-grid.mt-3 {
    margin-top: 12px;
}

.mud-grid.mt-4 {
    margin-top: 16px;
}

.mud-grid.mb-1 {
    margin-bottom: 4px;
}

.mud-grid.mb-2 {
    margin-bottom: 8px;
}

.mud-grid.mb-3 {
    margin-bottom: 12px;
}

.mud-grid.mb-4 {
    margin-bottom: 16px;
}

.mud-grid.my-1 {
    margin-top: 4px;
    margin-bottom: 4px;
}

.mud-grid.my-2 {
    margin-top: 8px;
    margin-bottom: 8px;
}

.mud-grid.my-3 {
    margin-top: 12px;
    margin-bottom: 12px;
}

.mud-grid.my-4 {
    margin-top: 16px;
    margin-bottom: 16px;
}

.mud-input.mud-input-outlined .mud-input-outlined-border {
    border-color: rgba(181, 184, 192, 0.5);
}

.mud-icon-root path {
    stroke-width: 1px;
}

.mud-elevation-1 {
    box-shadow: 0 4px 5px rgba(0, 0, 0, 0.05) !important;
}

.custom-small-icon .mud-icon-root {
    font-size: 16px !important;
}

.custom-rounded .mud-input-outlined-border {
    border-radius: 8px !important;
}

/* Square-ish 8px corners for FAB action buttons, matching the .custom-rounded fields */
.custom-rounded-fab.mud-button-root {
    border-radius: 8px !important;
}


/* Adjust hover earea of icon */
.mud-icon-button {
    padding: 5px;
}

/* Adjust icon size */
.small-menu-item .mud-icon-root {
    font-size: 1.2rem !important;
}

/* Split-button dropdown arrow (MudButtonGroup: action button + MudMenu).
   Sizing the .mud-menu wrapper alone changes nothing - the activator button inside keeps its
   own padding and overflows it, which is why the cap stayed as wide as the action button.
   The width has to be taken off the button itself. */
.lisdz-split-arrow .mud-icon-button {
    padding: 0 !important;
    min-width: 0;
    width: 100%;
    height: 100%;
}

.lisdz-split-arrow .mud-icon-root {
    font-size: 1.15rem;
    width: 1.15rem;
    height: 1.15rem;
}

/* Adjust size of user profile name */
.mud-typography {
    font-size: 0.9rem !important;
}




/* Fixed Width */
.fixed-menu-width {
    width: 250px !important;
    min-width: 250px !important;
    max-width: 250px !important;
}

/* Menu de NAVIGATION (MenuBar) uniquement - pose apres .fixed-menu-width pour la surcharger.
   Ses entrees portent un badge compteur : « Postes de paillasse » suivi de « 164 » depassait
   la largeur fixe de 250 px et le badge retombait sous le libelle. Le popover se cale donc
   sur son contenu, avec 250 px de plancher (aspect inchange pour les menus courts) et un
   plafond qui evite qu'un libelle aberrant n'etale le menu sur tout l'ecran.
   Les menus d'actions de ligne (MudRowActionsMenu) gardent la largeur fixe. */
.nav-menu-width {
    width: max-content !important;
    min-width: 250px !important;
    max-width: 360px !important;
}

/* Menu top bottom padding */
.fixed-menu-width .mud-list {
    padding-top: 4px !important;
    padding-bottom: 4px !important;
}



.permission-menu .mud-button-icon-start .mud-svg-icon {
    color: #4C5257;
}

.mud-menu.permission-menu .mud-button-icon-end svg {
    fill: var(--mud-palette-text-primary) !important;
}

.permission-item-menu .mud-icon-root {
    font-size: 1.2rem !important;
}

/* Top-level menu icon colors outside the MudBlazor Color enum (Rapports / Tableau de bord) */
.menu-icon-pink .mud-icon-root {
    color: #e91e63 !important;
}

.menu-icon-teal .mud-icon-root {
    color: #009688 !important;
}

/* Privilèges : violet, hors énumération Color de MudBlazor comme les deux ci-dessus. Même
   teinte que le bouton « permissions » de la fiche utilisateur et que le titre du dialogue
   d'édition - les trois désignent le même objet. */
.menu-icon-purple .mud-icon-root {
    color: #9c27b0 !important;
}

.mud-data-grid .mud-table-head .mud-table-cell {
    font-weight: bold !important;
}

/* FLÈCHE DE TRI COLLÉE AU TITRE, PARTOUT (2026-09-14). MudBlazor étale l'en-tête d'une colonne :
   titre à 100 % de la cellule, flèche de tri au bord opposé (space-between). Sur une colonne large,
   la flèche finissait à l'autre bout de la colonne, loin du titre qu'elle trie. Le titre prend
   désormais sa largeur, et la flèche le suit.

   SAUF les en-têtes CENTRÉS - span « text-align:center » du HeaderTemplate, HeaderClass
   « justify-center », colonne Actions : leur titre a besoin de toute la largeur pour se centrer, et
   réduit à la sienne il se collerait à gauche. Ils gardent le comportement de MudBlazor. Les
   en-têtes alignés à droite sont repris juste après (ligne inversée). */
.mud-data-grid th:not(.justify-center):not(.lisdz-actions-header) .column-header:not(:has(span[style*="text-align:center"])):not(:has(span[style*="text-align: center"])) {
    justify-content: flex-start;
}

.mud-data-grid th:not(.justify-center):not(.lisdz-actions-header) .column-header:not(:has(span[style*="text-align:center"])):not(:has(span[style*="text-align: center"])) .sortable-column-header {
    width: auto;
}

/* EN-TÊTE ALIGNÉ À DROITE, PARTOUT (2026-09-14). L'en-tête d'une colonne MudDataGrid est une ligne
   flex : le titre (span.sortable-column-header, largeur 100 %) puis span.column-options, qui porte
   le bouton de tri - INVISIBLE (opacity 0) tant que la colonne n'est ni triée ni survolée, mais qui
   garde sa place (une trentaine de pixels) à droite. Un titre aligné à droite s'arrêtait donc avant
   le bord, et ne tombait plus au-dessus des montants de sa colonne.

   Correctif : quand le titre est aligné à droite, la ligne s'inverse - le titre touche le bord droit
   et la flèche de tri apparaît à sa GAUCHE, disposition usuelle des colonnes numériques. Reconnu sur
   le span du HeaderTemplate (style « text-align:right », la façon documentée d'aligner un en-tête)
   ou sur HeaderClass="justify-end" : aucune des colonnes existantes n'a à changer. */
.mud-data-grid .mud-table-cell .column-header:has(span[style*="text-align:right"]),
.mud-data-grid .mud-table-cell .column-header:has(span[style*="text-align: right"]),
.mud-data-grid th.justify-end .column-header {
    flex-direction: row-reverse;
    /* En row-reverse, flex-start est le bord DROIT : titre et flèche se serrent ensemble contre lui.
       Le space-between de MudBlazor, conservé, envoyait la flèche au bord GAUCHE de la colonne, loin
       de son titre. */
    justify-content: flex-start;
}

/* Le titre prend sa largeur, pas toute la cellule : à 100 % (MudBlazor), il repoussait la flèche
   au bord opposé. */
.mud-data-grid .mud-table-cell .column-header:has(span[style*="text-align:right"]) .sortable-column-header,
.mud-data-grid .mud-table-cell .column-header:has(span[style*="text-align: right"]) .sortable-column-header,
.mud-data-grid th.justify-end .column-header .sortable-column-header {
    width: auto;
}

/* L'écart titre / flèche change de côté avec elle : MudBlazor le pose à gauche de la flèche. */
.mud-data-grid .mud-table-cell .column-header:has(span[style*="text-align:right"]) .sort-direction-icon,
.mud-data-grid .mud-table-cell .column-header:has(span[style*="text-align: right"]) .sort-direction-icon,
.mud-data-grid th.justify-end .column-header .sort-direction-icon {
    margin-left: 0;
    margin-inline-start: 0;
    margin-right: 4px;
    margin-inline-end: 4px;
}

/* HeaderClass="justify-end" n'aligne que la cellule, pas le titre (voir la mémoire d'alignement) :
   on aligne le titre ici, pour que la classe tienne enfin ce qu'elle annonce. */
.mud-data-grid th.justify-end .column-header .sortable-column-header {
    text-align: right;
}

/* Même défaut sur MudTable : MudTableSortLabel est un inline-flex « texte puis flèche », et la
   flèche invisible (opacity 0, 18 px plus ses marges) garde sa place après le texte. Dans un MudTh
   aligné à droite, le libellé s'arrêtait donc avant le bord (NormeEditor : MIN, MAX, critiques).
   La flèche passe à gauche du texte. */
.mud-table-head th[style*="text-align:right"] .mud-table-sort-label,
.mud-table-head th[style*="text-align: right"] .mud-table-sort-label {
    flex-direction: row-reverse;
}

/* Piste d'audit : la grille est déjà en mode dense, mais deux de ses colonnes (Action,
   Détails) affichent des puces, et ce sont les marges du MudChipSet - pas le remplissage
   des cellules - qui rallongeaient chaque ligne d'une bonne dizaine de pixels. On resserre
   donc le vertical là où il se perd, sans toucher au confort horizontal ni au reste des
   grilles de l'application (classe portée par le seul AuditLogViewer). */
/* Piste d'audit, page plein écran : la page ne défile JAMAIS - ce qui déborde défile dans
   la zone des lignes, sous un en-tête qui reste visible, et le pagineur reste toujours à
   l'écran. MAX-hauteur et non hauteur : une hauteur fixe ne sait pas rétrécir, elle laissait
   un grand blanc quand la journée ne comptait que trois actions.

   Les 420px = tout ce qui n'est pas la zone des lignes : barre d'application et menu (~91),
   titre de page (~60), panneau de filtres et sa marge (~90), barre d'outils de la grille et
   l'en-tête de colonnes (~50), puis en bas le pagineur (~52) et le pied de page (~32) - plus
   la marge que ce décompte sous-estimait, mesurée à une ligne près sur l'écran réel.
   Le dialogue n'est pas concerné : il passe sa propre hauteur et n'a pas de page pour
   défiler - d'où le préfixe .audit-page. */
.audit-page .audit-grid .mud-table-container {
    max-height: calc(100vh - 420px);
}

/* 8px : au-dessus des 6px de MudBlazor en mode dense. La compression initiale (1px) partait
   d'un diagnostic faux - la hauteur des rangées venait de l'IP rendue en bloc dans la colonne
   « Par », pas du remplissage des cellules. Cette cause corrigée, il ne reste aucune raison
   de serrer : les rangées portent des puces, qui ont besoin d'air autour d'elles. */
.audit-grid .mud-table-cell {
    padding-top: 8px !important;
    padding-bottom: 8px !important;
}

.audit-grid .mud-chipset {
    margin: 0 !important;
}

/* Seul le VERTICAL est resserré. L'écart horizontal reste celui de MudBlazor (4px de
   chaque côté, donc 8px entre deux puces) : le mettre à zéro collait les puces de la
   colonne Détails les unes aux autres, on ne voyait plus où l'une finissait. */
.audit-grid .mud-chipset .mud-chip {
    margin: 1px 4px !important;
    height: 20px;
}

.loginmenu {
    color: var(--mud-palette-text-primary) !important;
}

/* Pied de grille : « Lignes par page », le compteur « 1-20 sur 98 » et les flèches forment UN
   bloc, calé à droite. Par défaut le libellé se retrouvait au centre, séparé de la navigation
   qu'il commande - on lisait donc le réglage d'un côté et son effet de l'autre.

   Le spacer de MudBlazor est déclaré flex:1 1 100%, ce qui le laisse gonfler entre les éléments ;
   ramené à `auto`, il ne pousse plus que ce qu'il faut et le groupe reste soudé. Règle globale :
   toutes les grilles et tous les tableaux de l'application ont le même pied. */
.mud-table-pagination-toolbar {
    justify-content: flex-end;
}

.mud-table-pagination-spacer {
    flex: 1 1 auto;
}

/* Default (Light Mode) */
.nested-tray-background {
    background-color: var(--mud-palette-background-gray) !important;
    /* resolves to #f5f5f5 in light palette */
}

/* Dark Mode Override - stronger specificity and palette var */
body.mud-theme-dark .nested-tray-background,
.mud-theme-dark .nested-tray-background {
    background-color: var(--mud-palette-background-gray) !important;
    /* resolves to #222736 in dark palette */
}

/* Ensure MudGrid/MudDataGrid internals don't override the background */
.nested-tray-background.mud-grid,
.nested-tray-background .mud-grid-root,
.nested-tray-background .mud-paper,
.nested-tray-background .mud-table-container {
    background-color: inherit !important;
}

/* Disable hover effect ONLY for the expanded detail row */
.mud-table-hover .mud-table-row:has(.mud-table-child-content):hover {
    background-color: transparent !important;
}

/* Keep the hover highlight visible even on colored rows (RowStyleFunc inline background).
   Inline styles beat MudBlazor's stylesheet :hover, so force it with the same hover variable.
   The more-specific detail-row rule above still wins for expanded child rows. */
.mud-table-hover .mud-table-row:hover {
    background-color: var(--mud-palette-table-hover) !important;
}

/* Global tab margin - gives the tab strip breathing room from surrounding content */
.mud-tabs {
    margin-top: 4px;
    margin-bottom: 4px;
}

/* Mask text as password dots without using type=password (prevents Chrome autofill popup) */
.pwd-mask input {
    -webkit-text-security: disc;
}

/* Simple dialogs with only a few fields - suppress both the content and dialog-level scrollbars */
.no-overflow-content {
    overflow: hidden !important;
}

.no-dialog-scroll {
    overflow-y: hidden !important;
}

/* Align icon + text vertically in all dialog titles */
.mud-dialog-title .mud-typography-h6 {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Two requirements at once: same height on both tabs (no jump) AND no inner scrollbar.
   So the floor is set to the TALLER tab (Fiche Partenaire, ~600px of dense fields) and
   there is no ceiling - the shorter Tarification tab pads out to the same height, and
   neither tab is ever clipped. Fixed px, not vh: the content height does not scale with
   the viewport, so a vh floor would still clip on a short screen and over-pad on a tall one. */
.fixed-dialog-content {
    min-height: 860px;
    overflow-y: visible;
    display: flex;
    flex-direction: column;
}

/* MudBlazor caps .mud-dialog at the viewport and scrolls .mud-dialog-content, which
   would reinstate the inner scrollbar. Lift the cap for this dialog only and let the
   overlay scroll instead, so a tall dialog stays fully reachable on a short screen.

   margin:auto (not align-items:center) does the vertical centering: it centres the
   dialog while it fits, but yields instead of clipping once it is taller than the
   overlay - align-items:center would push the top out of reach above the scroll area. */
.mud-dialog:has(.fixed-dialog-content) {
    max-height: none;
    margin: auto;
}

.mud-dialog-container:has(.fixed-dialog-content) {
    overflow-y: auto;
    align-items: flex-start;
    padding: 24px 0;
}

/* Tab bodies inside that shell need their own breathing room: the panel content is
   flush against the tab strip and the dialog edges otherwise. The top value must stay
   in step with the global .mud-tabs-panels rule below: this selector is more specific
   and silently replaced its 16px with 4px, gluing the first row to the tab strip. */
.fixed-dialog-content .mud-tabs-panels {
    padding: 16px 4px 8px;
}

/* Make tabs fill available height */
.fixed-tabs {
    flex: 1 1 auto;
    min-height: 0;
    /* allow children to size correctly */
}

/* Onglets répartis sur toute la largeur - posé par le composant DialogTabs, jamais à la main.
   MudTabs n'offre aucune option pour cela : Centered ne fait que centrer, MinimumTabWidth ne
   pose qu'un plancher. Deux règles de MudBlazor 9.7 gardent les onglets groupés à gauche :
       .mud-tabs-tabbar-wrapper { width: max-content }
       .mud-tab                 { flex-shrink: 0 }
   Sélecteurs plus spécifiques que ceux de la librairie, donc aucun !important. */
.justified-tabs .mud-tabs-tabbar-content .mud-tabs-tabbar-wrapper {
    width: 100%;
}

/* Le partage se pose sur les ENFANTS DIRECTS du wrapper, pas sur .mud-tab : MudBlazor
   enveloppe chaque onglet dans un .mud-tooltip-root, ou un .d-inline-block quand l'onglet
   utilise TabContent au lieu de Text. Ce sont ces div-là les éléments flex - poser flex sur
   .mud-tab ne produit rien, et width:auto neutralise le width:fit-content en style inline
   que MudBlazor met sur la variante TabContent.

   flex-basis auto, et non 0 : avec 0 tous les onglets prennent exactement la meme largeur
   quel que soit leur titre, et le plus long passe a la ligne des qu'il approche sa part.
   En auto chacun part de sa largeur naturelle et seul l'espace LIBRE est partage, donc la
   barre remplit toujours le dialogue mais un titre long garde la place qu'il lui faut. */
.justified-tabs .mud-tabs-tabbar-wrapper > * {
    flex: 1 1 auto;
    width: auto;
    white-space: nowrap;
}

.justified-tabs .mud-tabs-tabbar-wrapper > * > .mud-tab {
    width: 100%;
}

/* Compteur dans un titre d'onglet - posé par le composant TabTitre, à utiliser à la place de
   MudBadge, qui met sa pastille en absolu sur un coin et n'a, autour d'un texte nu, que le choix
   entre écrire sur les lettres et flotter au-dessus. Posée en ligne, la pastille suit le texte et
   la barre d'onglets ne la rogne pas. min-width = height pour rester ronde à un chiffre et
   s'allonger en gélule au-delà. */
.tab-compteur {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    margin-left: 6px;
    border-radius: 9px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    color: #fff;
    background-color: var(--mud-palette-info);
}

/* Même pastille en orange : l'onglet ne fait plus que compter, il demande une action. Une
   seconde pastille à côté de la bleue ferait passer le titre à la ligne. */
.tab-compteur-alerte {
    background-color: var(--mud-palette-warning);
}

/* Left-tab strip: left-align all tab buttons */
.guichet-tabs .mud-tab {
    justify-content: flex-start !important;
    padding-left: 16px !important;
}

/* Override MudBlazor's flex panels container so the active panel fills full width */
.guichet-tabs .mud-tabs-panels.mud-tabs-vertical {
    display: block;
}

/* Espace global sous la barre d'onglets, en PADDING et non en marge : une marge est hors du
   fond du panneau et laissait une bande transparente (fond de page visible) sur les pages où
   les onglets posent directement sur le fond décoré. Les utilitaires de retrait (pa-N, pt-N)
   passés via TabPanelsClass, en !important, gardent la priorité quand une page choisit son
   propre retrait.

   ATTENTION : ne jamais écrire "pa-*" suivi d'un slash dans ce commentaire. La séquence ferme
   le commentaire au milieu de la phrase, le reste du texte devient un sélecteur invalide et le
   navigateur jette la règle qui suit avec lui. C'est exactement ce qui a supprimé ce retrait
   sur toutes les pages à onglets entre le 11/08/2026 et aujourd'hui. */
.mud-tabs-panels {
    padding-top: 16px;
}

/* Selector-only tab strip (tabs used purely as a filter, no panel body):
   hide the empty .mud-tabs-panels container so it doesn't leave dead space */
.selector-tabs .mud-tabs-panels {
    display: none;
}

/* Onglets-filtres a badge compteur (Analyseurs, Paiement) - badge QUI TIENT DANS L'ONGLET.
   A poser sur tout MudTabs dont les MudTabPanel portent un BadgeData.
   MudBlazor pose le badge en position absolue sur un .mud-badge-root de largeur nulle
   (« inset: auto auto calc(100% - 12px) calc(100% - 12px) »). L'onglet centre donc son contenu
   SANS compter le badge, qui part vers la droite : a quatre ou cinq chiffres il franchissait la
   bordure de l'onglet. Rendu au flux, le badge est mesure comme le reste, l'onglet s'elargit
   pour lui et le nombre exact tient toujours a l'interieur.
   Le selecteur ne descend pas jusqu'a .mud-tab : selector-tabs masque deja .mud-tabs-panels,
   le seul badge vivant sous .tabs-badge-inline est donc celui d'un onglet.
   DEUX couches a ramener au flux, pas une : MudBadge rend
   .mud-badge-root > .mud-badge-wrapper (absolu, 100 % x 100 % du root) > .mud-badge.
   Rendre le seul .mud-badge statique le laisse enferme dans un wrapper absolu de taille nulle,
   et il deborde toujours. */
/* Le root reste inline-block : pose sur la ligne de base, il fait 30 px de haut pour un badge
   de 20 px et la pastille descend sous l'axe du texte. En flex centre il fait la hauteur du
   badge, et align-items:center de l'onglet aligne icone, libelle et nombre sur le meme axe. */
.tabs-badge-inline .mud-badge-root {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}

.tabs-badge-inline .mud-badge-wrapper {
    position: static;
    display: inline-flex;
    width: auto;
    height: auto;
    pointer-events: auto;
}

.tabs-badge-inline .mud-badge {
    position: static;
    inset: auto;
}

/* Libelle et nombre sur une seule ligne : l'onglet s'elargit, il ne se casse pas en deux. */
.tabs-badge-inline .mud-tab {
    white-space: nowrap;
}

.guichet-tabs .mud-tab-panel {
    width: 100%;
}

/* Ensure each tab panel fills and scrolls instead of resizing dialog */
.fixed-tab-panel {
    height: 100%;
    overflow: auto;
}

/* EN-TETE DE TABLE GRIS, PARTOUT (2026-09-11). Regle globale : MudDataGrid, MudTable et
   MudSimpleTable (dont le thead est ecrit a la main et ne porte pas .mud-table-head). Avant,
   seule la grille l'avait d'office et un MudTable devait poser .soft-header ; la classe reste
   acceptee mais n'est plus necessaire. */
.mud-table .mud-table-head,
.mud-table .mud-table-head .mud-table-cell,
.mud-simple-table thead th {
    background-color: #F5F5F5 !important;
}

html[data-theme="dark"] .mud-table .mud-table-head,
html[data-theme="dark"] .mud-table .mud-table-head .mud-table-cell,
html[data-theme="dark"] .mud-simple-table thead th {
    background-color: #2A2A2A !important;
}

/* Densite intermediaire. MudTable n'expose qu'un booleen : Dense=false donne 16px de
   remplissage vertical (ligne d'environ 53px), Dense=true 6px (environ 33px). A poser AVEC
   Dense="true" : 11px placent la ligne a mi-chemin, sans !important car le selecteur porte
   deux classes sur l'element racine la ou MudBlazor n'en pose qu'une. */
.table-demi-dense.mud-table-dense * .mud-table-row .mud-table-cell {
    padding-top: 11px;
    padding-bottom: 11px;
}

/* ============================================================
   BLAZOR RECONNECT DIALOG
   Écrit à la main volontairement : ce balisage vit dans App.razor et c'est le
   runtime JS de Blazor qui l'affiche pendant que le circuit est coupé, donc aucun
   composant Razor/MudBlazor ne peut le rendre. Les couleurs, la police et le rayon
   sont malgré tout lus dans le thème via les variables CSS de MudBlazor (émises par
   MudThemeProvider sur :root et conservées dans le DOM après la coupure), donc la
   carte suit MainTheme et le mode sombre toute seule. Les valeurs littérales ne
   servent que de repli si le provider n'a jamais été rendu (page Login, échec de
   prérendu). Voir docs/frosted-glass-archive.md pour l'ancienne version figée.
   ============================================================ */

#components-reconnect-modal {
    display: none;
}

#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: flex;
}

.reconnect-overlay {
    position: fixed;
    inset: 0;
    z-index: 99999;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.reconnect-card {
    font-family: var(--mud-typography-default-family, 'Nunito', sans-serif);
    background-color: var(--mud-palette-surface, #ffffff);
    color: var(--mud-palette-text-primary, #4C5257);
    border-radius: var(--mud-default-borderradius, 12px);
    padding: 1.25rem 2rem 1.25rem;
    max-width: 420px;
    width: calc(100% - 2rem);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

/* Fond et texte suivent le thème ; seule l'ombre reste plus dense en mode sombre. */
html[data-theme="dark"] .reconnect-card {
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}

.reconnect-brand {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--mud-palette-primary, #00A355);
    margin-bottom: 0.75rem;
    text-transform: uppercase;
}

.reconnect-content {
    display: none;
    flex-direction: column;
    align-items: center;
    width: 100%;
}

#components-reconnect-modal.components-reconnect-show .reconnect-content-connecting {
    display: flex;
}

#components-reconnect-modal.components-reconnect-failed .reconnect-content-failed {
    display: flex;
}

#components-reconnect-modal.components-reconnect-rejected .reconnect-content-rejected {
    display: flex;
}

.reconnect-title {
    font-size: 1rem;
    font-weight: 700;
    margin: 0.75rem 0 0;
}

.reconnect-subtitle {
    font-size: 0.875rem;
    margin: 0.25rem 0 0.5rem;
    opacity: 0.75;
    line-height: 1.5;
}

.reconnect-spinner {
    width: 52px;
    height: 52px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.reconnect-spinner-ring {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: 3px solid rgba(var(--mud-palette-primary-rgb, 0, 163, 85), 0.2);
    border-top-color: var(--mud-palette-primary, #00A355);
    animation: reconnect-spin 0.85s linear infinite;
}

@keyframes reconnect-spin {
    to {
        transform: rotate(360deg);
    }
}

.reconnect-icon {
    width: 52px;
    height: 52px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.reconnect-icon svg {
    width: 44px;
    height: 44px;
}

.reconnect-icon-warning {
    color: var(--mud-palette-warning, #FF6F00);
}

.reconnect-icon-error {
    color: var(--mud-palette-error, #F44336);
}

.reconnect-btn {
    margin-top: 0.25rem;
    padding: 0.55rem 1.5rem;
    font-family: var(--mud-typography-default-family, 'Nunito', sans-serif);
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--mud-palette-primary-text, #ffffff) !important;
    background-color: var(--mud-palette-primary, #00A355);
    border: none;
    border-radius: var(--mud-default-borderradius, 8px);
    cursor: pointer;
    transition: background-color 0.2s ease;
}

/* !important conservé : le runtime Blazor pose ses propres styles par défaut sur
   les enfants de #components-reconnect-modal. */
#components-reconnect-modal .reconnect-btn {
    background-color: var(--mud-palette-primary, #00A355) !important;
    color: var(--mud-palette-primary-text, #ffffff) !important;
}

#components-reconnect-modal .reconnect-btn:hover {
    background-color: var(--mud-palette-primary-darken, #0d8f6e) !important;
    color: var(--mud-palette-primary-text, #ffffff) !important;
}

#components-reconnect-modal .reconnect-btn:active {
    background-color: var(--mud-palette-primary-darken, #0b7a5e) !important;
    color: var(--mud-palette-primary-text, #ffffff) !important;
    opacity: 0.85;
}

#components-reconnect-modal .reconnect-btn:focus-visible {
    outline: 2px solid var(--mud-palette-primary, #00A355);
    outline-offset: 3px;
}

#components-reconnect-modal button {
    margin: 20px auto !important;
}

/* Encrypted settings fields: placeholder shown in primary colour, not faded */
.encrypted-field input::placeholder,
.encrypted-field .mud-input-slot::placeholder {
    color: var(--mud-palette-primary) !important;
    opacity: 1 !important;
}

/* ============================================================
   BLAZOR ERROR UI (Unhandled Exceptions)
   Même contrainte que la carte de reconnexion ci-dessus : balisage statique
   d'App.razor affiché par le runtime JS quand le circuit est mort, donc écrit à la
   main mais alimenté par les variables CSS du thème MudBlazor.
   ============================================================ */
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: 0 !important;
    z-index: 1000000 !important;
    background-color: rgba(0, 0, 0, 0.45) !important;
    backdrop-filter: blur(4px) !important;
    -webkit-backdrop-filter: blur(4px) !important;
    box-sizing: border-box;
}

.blazor-error-container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 90%;
    max-width: 550px;
    margin: 0 auto;
    background: color-mix(in srgb, var(--mud-palette-surface, #ffffff) 85%, transparent);
    backdrop-filter: blur(12px) saturate(180%);
    -webkit-backdrop-filter: blur(12px) saturate(180%);
    border: 1px solid color-mix(in srgb, var(--mud-palette-error, #F44336) 25%, transparent);
    border-radius: var(--mud-default-borderradius, 16px);
    padding: 14px 20px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15),
        inset 0 1px 0 rgba(255, 255, 255, 0.6);
    font-family: var(--mud-typography-default-family, 'Nunito', sans-serif);
    animation: blazor-error-slide-down 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.blazor-error-content-left {
    display: flex;
    align-items: center;
    gap: 12px;
}

@keyframes blazor-error-slide-down {
    from {
        transform: translateY(-30px);
        opacity: 0;
    }

    to {
        transform: translateY(0);
        opacity: 1;
    }
}

/* Le fond suit --mud-palette-surface ; on renforce seulement bordure et ombre. */
html[data-theme="dark"] .blazor-error-container {
    border: 1px solid color-mix(in srgb, var(--mud-palette-error, #F44336) 35%, transparent);
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45),
        inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.blazor-error-container {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
}

.blazor-error-svg {
    width: 24px;
    height: 24px;
    color: var(--mud-palette-error, #F44336);
    flex-shrink: 0;
}

.blazor-error-message {
    color: var(--mud-palette-text-primary, #4C5257);
    font-size: 0.9rem;
    font-weight: 700;
    flex-grow: 1;
    line-height: 1.4;
    text-align: left;
}

.blazor-error-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}

.blazor-error-actions .reload {
    position: relative !important;
    right: auto !important;
    top: auto !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--mud-palette-error, #F44336);
    color: var(--mud-palette-error-text, #ffffff) !important;
    font-weight: 700;
    font-size: 0.8rem;
    padding: 6px 14px;
    border-radius: var(--mud-default-borderradius, 8px);
    text-decoration: none !important;
    transition: background-color 0.2s ease, transform 0.1s ease;
    box-shadow: 0 2px 4px rgba(var(--mud-palette-error-rgb, 244, 67, 54), 0.2);
}

.blazor-error-actions .reload:hover {
    background-color: var(--mud-palette-error-darken, #dc2626);
    transform: translateY(-1px);
}

.blazor-error-actions .reload:active {
    background-color: var(--mud-palette-error-darken, #b91c1c);
    transform: translateY(0);
    opacity: 0.85;
}

.blazor-error-actions .dismiss {
    position: relative !important;
    right: auto !important;
    top: auto !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    color: var(--mud-palette-text-secondary, #718096) !important;
    border-radius: 50%;
    cursor: pointer;
    text-decoration: none !important;
    font-size: 0.85rem;
    font-weight: bold;
    transition: background-color 0.2s ease, color 0.2s ease;
}

.blazor-error-actions .dismiss:hover {
    background-color: var(--mud-palette-action-default-hover, rgba(0, 0, 0, 0.05));
    color: var(--mud-palette-text-primary, #1a202c) !important;
}

/* ------------------------------------------------------------
   Variante "carte centrée" du bandeau, réservée à #blazor-error-ui :
   même gabarit que la carte de reconnexion / "Session expirée"
   (420px, centrée, marque / icône / titre / sous-titre / bouton).
   Le panneau récupérable de MainLayout utilisait autrefois le bandeau
   horizontal ; il est passé au composant StatusPanel, donc seule cette
   variante carte est encore rendue.
   ------------------------------------------------------------ */
#blazor-error-ui .blazor-error-container {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0;
    width: calc(100% - 2rem);
    max-width: 420px;
    border-radius: var(--mud-default-borderradius, 12px);
    padding: 1.25rem 2rem;
    animation: blazor-error-card-in 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

/* L'animation du bandeau utilise translateY et écraserait le centrage. */
@keyframes blazor-error-card-in {
    from {
        transform: translate(-50%, calc(-50% - 20px));
        opacity: 0;
    }

    to {
        transform: translate(-50%, -50%);
        opacity: 1;
    }
}

#blazor-error-ui .blazor-error-brand {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--mud-palette-primary, #00A355);
    margin-bottom: 0.75rem;
    text-transform: uppercase;
}

/* svg 44px dans une boîte de 52px : équivalent du .reconnect-icon. */
#blazor-error-ui .blazor-error-svg {
    width: 44px;
    height: 44px;
    margin: 4px 0;
}

#blazor-error-ui .blazor-error-message {
    flex-grow: 0;
    text-align: center;
    font-size: 1rem;
    margin: 0.75rem 0 0;
}

#blazor-error-ui .blazor-error-submessage {
    font-size: 0.875rem;
    margin: 0.25rem 0 0.5rem;
    opacity: 0.75;
    line-height: 1.5;
    color: var(--mud-palette-text-primary, #4C5257);
}

/* Bouton au gabarit du .reconnect-btn, mais rouge (accent d'erreur).
   Marges 20px haut/bas comme la règle "#components-reconnect-modal button"
   qui donne sa hauteur à la carte "Session expirée". */
#blazor-error-ui .blazor-error-actions {
    margin: 20px auto;
    justify-content: center;
}

#blazor-error-ui .blazor-error-actions .reload {
    font-size: 0.875rem;
    padding: 0.55rem 1.5rem;
}

/* StatusPanel (états erreur / accès refusé / page introuvable) n'a plus de CSS :
   le composant est entièrement en MudBlazor et hérite du thème. L'ancien style
   "verre dépoli" est archivé dans docs/frosted-glass-archive.md. */

/* Uniform chip corner radius across the whole app */
.mud-chip {
    border-radius: 5px !important;
}

/* Tailles de texte des pastilles et des infobulles en rem. MudBlazor les fixe en px (12, 14 et
   16px pour les pastilles, 12px pour l'infobulle) : elles echappaient donc au reglage global
   html { font-size } et restaient petites a cote d'un texte agrandi. Memes valeurs a 16px, mais
   elles suivent desormais le reglage. Les hauteurs (24/32/40px) ne bougent pas. */
.mud-chip.mud-chip-size-small {
    font-size: 0.75rem;
}

.mud-chip.mud-chip-size-medium {
    font-size: 0.875rem;
}

.mud-chip.mud-chip-size-large {
    font-size: 1rem;
}

.mud-tooltip {
    font-size: 0.75rem;
}

/* Pastille d'etat d'un parametre (EtatParametreVisuals). La couleur de l'etat arrive par la
   variable --etat, posee en ligne par l'appelant. Avant, elle coloriait le texte seul, pose sur
   le gris a 6% de .mud-chip-text : un vert moyen sur gris, en petit, se lisait a peine, et les
   teintes claires (rose, violet, orange) encore moins. Ici le fond prend un voile de la couleur
   et le texte une version assombrie de la meme couleur : l'etat se reconnait toujours a sa
   teinte, avec un contraste lisible. En mode sombre le texte s'eclaircit au lieu de foncer. */
.mud-chip.etat-param-chip {
    color: color-mix(in srgb, var(--etat) 60%, black);
    background-color: color-mix(in srgb, var(--etat) 15%, transparent);
    font-weight: 600;
}

html[data-theme="dark"] .mud-chip.etat-param-chip {
    color: color-mix(in srgb, var(--etat) 60%, white);
    background-color: color-mix(in srgb, var(--etat) 24%, transparent);
}

/* Badge compteur de charge dans le menu (MenuBar) - rendu apres le titre de l'item.
   Le fond vient des classes de gravite ci-dessous, communes aux badges des tuiles. */
.menu-count-badge {
    display: inline-block;
    margin-left: 8px;
    min-width: 20px;
    padding: 1px 6px;
    border-radius: 10px;
    color: #fff;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    vertical-align: middle;
}

/* Gravite des compteurs de charge : vert = charge normale, orange = seuil d'alerte
   depasse, rouge = seuil de danger depasse (seuils COMPTEUR_* dans Parametres). */
.count-ok {
    background: var(--mud-palette-success);
}

.count-warn {
    background: var(--mud-palette-warning);
}

.count-danger {
    background: var(--mud-palette-error);
}

/* ============================================================
   TEINTES DE CAISSE - repérage d'un montant par sa nature
   ============================================================
   Une déclaration de caisse mélange quatre natures d'argent - espèces, carte, bons de prise en
   charge, dépenses - réparties sur trois onglets et récapitulées dans une colonne unique. Le
   libellé seul ne suffit pas à les rattacher d'un coup d'oeil : la teinte le fait.

   Elle N'EST JAMAIS le seul canal - chaque ligne garde son libellé écrit et chaque onglet son
   titre. Le rouge reste réservé à l'écart et à l'erreur de saisie : aucune des quatre teintes ne
   s'en approche.

   Valeurs prises dans la classe Colors de MudBlazor (Darken3/Darken4 en clair, Lighten2 en
   sombre) plutôt qu'inventées, pour rester dans la palette du reste de l'application. */
html {
    --caisse-especes: #2e7d32; /* Colors.Green.Darken3   - billets ET pièces */
    --caisse-tpe: #1565c0; /* Colors.Blue.Darken3    - paiement par carte */
    --caisse-pec: #6a1b9a; /* Colors.Purple.Darken3  - bons de prise en charge */
    --caisse-depense: #e65100; /* Colors.Orange.Darken4  - sorties de caisse */
    /* Le fond de caisse : un bleu AUSSI, mais pas CELUI du TPE - Indigo contre Blue. Le bleu TPE
       signifie « paiement par carte » dans tout le module, et le fond n'est pas une recette ;
       deux familles de bleu gardent le repère sans fabriquer une fausse parenté. */
    --caisse-fond: #283593; /* Colors.Indigo.Darken3 - monnaie déposée à l'ouverture */
}

html[data-theme="dark"] {
    --caisse-especes: #81c784; /* Colors.Green.Lighten2 */
    --caisse-tpe: #64b5f6; /* Colors.Blue.Lighten2 */
    --caisse-pec: #ba68c8; /* Colors.Purple.Lighten2 */
    --caisse-depense: #ffb74d; /* Colors.Orange.Lighten2 */
    --caisse-fond: #7986cb; /* Colors.Indigo.Lighten2 */
}

/* Champ de saisie teinté. À poser en DEUX classes : « champ-teinte » porte le comportement,
   « champ-teinte-xxx » choisit la couleur - Class="champ-teinte champ-teinte-pec".

   Le CHIFFRE et la bordure au repos portent la teinte. Le chiffre d'abord : c'est lui qu'on lit,
   et une bordure seule laisse un tableau de nombres tous identiques. La bordure suit, parce
   qu'elle désigne la case où taper avant même qu'il y ait quelque chose à lire.

   Les trois états signifiants de MudBlazor restent intacts et passent devant la teinte :
   focus en primaire, erreur en rouge, désactivé en gris pointillé - d'où les :not(). */
.champ-teinte-especes {
    --champ-teinte: var(--caisse-especes);
}

.champ-teinte-tpe {
    --champ-teinte: var(--caisse-tpe);
}

.champ-teinte-pec {
    --champ-teinte: var(--caisse-pec);
}

.champ-teinte-depense {
    --champ-teinte: var(--caisse-depense);
}

.champ-teinte-fond {
    --champ-teinte: var(--caisse-fond);
}

/* Le chiffre saisi, et l'unité qui le suit quand le champ en porte une (« DA »). Couleur SEULE,
   sans graisse : la teinte suffit à désigner la nature du montant, et une saisie en demi-gras au
   milieu de champs qui ne le sont pas se lit comme une mise en avant - alors que ces chiffres
   n'ont rien de plus important que les autres. */
.champ-teinte .mud-input:not(.mud-disabled):not(.mud-input-error) .mud-input-slot,
.champ-teinte .mud-input:not(.mud-disabled):not(.mud-input-error) > .mud-input-adornment {
    color: var(--champ-teinte);
}

/* Chiffres alignés à droite, comme n'importe quelle colonne de nombres. Un champ de saisie aligne
   son contenu à gauche par défaut, y compris dans une cellule en text-align:right : la propriété
   ne traverse pas la frontière du contrôle de formulaire. Les quantités flottaient donc à gauche
   sous un en-tête et au-dessus d'un total tous deux calés à droite. */
.champ-montant-droite .mud-input-slot {
    text-align: right;
}

/* Champ teinté qui vaut zéro : le chiffre s'efface comme un .montant-nul, le soulignement garde
   la teinte - il désigne toujours la case où taper. Une classe de plus que la règle du chiffre
   teinté, donc plus spécifique sans !important. */
.champ-teinte.champ-nul .mud-input:not(.mud-disabled):not(.mud-input-error) .mud-input-slot {
    color: var(--mud-palette-text-disabled);
}

/* Variant.Text / Filled : le soulignement au repos (le :after, invisible hors focus, est laissé
   à la primaire et au rouge d'erreur). */
.champ-teinte .mud-input.mud-input-underline:not(.mud-disabled):not(.mud-input-error):before {
    border-bottom-color: var(--champ-teinte);
}

/* PAS DE RÈGLE POUR Variant.Outlined, volontairement. Un cadre complet teinté encercle le champ
   sur ses quatre côtés : à côté d'un soulignement de 1 px, c'est dix fois la même couleur pour la
   même information, et le champ se met à ressembler à un état d'erreur ou de validation. Les
   chiffres portent la teinte, cela suffit à le rattacher à sa nature. */

/* Les mêmes teintes en texte, pour les totaux qui reprennent chaque nature dans le récapitulatif
   et dans les pieds de tableau. */
.texte-especes {
    color: var(--caisse-especes);
}

.texte-tpe {
    color: var(--caisse-tpe);
}

.texte-pec {
    color: var(--caisse-pec);
}

.texte-depense {
    color: var(--caisse-depense);
}

.texte-fond {
    color: var(--caisse-fond);
}

/* Ligne de comptage à zéro : le total (et la quantité, en lecture) prend la couleur des textes
   désactivés. Onze « 0,00 DA » avant la première frappe disputaient l'attention aux lignes
   remplies ; effacés, ils disent seulement « rien de cette coupure ». Pas d'opacité : elle
   s'appliquerait aussi au fond de la cellule au survol. */
.montant-nul {
    color: var(--mud-palette-text-disabled);
}

/* LE ROUGE PASSE DEVANT TOUTE TEINTE. Posée à la place d'une texte-xxx et jamais avec elle (voir
   ClasseMontant), donc aucune bataille de spécificité : un montant négatif n'est pas un montant
   d'une certaine nature, c'est un manque. */
.texte-negatif {
    color: var(--mud-palette-error);
}

/* Tableau de comptage RESSERRÉ (dialogue de déclaration de caisse). Deux gisements de hauteur,
   tous deux dans les valeurs par défaut de MudBlazor et pas dans le balisage - les cellules sont
   déjà à padding zéro :

   1. L'input d'un champ porte padding:6px 0 7px, soit 13 px par ligne de saisie ; sur neuf
      coupures et le bloc TPE, plus de 130 px partaient en respiration de champ.
   2. Un titre Typo.overline hérite d'une line-height Material de 2,66 : le mot « Billets » seul
      occupait ~32 px.

   Sélecteurs plus spécifiques que ceux de la librairie (.comptage-serre devant), donc aucun
   !important. */
.comptage-serre .mud-input > input.mud-input-root {
    padding-top: 2px;
    padding-bottom: 2px;
}

.comptage-serre .mud-typography-overline {
    line-height: 1.6;
}

/* Sélecteur de période du tableau de bord (Header de MudTabs, page Dashboard).
   Trois défauts de MudBlazor se cumulent pour écraser le groupe :
   1. .mud-tabs-tabbar-inner est une rangée flex où .mud-tabs-tabbar-content porte
      width:100%;flex:1 1 auto - la barre d'onglets réclame TOUTE la largeur et comprime le
      contenu Header, simple flex:0 1 auto ;
   2. MudToggleGroup pose grid-template-columns:repeat(N, minmax(0, 1fr)) en style INLINE,
      soit un plancher de piste à 0 : les segments cèdent jusqu'à zéro sous la pression ;
   3. .mud-toggle-group porte overflow:hidden, donc rien ne déborde pour signaler la gêne -
      les libellés finissent simplement collés aux séparateurs.
   On fige donc la largeur du Header dans la rangée flex, puis on rend sa respiration au groupe.

   La règle porte sur .mud-tabs-header-after et NON sur un div à nous placé dans le Header :
   l'élément flex de la rangée, c'est le conteneur que MudTabs génère autour du fragment Header.
   Bloquer le rétrécissement à l'intérieur de ce conteneur ne l'empêche pas, lui, de céder de la
   largeur : son contenu déborde alors par la droite et sort du MudPaper. C'est le conteneur
   lui-même qu'il faut figer ; .mud-tabs-tabbar-content, seul élément encore rétrécissable de la
   rangée, absorbe la différence (il porte overflow:hidden et sort ses flèches de défilement). */
.dashboard-tabs .mud-tabs-header-after {
    flex: 0 0 auto;
}

/* !important assumé : la piste de grille vient d'un style INLINE de MudToggleGroup, aucune
   spécificité de sélecteur ne passe devant. auto plutôt que 1fr : chaque segment prend sa
   largeur naturelle au lieu de la largeur du plus long ("Semaine") multipliée par quatre, ce
   qui laisse à la barre la place de ses sept titres avant de sortir les flèches de défilement. */
.dash-periode-toggle {
    grid-template-columns: repeat(4, auto) !important;
}

/* MudBlazor donne 3 px de padding aux items d'un groupe outlined en taille Small - 3 px en haut
   comme sur les côtés. Un libellé a besoin de marge horizontale, pas verticale : on garde la
   hauteur compacte voulue par Size.Small et on ouvre les côtés. Sélecteur à spécificité égale à
   celui de la librairie mais app.css est chargé APRÈS MudBlazor.min.css, donc il l'emporte. */
.dash-periode-toggle .mud-toggle-item.mud-toggle-item-size-small {
    padding: 4px 14px;
}

/* Ombre des cartes du tableau de bord - vignettes d'indicateur (DashKpiCard) ET cartes de
   graphique (DashCard), une seule classe pour les deux : sur une page où le conteneur des
   onglets est transparent, ce sont les seules surfaces, elles doivent se détacher pareil.
   Posée ici plutôt que par Elevation : les ombres
   Material de MudBlazor sont courtes et contrastées - un liseré sombre collé sous la carte.
   Sur le fond désormais transparent des onglets, c'est une ombre DIFFUSE qu'il faut :
   beaucoup de flou, un décalage vertical franc, et une opacité qui reste basse SANS devenir
   invisible. Trois couches empilées : un contact de 2 px qui pose la carte, une nappe
   moyenne qui lui donne son épaisseur, une nappe large qui se fond dans le fond de la page.
   La teinte n'est pas un noir pur mais le bleu-ardoise du thème : une ombre noire sur fond
   gris clair vire au sale.
   Pas de rayon d'étalement très négatif sur la couche large : -24 px sur 48 px de flou
   ramenait le halo sous la carte, où il ne se voyait plus - l'ombre existait sans se voir.

   Aucun contour en mode CLAIR : un filet net de 1 px aplatit la carte quelle que soit
   l'ombre derrière, les deux se contredisent. C'est l'ombre seule qui détache la carte. */
.dash-card {
    border: none;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .04),
                0 10px 22px -6px rgba(15, 23, 42, .07),
                0 28px 46px -14px rgba(15, 23, 42, .09);
}

/* En mode sombre, l'ombre seule ne suffit plus : du noir sur un fond déjà foncé ne dessine
   pas de bord. On monte l'opacité ET on rend le filet, qui redevient ici le seul trait sûr
   pour borner le graphique.
   html[data-theme="dark"] est le VRAI sélecteur de thème sombre de l'application, stampé sur
   <html> avant le premier rendu (script d'App.razor) - « .mud-theme-dark » ne correspond à
   rien ici et la règle serait morte. */
html[data-theme="dark"] .dash-card {
    border: 1px solid var(--mud-palette-lines-default);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .18),
                0 10px 22px -6px rgba(0, 0, 0, .24),
                0 28px 46px -14px rgba(0, 0, 0, .32);
}

/* ══ Tableau de bord : hiérarchie de texte et accents ═══════════════════════════════════════

   TROIS NIVEAUX DE TEXTE, ET SEULEMENT SUR CETTE PAGE.

   Dans MainTheme, TextPrimary et TextSecondary valent la MÊME couleur (#4C5257). Toute la
   page sortait donc dans un gris unique : le libellé d'une vignette, son chiffre et son
   commentaire ne se distinguaient que par la taille. Rien ne ressortait parce que rien
   n'était en retrait.

   Les trois niveaux sont posés sur .dashboard-root et non dans MainTheme : le tableau de
   bord est la page qui en a besoin tout de suite, et corriger le thème repeindrait d'un
   coup toutes les grilles, tous les dialogues et toutes les pages de l'application - ça se
   décide et se relit à part. Tant que ce n'est pas fait, le reste de LISDZ ne bouge pas
   d'un pixel.

   --mud-palette-text-secondary est redirigé vers le gris discret DANS ce périmètre : c'est
   ce qui fait enfin reculer DashboardPalette.TextMuted (qui pointe dessus) sans avoir à
   toucher aux composants un par un. Une variable CSS s'hérite, la redéfinir sur un
   conteneur suffit.

   html[data-theme="dark"] est le vrai sélecteur de mode sombre de l'application (stampé
   sur <html> avant le premier rendu par le script d'App.razor). */
   Le niveau discret est un gris LISIBLE, pas un gris clair : #94A3B8 avait été essayé et
   retiré, il ne tenait que 2,6:1 sur une carte blanche, sous le minimum de 4,5:1 exigé pour
   du petit texte. « En retrait » veut dire moins appuyé que l'encre, jamais illisible. */
.dashboard-root {
    --dash-ink: #0F172A;
    --dash-body: #475569;
    --dash-muted: #566374;
    --mud-palette-text-secondary: var(--dash-muted);
}

html[data-theme="dark"] .dashboard-root {
    --dash-ink: #F1F5F9;
    --dash-body: #CBD5E1;
    --dash-muted: #9BA7B5;
    --mud-palette-text-secondary: var(--dash-muted);
}

/* Ombre de la BARRE D'ONGLETS seule, et non du conteneur de la page.

   La page n'a qu'un seul MudPaper, qui enveloppe la barre ET les sept panneaux : lui poser
   l'ombre encadrait tout le tableau de bord d'un liseré et obligeait à lui donner un fond,
   qui se voyait alors sous les graphiques. C'est la barre qu'on veut détacher, donc c'est
   elle qui porte la surface et l'ombre ; le conteneur reste transparent et le fond de
   l'application continue de passer entre les cartes.

   MudTabs est en Color.Transparent : sans fond explicite, la barre n'aurait rien pour
   projeter une ombre. */
.dashboard-tabs .mud-tabs-tabbar {
    background-color: var(--mud-palette-surface);
    border-radius: var(--mud-default-borderradius);
    box-shadow: 0 1px 3px rgba(15, 23, 42, .04),
                0 10px 22px -6px rgba(15, 23, 42, .07),
                0 28px 46px -14px rgba(15, 23, 42, .09);
}

html[data-theme="dark"] .dashboard-tabs .mud-tabs-tabbar {
    border: 1px solid var(--mud-palette-lines-default);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .18),
                0 10px 22px -6px rgba(0, 0, 0, .24),
                0 28px 46px -14px rgba(0, 0, 0, .32);
}

/* ── Valeur d'une vignette d'indicateur (DashKpiCard) ──────────────────────────────────────
   La vignette n'a ni rail d'accent, ni chip d'icône, ni libellé coloré : ce sont des objets
   graphiques que le reste de LISDZ n'a pas, et une page ne s'invente pas un vocabulaire à
   elle (docs/ui-patterns.md). Seul le CHIFFRE change - il passe à l'encre, au niveau haut
   des trois niveaux de texte de la page, pour cesser d'avoir la couleur de son propre
   libellé.

   2rem !important : app.css ramène TOUT MudText à 0,9rem !important (règle .mud-typography
   plus haut dans ce fichier). Seule une déclaration également importante passe. */
.dash-kpi-value {
    font-size: 2rem !important;
    font-weight: 700;
    line-height: 1.25;
    margin-top: 4px;
    color: var(--dash-ink);
    /* Chiffres à chasse fixe : sans ça, la valeur danse latéralement d'une période à
       l'autre parce que le « 1 » d'une police proportionnelle est plus étroit que le « 8 ». */
    font-variant-numeric: tabular-nums;
}

/* ── Barre de flux (DashFluxBar) ───────────────────────────────────────────────────────────
   Le jeu de 2 px entre les tranches est ce qui rend une tranche minuscule visible : deux
   aplats collés se lisent comme un seul, séparés par le fond de la piste ils se comptent.
   flex-shrink laissé à 1 sur les tranches (voir DashFluxBar) : les jeux sont prélevés au
   prorata, les proportions sont conservées, et rien ne déborde de la piste. */
.dash-flux-track {
    display: flex;
    gap: 2px;
    height: 12px;
    border-radius: 6px;
    overflow: hidden;
    background: var(--mud-palette-lines-default);
}

.dash-flux-seg {
    height: 100%;
    border-radius: 2px;
}

/* La barre d'onglets reste celle de MudBlazor - libellé souligné par le curseur, comme
   partout ailleurs dans l'application. Une pastille pleine sur l'onglet actif avait été
   essayée puis retirée : c'était un traitement d'onglet que LISDZ n'a nulle part. */

/* ── Visualiseur de rapport intégré (page Rapports) ────────────────────────────────────────
   Le rapport s'affiche DANS la page et non plus dans un <iframe> vers /Report : DxReportViewer
   est un composant Blazor NATIF, il vit donc dans le même document que MudBlazor - c'est déjà
   ce que fait le concepteur du dialogue des tableaux normes. Le cadre isolé n'existait que pour
   contenir la feuille blazing-berry chargée par /Report EN PLUS du thème d'App.razor ; deux
   thèmes DevExpress empilés, d'où le bandeau mauve et la barre d'outils en charabia. Un seul
   thème reste, et l'habillage se fait ici.

   1. LA PALETTE DU VISUALISEUR VIENT DE VARIABLES BOOTSTRAP. Le thème DevExpress chargé par
      App.razor est « bootstrap-external » : il ne peint rien lui-même, il lit des --bs-* qu'une
      feuille Bootstrap est censée poser. L'application n'embarque pas Bootstrap, donc ces
      variables n'existaient pas et le visualiseur retombait sur ses gris d'usine - clairs en
      toutes circonstances, mode sombre compris. On les pose ici depuis la palette MudBlazor.
      Le visualiseur suit alors le thème SANS JAVASCRIPT NI RECHARGEMENT : MudThemeProvider
      réécrit les --mud-palette-* au basculement clair/sombre, et celles-ci en dérivent.

      Portée limitée au conteneur, JAMAIS <html> : le concepteur de rapports (dialogue des
      tableaux normes) est un contrôle JavaScript dont la feuille de style est claire en dur.
      Lui poser une palette sombre autour ne ferait que l'encadrer de noir.

   2. SON CADRE RÉCLAME BOOTSTRAP LUI AUSSI. RootCssClasses vaut par défaut
      « border border-secondary shadow rounded » - quatre classes utilitaires Bootstrap,
      absentes ici, d'où le pavé sans bordure ni ombre. La page passe .rapport-viseur-cadre à
      la place, réglée plus bas.

   Le PAPIER, lui, reste blanc en mode sombre, et c'est voulu : un aperçu avant impression
   montre la feuille telle qu'elle sortira de l'imprimante. Seul le châssis - barre d'outils,
   panneau des paramètres, fond de défilement - suit le thème. */
/* PORTÉE : <html>, ET NON LE SEUL CONTENEUR DU VISUALISEUR.
   Les listes déroulantes de DevExpress (Zoom, taille de page) ne sont pas rendues à l'intérieur
   du composant : elles sont détachées et rattachées au niveau du <body>. Posées sur
   « .rapport-viseur », ces variables ne les atteignaient donc pas, et
   « --dxbl-dropdown-bg: var(--bs-body-bg, var(--dxbl-body-bg, inherit)) » retombait sur
   « inherit » - autrement dit un fond TRANSPARENT, à travers lequel on lisait le rapport.
   Au niveau de <html>, la variable suit le calque détaché comme le reste.

   Sans danger pour le concepteur de rapports (dialogue des tableaux normes) : c'est un contrôle
   JavaScript dont la feuille de style est claire en dur et qui ne lit aucun --bs-*. Seule
   l'enveloppe Blazor autour de lui les consulte, et c'est justement ce qu'on veut voir suivre
   le thème. */
html {
    /* ── AUCUNE COULEUR D'ACCENT DANS LE CHÂSSIS ──
       DevExpress peint ses boutons (--dxbl-btn-*), l'onglet des paramètres et les états actifs
       avec --bs-primary et --bs-secondary. Chez Bootstrap ces deux rôles sont NEUTRES : un bleu
       d'interface sobre et un GRIS. Chez MudBlazor, Primary est le vert de l'application et
       Secondary un vrai bleu. Les brancher l'un sur l'autre - ce qui semblait « suivre le thème »
       - repeignait la barre en vert et les boutons en bleu.

       On les pose donc en gris de fer, et on ne mappe AUCUNE des autres couleurs de sens
       (success, info, warning, danger) : un aperçu avant impression n'a pas d'accent. La seule
       couleur qu'on y regarde est celle du RAPPORT, et un châssis teinté la fausse. */
    --bs-primary: #6c757d;
    --bs-primary-rgb: 108, 117, 125;
    --bs-secondary: #6c757d;
    --bs-secondary-rgb: 108, 117, 125;

    /* Surface et texte. En mode CLAIR, c'est tout ce que le thème a besoin de savoir : les gris
       d'usine de DevExpress (#f8f9fa, #e9ecef, #dee2e6 ...) sont déjà exactement le blanc et le
       gris clair voulus, on ne les touche pas. L'échelle n'est redéfinie qu'en mode sombre,
       plus bas - et en gris NEUTRES : la dériver de la couleur du texte (#4C5257, un gris
       BLEUTÉ) lavait tout le visualiseur de bleu pâle, voile de chargement compris. */
    --bs-body-bg: var(--mud-palette-surface);
    --bs-body-color: var(--mud-palette-text-primary);
    --bs-body-color-rgb: var(--mud-palette-text-primary-rgb);
    --bs-border-color: var(--mud-palette-lines-default);

    /* Rien ici pour la bande verticale des onglets : elle n'existe plus. Les quatre onglets du
       visualiseur sont masqués côté C# (voir OnAfterRender dans Rapports.razor), et le
       composant retire le panneau dès qu'aucun onglet n'est visible. */

    /* LES DEUX LITTÉRAUX BOOTSTRAP. Ils ne sont pas des couleurs de thème mais du blanc et du
       noir purs, et plusieurs règles DevExpress s'en servent pour poser un texte SUR un aplat
       coloré. Bootstrap n'étant pas chargé, ni --bs-white ni son repli --white n'existaient :
       ces règles devenaient invalides et le texte gardait sa couleur d'origine. */
    --bs-white: #ffffff;
    --bs-black: #000000;

    /* SURBRILLANCE DE L'ÉLÉMENT CHOISI dans une liste déroulante (Zoom, taille de page).
       DevExpress peint la ligne sélectionnée avec --bs-primary et pose son texte en
       --bs-white. Avec --bs-primary en gris de fer (#6c757d) et --bs-white absent, on
       obtenait du texte sombre sur un aplat sombre : « 100% » disparaissait dans sa propre
       surbrillance.

       Plutôt que de compter sur le blanc rétabli ci-dessus, on renverse le rapport : aplat
       DISCRET et texte normal. Une liste de zoom n'a pas à crier - il s'agit de retrouver la
       ligne courante, pas de la mettre en vedette. Le voile est neutre et exprimé en alpha,
       donc il fonce ce qui est clair et éclaircit ce qui est sombre, sans teinte. */
    --dxbl-list-box-item-selected-bg: rgba(0, 0, 0, .07);
    --dxbl-list-box-item-selected-color: var(--mud-palette-text-primary);
    --dxbl-list-box-item-selected-hover-bg: rgba(0, 0, 0, .12);
    --dxbl-list-box-item-selected-hover-color: var(--mud-palette-text-primary);
    --dxbl-list-box-item-hover-bg: rgba(0, 0, 0, .05);
}

/* ── Hauteur des deux colonnes de la page Rapports ────────────────────────────────────────
   LA PAGE NE DÉFILE PAS : seuls le catalogue et le rapport défilent, chacun dans son cadre.
   Pour cela il faut que les deux colonnes tiennent dans ce qui reste de la fenêtre une fois le
   châssis déduit. Ce châssis n'est pas deviné, il est lisible dans MainLayout :

     111 px  MudMainContent, padding-top: calc(64px + 35px + 12px)   barre + menu + respiration
      51 px  fil d'Ariane (MudBreadcrumbs, 8 px de marge + une ligne en Typo.h6 à 1 rem)
      64 px  MudMainContent, classe pb-16
     ─────
     226 px  auxquels on ajoute une marge de sécurité : 270 px.

   LA MARGE EST DÉLIBÉRÉMENT LARGE. Ces hauteurs dépendent de la police, du zoom du navigateur
   et du réglage de taille de texte de l'application (html { font-size: 112.5% }) : un budget
   calculé au pixel près redevient faux au premier de ces changements. Quarante pixels de
   réserve coûtent une bande vide sous le rapport, que personne ne remarque ; les rogner
   ramène la barre de défilement de la page, que tout le monde voit.

   Le pied de page ne compte PAS : il est en position:fixed (voir .footer) et ne prend donc
   aucune place dans le flux - c'est le pb-16 qui lui réserve son espace.

   UNE SEULE VALEUR POUR LES DEUX COLONNES, sur leur ancêtre commun. C'est la correction du
   défaut d'origine : le catalogue était plafonné à 100vh - 190px, soit ~30 px de trop, et
   faisait apparaître la barre de défilement de la page dès qu'une famille était dépliée -
   alors que le visualiseur, lui, tenait. Deux budgets indépendants finissent toujours par
   diverger ; ici ils ne peuvent plus. */
.rapports-page {
    --rapports-colonne: calc(100vh - 270px);

    /* Hauteur du bandeau du rapport (titre, légende, sélecteur de période), séparateur compris.
       Mesurée sur le rendu, pas déduite : pa-4 (16 px en haut et en bas) autour d'un bloc dont
       le sélecteur de période, en Variant.Outlined + Margin.Dense, fixe la hauteur.

       ON NE PEUT PAS S'EN PASSER, et une tentative l'a montré : donner la hauteur au PANNEAU et
       laisser le visualiseur prendre le reste avec « flex: 1 1 auto » paraît plus robuste, mais
       un élément flex ainsi dimensionné n'a pas de hauteur DÉFINIE. Le visualiseur DevExpress
       mesure ses propres blocs internes (.dxbrv-viewbox, .dxbrv-surface-wrapper en position
       absolue) contre celle de son hôte : sans hauteur définie, sa mise en page s'effondre et la
       barre d'outils descend au milieu du panneau. Il lui faut une hauteur en dur. */
    --rapports-bandeau: 115px;
}

/* Le catalogue défile dans son propre cadre. Hauteur FIXE, pas un plafond : avec un simple
   max-height, replié il s'arrêtait à ses sept familles et se terminait bien au-dessus du
   panneau de droite, qui lui occupe toute la colonne. Les deux cartes ont donc la même
   hauteur, familles dépliées ou non, et le même plancher que .rapports-rapport pour rester
   alignées aussi sur une fenêtre basse. */
.rapports-catalogue {
    height: var(--rapports-colonne);
    min-height: 420px;
    display: flex;
    flex-direction: column;
}

/* La recherche reste en tête, c'est l'ARBRE qui défile en dessous. min-height:0 est ce qui
   autorise un enfant flex à devenir plus petit que son contenu, sans quoi il ne défile jamais
   et pousse la carte au-delà de sa hauteur. */

/* Le champ de recherche prend SA hauteur et rien de plus. MudBlazor pose « flex-grow » sur
   .mud-input-control pour que le champ remplisse une ligne de formulaire ; dans une colonne
   flex, il s'étirait à la moitié de la carte et rejetait l'arbre au milieu. */
.rapports-catalogue > .mud-input-control {
    flex: 0 0 auto;
}

.rapports-catalogue-liste {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* Le panneau du rapport : même hauteur que le catalogue, pour que les deux colonnes se
   terminent sur la même ligne. */
.rapports-rapport {
    height: var(--rapports-colonne);
    min-height: 420px;
    overflow: hidden;
}

/* Le visualiseur occupe ce qui reste sous le bandeau. Hauteur EN DUR, pour la raison exposée
   ci-dessus. Le plancher évite qu'il ne se referme en bandeau illisible sur une fenêtre basse -
   dans ce cas seulement la page redéfile, ce qui vaut mieux qu'un rapport haut de trois
   centimètres. */
.rapport-viseur {
    display: block;
    height: calc(var(--rapports-colonne) - var(--rapports-bandeau));
    min-height: 305px;
}

/* Aucun rapport choisi : la carte d'attente prend TOUTE la hauteur de sa colonne. Les
   colonnes d'une MudGrid s'étirent à la plus haute des deux ; le catalogue, replié ou déplié,
   donne donc la mesure, et la carte d'attente se termine exactement sur sa ligne au lieu de
   s'arrêter à la hauteur de son texte. L'invite reste centrée dans la carte, quelle que soit
   cette hauteur. */
.rapports-attente {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Mode sombre : l'échelle de gris s'inverse. Ce sont des gris NEUTRES, pas des dérivés de la
   palette - le châssis doit rester incolore des deux côtés. Les rôles Bootstrap sont conservés
   dans l'ordre : 100 est le plus proche du fond, 900 le plus proche du texte.
   Sur <html> pour la même raison que ci-dessus : les listes déroulantes sont détachées. */
html[data-theme="dark"] {
    /* Le voile de surbrillance s'inverse : sur fond sombre, c'est du blanc à faible opacité
       qui détache la ligne courante. Le texte, lui, suit --mud-palette-text-primary posé
       plus haut et n'a rien à redéfinir ici. */
    --dxbl-list-box-item-selected-bg: rgba(255, 255, 255, .12);
    --dxbl-list-box-item-selected-hover-bg: rgba(255, 255, 255, .18);
    --dxbl-list-box-item-hover-bg: rgba(255, 255, 255, .08);

    --bs-gray-100: #2b2b2b;
    --bs-gray-200: #333333;
    --bs-gray-300: #3d3d3d;
    --bs-gray-400: #4a4a4a;
    --bs-gray-500: #5c5c5c;
    --bs-gray-600: #757575;
    --bs-gray-700: #909090;
    --bs-gray-800: #b0b0b0;
    --bs-gray-900: #d0d0d0;
}

/* ATTENTION À LA SPÉCIFICITÉ dans tout ce qui suit. App.razor charge le thème DevExpress APRÈS
   app.css : à spécificité égale, c'est donc le thème qui gagne, et une règle écrite ici « comme
   d'habitude » reste lettre morte. Chaque sélecteur passe volontairement par .rapport-viseur ET
   .dxbrv-wrapper pour être plus spécifique que celui de la librairie - ce qui évite les
   !important, qu'il faudrait sinon poser partout.

   Le cadre du visualiseur (.dxbrv-wrapper, l'élément qui porte RootCssClasses) :

   - PAS DE BORDURE NI D'OMBRE. Le thème lui pose « border: 1px solid var(--dxbrv-secondary-color) »
     et une ombre portée. --dxbrv-secondary-color dérive de --bs-secondary, mis en gris de fer
     plus haut pour désaturer les boutons : d'où un liseré presque noir collé au bord. Le
     visualiseur est déjà DANS un MudPaper qui porte son propre cadre - le second trait ne
     délimitait rien, il doublait le premier.

   - FOND BLANC. Le thème étale un voile sur toute la zone du document
     (.dxbrv-surface-container:before, aplat de --dxbrv-secondary-color à 10 % d'opacité), ce qui
     grisait le fond. On le retire plus bas : la page se détache déjà de son fond par sa propre
     ombre portée, elle n'a pas besoin qu'on assombrisse tout autour.

   - HAUTEUR REPRISE. Le thème fixe « height: 50rem » en dur sur le cadre. À spécificité égale il
     l'emportait sur le 100 % du conteneur, et le visualiseur gardait ses 800 px quelle que soit
     la place disponible. */
.rapport-viseur .dxbrv-wrapper {
    background-color: var(--mud-palette-surface);
    border: 0;
    box-shadow: none;
    height: 100%;
    width: 100%;
    border-radius: 0;
    border-bottom-left-radius: var(--mud-default-borderradius, 8px);
    border-bottom-right-radius: var(--mud-default-borderradius, 8px);
}

/* Le voile gris sur la zone du document. */
.rapport-viseur .dxbrv-wrapper .dxbrv-surface-container::before {
    display: none;
}

/* La barre d'outils passe sur la surface de l'application et se sépare du document par le même
   trait que les autres en-têtes de la page. C'est ce qui la fait lire comme la barre DE la page
   plutôt que comme celle d'un composant rapporté. */
.rapport-viseur .dxbrv-wrapper .dxbrv-toolbar {
    background-color: var(--mud-palette-surface);
    border-bottom: 1px solid var(--mud-palette-lines-default);
    box-shadow: none;
}

/* ===== Pastille de catégorie des cartes de courtoisie =====
   Partagée par la grille /cartes-courtoisie et le dialogue « Catégories et barème ».

   Les teintes NE VIENNENT PAS de la carte imprimée : celles-là sont des encres, choisies pour
   porter du texte blanc sur un badge PVC. Très sombres, elles écrasaient la ligne en thème clair
   et disparaissaient en thème sombre ; le vert du personnel et le turquoise de la solidarité y
   étaient de surcroît presque identiques.

   Vert, bleu et violet viennent donc de la PALETTE, qui s'éclaircit d'elle-même en thème sombre -
   et le personnel tombe exactement sur le vert de la pastille « Active » juste à côté. La
   solidarité garde son turquoise, absent de la palette : il est donc posé à la main, en DEUX
   valeurs, sans quoi il retomberait dans le défaut qu'on vient de corriger.

   Recette reprise de la pastille d'état (MudBlazor, Variant.Text) : texte à la couleur pleine sur
   un simple voile de cette même couleur, plus un filet DE LA COULEUR DU TEXTE - sans lui la
   pastille flotte sur le fond de la ligne.

   Le repli d'abord : ces règles pèsent toutes une classe, la dernière écrite l'emporte. */
.cat-chip { --cat: var(--mud-palette-text-secondary); }

.cat-personnel  { --cat: var(--mud-palette-success); }
.cat-medecins   { --cat: var(--mud-palette-info); }
.cat-vip        { --cat: var(--mud-palette-tertiary); }
.cat-solidarite { --cat: #00796B; }                      /* Colors.Teal.Darken2 */

/* html[data-theme="dark"] : le VRAI sélecteur de thème sombre de cette application, stampé sur
   <html> avant le premier rendu (voir setBodyDarkMode dans app.js). Ce n'est pas
   « .mud-theme-dark », qui ne correspond à rien ici. */
html[data-theme="dark"] .cat-solidarite { --cat: #4DB6AC; }  /* Colors.Teal.Lighten2 */

/* !important parce que MudBlazor pose lui-même le fond de la pastille. */
.cat-chip.mud-chip {
    background-color: color-mix(in srgb, var(--cat) 14%, transparent) !important;
    color: var(--cat) !important;
    border: 1px solid var(--cat);
    font-weight: 600;
}

/* Icône du titulaire, à la teinte de sa catégorie : la ligne se lit alors d'un bloc, au lieu
   d'une pastille colorée suivie d'un gris quelconque.

   Repli DANS le var() plutôt que dans une règle à part : une catégorie sans thème connu ne pose
   pas --cat, et une déclaration de repli séparée devrait se placer avant les classes de teinte
   pour ne pas les écraser - contrainte d'ordre qu'on évite ici.

   !important parce que MudIcon pose sa propre couleur (.mud-icon-default). */
.cat-icon.mud-icon-root {
    color: var(--cat, var(--mud-palette-text-secondary)) !important;
}

/* Sélection franche : liste maître d'un dialogue maître-détail (paramètres de l'analyseur).
   Le .row-selected à 15 % suffit dans une grille de recherche, pas quand le panneau de droite
   dépend de la ligne choisie : ici la ligne doit se voir d'un coup d'œil. */
.mud-table-row.row-selected-forte {
    background-color: #82C2E480 !important;
}
.mud-table-row.row-selected-forte .mud-table-cell {
    background-color: transparent !important;
    font-weight: 600;
}

/* Plages de norme : fond de ligne selon le sexe. Teintes en transparence pour rester lisibles
   sur le fond clair comme sur le fond sombre (rose = femelle, bleu = mâle, gris = indéterminé). */
.mud-table-row.plage-sexe-f .mud-table-cell { background-color: rgba(233, 30, 99, 0.12) !important; }
.mud-table-row.plage-sexe-m .mud-table-cell { background-color: rgba(33, 150, 243, 0.12) !important; }
.mud-table-row.plage-sexe-i .mud-table-cell { background-color: rgba(128, 128, 128, 0.14) !important; }
/* Plage en conflit (chevauchement ou bornes inversées) : le texte passe en rouge, la teinte du sexe reste. */
.mud-table-row.plage-conflit .mud-table-cell,
.mud-table-row.plage-conflit .mud-table-cell .mud-input,
.mud-table-row.plage-conflit .mud-table-cell .mud-select-input,
.mud-table-row.plage-conflit .mud-table-cell input { color: var(--mud-palette-error) !important; font-weight: 600; }

/* ===== Fiche de privilège (ModifierPermissionDialog) =====
   Hauteur FIXE : le volet des pages et le volet des permissions défilent chacun de leur côté,
   le pied du dialogue ne bouge jamais. Couleurs prises dans la palette MudBlazor (variables
   --mud-palette-*) pour tenir en thème sombre sans seconde feuille. */
.priv-head { padding: 4px 24px 8px; }
.priv-head .mud-alert { margin-bottom: 10px; }
.priv-fields { display: flex; gap: 12px; }
.priv-fields .priv-nom { flex: 1 1 0; }
.priv-fields .priv-recherche { flex: 1.3 1 0; }

.priv-body {
    display: grid;
    grid-template-columns: 290px 1fr;
    height: 620px;
    border-top: 1px solid var(--mud-palette-lines-default);
}
.priv-nav {
    overflow-y: auto;
    border-right: 1px solid var(--mud-palette-lines-default);
    background: var(--mud-palette-background-gray);
    padding: 4px 0 10px;
}
.priv-grp {
    font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
    color: var(--mud-palette-text-secondary); font-weight: 800; padding: 12px 16px 4px;
}
.priv-pg {
    display: grid; grid-template-columns: 1fr auto; column-gap: 10px;
    padding: 5px 14px 6px 16px; cursor: pointer; position: relative; outline: none;
    border-left: 3px solid transparent;
}
.priv-pg:hover, .priv-pg:focus-visible { background: var(--mud-palette-action-default-hover); }
.priv-pg:focus-visible { box-shadow: inset 0 0 0 2px var(--mud-palette-primary); }
.priv-pg.priv-on { background: var(--mud-palette-surface); border-left-color: var(--mud-palette-primary); }
.priv-pg .priv-n { font-weight: 600; font-size: 13.5px; }
.priv-pg.priv-on .priv-n { color: var(--mud-palette-primary); font-weight: 800; }
.priv-pg.priv-zero .priv-n { color: var(--mud-palette-text-secondary); }
.priv-pg .priv-c { font-variant-numeric: tabular-nums; font-size: 12px; color: var(--mud-palette-text-secondary); align-self: center; }
.priv-pg .priv-bar { grid-column: 1 / 3; height: 3px; background: var(--mud-palette-lines-default); border-radius: 2px; margin-top: 4px; overflow: hidden; }
.priv-pg .priv-bar i { display: block; height: 100%; background: var(--mud-palette-success); border-radius: 2px; }
.priv-pg .priv-dot { position: absolute; left: 5px; top: 12px; width: 6px; height: 6px; border-radius: 50%; background: var(--mud-palette-warning); }

.priv-pane { overflow-y: auto; padding: 12px 24px 20px; }
.priv-ph { display: flex; align-items: flex-end; gap: 12px; padding-bottom: 6px; }
.priv-ph h2 { margin: 0; font-size: 17px; font-weight: 800; line-height: 1.3; }
.priv-ph .priv-sub { color: var(--mud-palette-text-secondary); font-size: 12.5px; padding-bottom: 2px; font-variant-numeric: tabular-nums; }
.priv-ph .priv-acts { margin-left: auto; display: flex; gap: 4px; }
.priv-vide { color: var(--mud-palette-text-secondary); margin: 8px 0; }

.priv-master {
    border: 1px solid var(--mud-palette-lines-default); border-radius: 6px;
    padding: 4px 12px 8px; background: var(--mud-palette-background-gray); margin-bottom: 6px;
}
.priv-master .priv-lbl { font-weight: 800; }
.priv-master .priv-note { font-size: 12px; color: var(--mud-palette-text-secondary); margin: -2px 0 0 58px; }

.priv-sec {
    font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
    color: var(--mud-palette-text-secondary); font-weight: 800; padding: 12px 0 2px;
    display: flex; align-items: center; gap: 10px;
}
.priv-sec::after { content: ""; flex: 1; height: 1px; background: var(--mud-palette-lines-default); }

.priv-row { display: flex; align-items: center; gap: 12px; padding: 0 8px; border-radius: 4px; margin-left: -8px; }
.priv-row:hover { background: var(--mud-palette-action-default-hover); }
.priv-row.priv-child { margin-left: 26px; position: relative; }
.priv-row.priv-child::before {
    content: ""; position: absolute; left: -16px; top: -6px; width: 12px; height: 22px;
    border-left: 1.5px solid var(--mud-palette-lines-default); border-bottom: 1.5px solid var(--mud-palette-lines-default);
    border-radius: 0 0 0 4px;
}
.priv-row.priv-chg, .priv-row.priv-chg:hover, .priv-master.priv-chg { background: rgba(255, 193, 7, .18); }
.priv-row .priv-key, .priv-master .priv-key {
    font-size: 11px; color: var(--mud-palette-text-secondary); font-family: Consolas, ui-monospace, monospace;
    margin-left: 8px; opacity: 0; transition: opacity .12s;
}
.priv-row:hover .priv-key, .priv-master:hover .priv-key { opacity: 1; }
.priv-row .priv-was { margin-left: auto; font-size: 11px; color: var(--mud-palette-warning-darken); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; white-space: nowrap; }
.priv-row.priv-dis { opacity: .5; }

.priv-foot { display: flex; align-items: center; gap: 10px; width: 100%; }
.priv-foot .priv-sp { flex: 1; }
.priv-chip {
    display: inline-flex; align-items: center; border-radius: 14px; padding: 3px 10px;
    font-size: 12.5px; font-weight: 700; background: rgba(255, 193, 7, .18);
    color: var(--mud-palette-warning-darken); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.priv-chip.priv-none { background: var(--mud-palette-background-gray); color: var(--mud-palette-text-secondary); }

/* Code PIN à 4 cases (SaisiePin) : cases arrondies, chiffres masqués, à la manière des codes 2FA */
.pin-boxes { display: flex; gap: 12px; justify-content: center; }
.pin-boxes input.pin-box {
    width: 52px; height: 60px; padding: 0; box-sizing: border-box;
    border: 2px solid var(--mud-palette-lines-inputs); border-radius: 12px;
    text-align: center; font-size: 1.75rem; font-weight: 600;
    background: var(--mud-palette-surface); color: var(--mud-palette-text-primary);
    -webkit-text-security: disc; caret-color: var(--mud-palette-primary);
    transition: border-color .15s, box-shadow .15s;
}
.pin-boxes input.pin-box:focus { outline: none; border-color: var(--mud-palette-primary); box-shadow: 0 0 0 3px rgba(var(--mud-palette-primary-rgb), .18); }
.pin-boxes input.pin-box:disabled { opacity: .6; }
.pin-boxes.six { gap: 8px; }
.pin-boxes.six input.pin-box { width: 44px; height: 54px; font-size: 1.5rem; }

/* ── Menu d'actions d'un message de la messagerie interne ────────────────────
 * Regle GLOBALE et non isolee : MudMenu rend son contenu dans le fournisseur de
 * popover, hors du sous-arbre de Messagerie.razor - une feuille .razor.css ne
 * l'atteint jamais.
 * Le menu s'ouvre au ras d'une bulle qui peut ne faire que deux caracteres : aux
 * dimensions par defaut d'une MudList, il ecrasait le message qu'il concerne. */
.messagerie-menu-message .mud-menu-list {
    padding: 2px 0;
}

/* Calibre sur MudButton Size.Small, celui des actions de la fiche du fil (« Epingler la
 * conversation »...) : memes 0.8125rem de texte, meme icone de 18px, meme gouttiere de 8px.
 * Les valeurs viennent de _button.scss, pas d'une estimation a l'oeil. */
.messagerie-menu-message .mud-menu-item {
    padding: 4px 10px;
    min-height: 0;
}

.messagerie-menu-message .mud-menu-item-text {
    font-size: 0.8125rem;
    line-height: 1.5;
}

/* La classe mud-menu-item-icon est portee par le SVG LUI-MEME, pas par un conteneur : viser
 * « .mud-menu-item-icon .mud-icon-root » ne trouvait donc rien, et l'icone restait a la taille
 * medium (1.5rem) - c'est elle qui donnait sa hauteur a la ligne. Le SVG se dimensionne en em,
 * donc la font-size posee ici suffit a le reduire. */
.messagerie-menu-message .mud-menu-item-icon {
    font-size: 18px;
    margin-right: 8px;
}

/* ── Panneau de la cloche (messagerie interne) ───────────────────────────────
 * Regle GLOBALE : MudMenu rend son contenu dans le fournisseur de popover, hors
 * du composant MessagerieIcones - une feuille isolee ne l'atteint jamais. */
.messagerie-cloche .mud-menu-list,
.messagerie-cloche .mud-menu-list-wrapper {
    padding: 0;
}

.cloche-panneau {
    width: 360px;
    max-width: 90vw;
}

.cloche-entete {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 10px 8px 10px 16px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.cloche-titre {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex: 1 1 auto;
    min-width: 0;
}

.cloche-nom {
    font-size: 0.95rem;
    font-weight: 600;
}

/* Le compte de non-lus en SOUS-TITRE plutot qu'en pastille : la pastille est deja
 * sur la cloche elle-meme, la repeter en gros dans l'en-tete du panneau qu'elle
 * vient d'ouvrir n'apprend rien de plus. */
.cloche-sous {
    font-size: 0.72rem;
    color: var(--mud-palette-text-secondary);
}

/* Le bouton « rediger » est le seul rempli du panneau : c'est la seule action qui
 * CREE quelque chose, les deux autres ne font que ranger. */
.messagerie-cloche .cloche-rediger {
    margin-left: 4px;
}

.cloche-liste {
    max-height: 320px;
    overflow-y: auto;
}

.cloche-ligne {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 14px;
    cursor: pointer;
    /* Liseré transparent en permanence : la ligne ne se decale pas quand il apparait. */
    border-left: 3px solid transparent;
    transition: background-color 120ms;
}

.cloche-ligne:hover {
    background-color: var(--mud-palette-table-hover);
}

/* Toute ligne de la cloche est NON LUE par construction - la procedure ne rend que
 * cela - d'ou le liseré et la teinte sur chacune, sans classe supplementaire. */
.cloche-ligne {
    border-left-color: var(--mud-palette-primary);
    background-color: rgba(var(--mud-palette-primary-rgb), 0.06);
}

.cloche-texte {
    flex: 1 1 auto;
    min-width: 0;
}

.cloche-ligne1,
.cloche-ligne2 {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.cloche-fil {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cloche-heure,
.cloche-apercu {
    font-size: 0.73rem;
    color: var(--mud-palette-text-secondary);
}

.cloche-heure {
    flex: 0 0 auto;
    white-space: nowrap;
}

.cloche-apercu {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Vert et non rouge : des messages en attente ne sont pas une panne. Le rouge de
 * l'application est reserve a ce qui a echoue. */
.cloche-compteur {
    flex: 0 0 auto;
    min-width: 20px;
    height: 20px;
    padding: 0 7px;
    border-radius: 10px;
    background-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary-text);
    font-size: 0.7rem;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.cloche-pied {
    border-top: 1px solid var(--mud-palette-lines-default);
    padding: 4px;
}

/* Aperçu d'un modèle de notification arabe (Paramètres > Notification) : seule la zone de
   texte passe de droite à gauche, l'étiquette flottante du champ reste à gauche. */
.lisdz-texte-rtl textarea,
.lisdz-texte-rtl input {
    direction: rtl;
    text-align: right;
}


/* ── Pastille de couleur de bouchon (Consommable.Couleur_Bouchon) ─────────────────────────
   Un disque cerclé d'un léger anneau, pour que le blanc et le beige restent visibles sur
   fond clair et le noir sur fond sombre. Le fond est posé en style inline (hex stocké) ;
   sans couleur, la pastille est invisible mais garde sa place (CouleursBouchon.StylePastille).
   Dialogue Consommable, référentiel, station de prélèvement (.grande). */
.pastille-bouchon {
    display: inline-block;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .18);
    flex: none;
    vertical-align: middle;
}

html[data-theme="dark"] .pastille-bouchon {
    box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .25);
}

.pastille-bouchon.grande {
    width: 22px;
    height: 22px;
}
/* ── Dialogues « Copier depuis… » ─────────────────────────────────────────────
   Une ligne Depuis -> Vers qui se lit comme une phrase, puis un bloc encadré dont
   chaque case à cocher est le titre de sa bande (composant CopieQuoiBloc et
   CopierDepuisDestinationDialog). Texte d'appoint en gris du thème et en bloc,
   pour que les lignes repliées restent alignées ; le rouge ne sert qu'à
   l'avertissement d'écrasement. */
.copie-dest-ligne { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 8px 12px; }
.copie-dest-bout { flex: 1 1 220px; min-width: 0; }
/* La flèche se centre sur le champ (40 px sous les 8 px de marge du label), pas sur
   la colonne entière, qui compte aussi la ligne de détail. */
.copie-dest-fleche { flex: 0 0 auto; margin-top: 16px; }
.copie-dest-detail { display: block; margin: 2px 0 0 14px; font-size: .78rem; line-height: 1.3; color: var(--mud-palette-text-secondary); }
/* Texte sous une case à cocher dense : aligné sur son libellé (bouton de 32 px). */
.copie-dest-sous { display: block; margin-left: 32px; font-size: .8rem; line-height: 1.35; color: var(--mud-palette-text-secondary); }
.copie-dest-alerte { display: flex; align-items: center; gap: 6px; margin-top: 2px; font-size: .8rem; line-height: 1.35; color: var(--mud-palette-error); }
.copie-dest-alerte.sous-case { margin: 4px 0 0 32px; }
.copie-dest-modes { margin-left: 24px; }
/* Hauteur réservée : la barre de lecture de l'aperçu ne fait pas sauter le bloc en dessous. */
.copie-dest-lecture { height: 4px; margin: 4px 0 12px; }
