:root {
    /* Valeur par défaut avant que SidebarMenu.razor (IBrowserViewportObserver) ne la mette à jour au premier
       rendu côté client : suppose desktop/drawer ouvert, comme _drawerOpen/_breakpoint par défaut. */
    --app-drawer-width: 240px;
}

/* Les snackbars sont en bas à droite (Program.cs) : décalés au-dessus de la MudToolBar fixe du bas
   (SidebarMenu.razor, 56px) pour ne pas se superposer. */
.mud-snackbar-location-bottom-right {
    bottom: 56px !important;
}

/* Overlay d'attente d'une édition inline de produit (apiClient.js::showEditBusy) : voile toute la page
   et bloque les interactions le temps de l'aller-retour Kbmax, comme showLoadingEdit() en MVC. z-index
   sous les snackbars (2000) pour que les erreurs éventuelles restent visibles. */
#cfg-edit-overlay {
    position: fixed;
    inset: 0;
    z-index: 1400;
    background: rgba(150, 150, 150, 0.22);
    cursor: wait;
    display: flex;
    align-items: center;
    justify-content: center;
}

.cfg-edit-spinner {
    width: 42px;
    height: 42px;
    border: 4px solid var(--cfg-accent-line);
    border-top-color: var(--cfg-accent);
    border-radius: 50%;
    animation: cfg-edit-spin 0.8s linear infinite;
}

@keyframes cfg-edit-spin {
    to { transform: rotate(360deg); }
}

/* ---------------------------------------------------------------------------
   Accents "primary" (teal KBmax) légers, appliqués globalement : uniquement du
   texte / des liserés, jamais de fond primary (règle UI : un peu de primary partout,
   sans aplat). Pilotés par --mud-palette-primary pour suivre le thème (clair/sombre).
   --------------------------------------------------------------------------- */

/* En-têtes de tableaux (MudTable/MudSimpleTable) : libellés en texte secondaire et fin liseré sous
   la ligne d'en-tête. Ils étaient en accent, ce qui les faisait lire comme des liens cliquables
   alors que seules certaines colonnes le sont — l indication de tri s en charge désormais. */
/* Spécificité à 3 classes (.mud-table ...) pour battre la règle par défaut de MudBlazor, sinon
   les colonnes triables reprennent leur couleur via .mud-table-sort-label. */
.mud-table .mud-table-head .mud-table-cell,
.mud-table .mud-table-head .mud-table-sort-label {
    color: var(--cfg-muted);
    font-weight: 600;
}

/* Chevron de tri visible en permanence, en retrait : MudBlazor le laisse à opacité 0 tant que la
   colonne n est pas triée, si bien que rien ne distingue une colonne triable d une autre. Exclut
   les deux états actifs, dont l opacité pleine doit rester prioritaire. */
.mud-table .mud-table-head .mud-table-sort-label .mud-table-sort-label-icon:not(.mud-direction-asc):not(.mud-direction-desc) {
    opacity: 0.4;
}

.mud-table .mud-table-head .mud-table-row {
    border-bottom: 2px solid var(--cfg-accent-line);
}

/* En-tête <thead> des MudSimpleTable (tableaux produit) : libellés teal + gras, et liseré teal
   sous l'en-tête (séparateur head/body). Les liserés début/fin de tableau et de total sont portés
   par ProduitCard.razor.

   Sélecteur aussi profond que celui de MudBlazor (.mud-simple-table table * tr>th, spécificité
   0,1,4) : un simple ".mud-simple-table thead th" (0,1,2) perdait font-weight et border-bottom.
   Restreint à thead : les codes articles du corps sont eux aussi des <th> et gardent leur rendu. */
.mud-simple-table table thead tr > th {
    color: var(--cfg-muted);
    font-weight: 700;
    /* Liseré en accent-line (30 %) et non en accent plein, comme la planche. */
    border-bottom: 2px solid var(--cfg-accent-line);
}

/* Titres de page (MudText Typo.h4) : petit liseré teal à gauche en repère de section. */
.mud-typography-h4 {
    border-left: 3px solid var(--mud-palette-primary);
    padding-left: 0.6rem;
}

/* En-têtes de cartes (MudCardHeader) : fin séparateur teal sous le titre. */
.mud-card-header {
    border-bottom: 1px solid var(--cfg-line);
}

/* Carte de totaux (PrixResumeAffiche, mode Detailed) : chiffres en colonnes alignées (tabular-nums)
   et un peu d'air vertical quand la ligne passe à la ligne (Wrap). Le total est mis en avant en teal
   directement dans le composant. */
.prix-resume-detaille {
    row-gap: 0.75rem;
}

.prix-resume-detaille .mud-typography {
    font-variant-numeric: tabular-nums;
}

.prix-resume-total {
    padding-left: 0.25rem;
}

    /* Total mis en avant comme le bandeau de la maquette (~1.7rem, teal). */
    .prix-resume-total .mud-typography-h5 {
        font-size: 1.7rem;
        line-height: 1.1;
        letter-spacing: -0.02em;
    }

/* Chevron aligné sur la ligne de base des valeurs (pas centré verticalement sur les libellés). */
.prix-resume-detaille .prix-chevron {
    align-self: center;
}

/* ---------------------------------------------------------------------------
   Chiffres "instrument de chiffrage" : monospace tabulaire sur les valeurs de prix/quantité,
   comme la maquette validée. Appliqué globalement, sans toucher aux libellés/textes.
   --------------------------------------------------------------------------- */
:root {
    --cfg-mono: "Cascadia Code", "SFMono-Regular", "Consolas", "Liberation Mono", ui-monospace, monospace;
    --cfg-ui: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

    /* Tokens de la planche. Aucune couleur en dur ici : chaque token alias une variable de palette
       posee dans AppTheme.cs pour les deux themes (voir le tableau de correspondance dans ce fichier).
       C'est ce qui rend le mode sombre automatique — auparavant les accents etaient des rgba fixes
       calibres pour du blanc, invisibles sur une surface sombre.

       Attention : le slot MudBlazor s'ecrit BackgroundGray (orthographe americaine). L'ancienne
       variable --mud-palette-background-grey n'existe pas en v9 : --cfg-surface-2 etait donc invalide,
       et les fonds de champs et de vignettes n'etaient jamais appliques. */
    --cfg-ground: var(--mud-palette-background);         /* fond de page */
    --cfg-surface: var(--mud-palette-surface);           /* cartes */
    --cfg-surface-2: var(--mud-palette-background-gray); /* fond leger des champs / vignettes */
    --cfg-ink: var(--mud-palette-text-primary);          /* texte principal */
    --cfg-muted: var(--mud-palette-text-secondary);      /* texte secondaire (libelles, legendes) */
    --cfg-faint: var(--mud-palette-text-disabled);       /* texte tertiaire (unites, meta) */
    --cfg-line: var(--mud-palette-lines-default);        /* bordures de cartes */
    --cfg-line-soft: var(--mud-palette-divider);         /* separateurs internes discrets */
    --cfg-accent: var(--mud-palette-primary);            /* accent (teal par defaut, au choix de l'utilisateur) */
    --cfg-accent-strong: var(--mud-palette-tertiary);    /* accent renforce (focus, survol) */
    --cfg-accent-line: var(--mud-palette-lines-inputs);  /* lisere d'accent (soulignements, chevrons) */
    --cfg-accent-tint: var(--mud-palette-table-hover);   /* fond d'accent tres leger (ligne selectionnee) */
    /* Accent independant du theme : le recapitulatif du configurateur reste en clair (il jouxte
       l'iframe KBmax), il lui faut donc la variante claire meme en mode sombre. Voir AppTheme.Info. */
    --cfg-accent-fixe: var(--mud-palette-info);
    --cfg-success: var(--mud-palette-success);
    --cfg-warning: var(--mud-palette-warning);
    --cfg-critical: var(--mud-palette-error);

    /* Ombres : la couleur est portee par le theme (AppTheme.OverlayDark), pas figee ici. */
    --cfg-shadow-sm: 0 1px 2px var(--mud-palette-overlay-dark);
    --cfg-shadow: 0 1px 2px var(--mud-palette-overlay-dark), 0 8px 24px var(--mud-palette-overlay-dark);
}

/* Alignement des chiffres dans tous les tableaux (colonnes de nombres qui se lisent en colonne). */
.mud-table .mud-table-cell,
.mud-simple-table td,
.mud-simple-table th {
    font-variant-numeric: tabular-nums;
}

/* Cellules numériques (alignées à droite) des tableaux produit en monospace : colonnes de prix,
   remises, marges, totaux — le code article (aligné à gauche) reste en police d'interface. */
.mud-simple-table td[style*="text-align:right"],
.mud-simple-table th[style*="text-align:right"] {
    font-family: var(--cfg-mono);
    font-variant-numeric: tabular-nums;
}

/* Valeurs de prix/total (PrixResumeAffiche, cartes de totaux, colonnes Total des listes). */
.prix-num {
    font-family: var(--cfg-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

/* Même règle sur une cellule de MudTable : MudBlazor impose la police via
   .mud-table-root .mud-table-body .mud-table-cell (0,3,0), qui bat .prix-num seul. */
.mud-table .mud-table-body .mud-table-cell.prix-num {
    font-family: var(--cfg-mono);
    font-variant-numeric: tabular-nums;
}

/* Navigation latérale : repère teal sur l'entrée active (comme la sidebar de la maquette). */
.mud-nav-link { position: relative; }
.mud-nav-link.active:not(.mud-nav-link-disabled) {
    color: var(--mud-palette-primary);
    font-weight: 600;
}
.mud-nav-link.active:not(.mud-nav-link-disabled)::before {
    content: "";
    position: absolute;
    left: 0; top: 8px; bottom: 8px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--mud-palette-primary);
}

/* Entrée sélectionnée de la nav des familles (ConfigurateurSelectionDialog) : même langage que
   .mud-nav-link.active ci-dessus — accent teal seul, jamais d'aplat primary. */
/* Sélecteur profond : MudBlazor colore ses entrées via .mud-navmenu .mud-nav-item .mud-nav-link
   (0,3,0), qui l'emportait sur un simple .mud-nav-link.cfg-cat-active (0,2,0) — la catégorie
   sélectionnée gardait donc le gris de texte par défaut. */
.mud-navmenu .mud-nav-item .mud-nav-link.cfg-cat-active,
.mud-nav-link.cfg-cat-active {
    color: var(--mud-palette-primary);
    font-weight: 600;
    background-color: var(--cfg-accent-tint);
}

    .mud-nav-link.cfg-cat-active::before {
        content: "";
        position: absolute;
        left: 0; top: 8px; bottom: 8px;
        width: 3px;
        border-radius: 0 3px 3px 0;
        background: var(--mud-palette-primary);
    }

/* ===========================================================================
   Theming renforcé : rapproche MudBlazor de la maquette validée, uniquement en CSS.
   Police système, boutons en casse normale, en-têtes de tableaux facon "instrument",
   survols et navigation teal. Rafraîchir (Ctrl+F5) pour voir.
   =========================================================================== */

/* Police système (plus nette que Roboto), sauf les chiffres monospace (.prix-num). */
.mud-typography:not(.prix-num),
.mud-input-root, .mud-input-slot, .mud-select,
.mud-button-root, .mud-table, .mud-simple-table,
.mud-nav-link, .mud-chip {
    font-family: var(--cfg-ui);
}

/* Champs de saisie et listes déroulantes en graisse normale, quelle que soit celle de leur
   contexte. Aucune règle de cette feuille ne les met en gras : ils l'HÉRITENT du bloc qui les
   accueille (ligne de total, en-tête de carte, cellule de tableau). Une valeur saisie paraissait
   alors plus importante qu'une valeur calculée, sans que rien ne le justifie. Poids posé sur le
   champ lui-même : une déclaration directe l'emporte toujours sur un héritage. */
.mud-input-root,
.mud-input-slot,
.mud-select .mud-input-root,
.mud-input-root input,
.mud-input-root textarea,
.produit-edit-input {
    font-weight: 400;
    font-size: 1rem;
    color: var(--mud-palette-text-primary);
}

/* Le noir dur n'existe nulle part ailleurs dans la palette : le texte saisi prend l'encre du thème
   (--cfg-ink en clair, --cfg-ink-dark en sombre), comme n'importe quel texte de la page. */
.mud-input-root,
.mud-input-slot,
.mud-input-root input,
.mud-input-root textarea {
    font-family: var(--cfg-ui);
}

/* Titres resserrés (poids + interlettrage négatif comme la maquette). */
.mud-typography-h4,
.mud-typography-h5,
.mud-typography-h6 {
    font-weight: 700;
    letter-spacing: -0.012em;
}
.mud-typography-subtitle1 { font-weight: 600; }

/* ...mais pas dans un champ ni dans une liste de choix. MudBlazor pose mud-typography-subtitle1 sur
   le texte de ses items (MudListItem, donc MudSelectItem) : la règle ci-dessus, pensée pour des
   sous-titres, mettait en gras les options d'un select et le texte saisi. Une valeur qu'on choisit
   ou qu'on tape n'est pas un titre. */
.mud-input-control .mud-typography-subtitle1,
.mud-select .mud-typography-subtitle1,
.mud-list .mud-typography-subtitle1,
.mud-list-item .mud-typography-subtitle1,
.mud-popover .mud-typography-subtitle1 {
    font-weight: 400;
}

/* Boutons : casse normale (MudBlazor met en MAJUSCULES par défaut), poids maquette. */
.mud-button-root {
    text-transform: none;
    font-weight: 650;
    letter-spacing: 0;
}

/* Onglets : la planche les écrit en casse normale ("Informations générales"), MudBlazor les met
   en capitales. .mud-tab ne porte pas .mud-button-root, d'où cette règle distincte.

   flex-shrink/min-width : MudBlazor fige les onglets (flex-shrink:0), si bien que dans le rail de
   360px les deux onglets débordaient et la barre basculait en mode défilement — "Mes Clients" se
   retrouvait tronqué en "M" entre deux flèches. Les autoriser à se réduire les fait tenir. */
.mud-tab {
    text-transform: none;
    font-weight: 650;
    letter-spacing: 0;
    font-size: 0.78rem;
    padding: 8px 12px;
    min-height: 40px;
    flex-shrink: 1;
    min-width: 0;
}

/* En-têtes de tableaux facon "instrument" : petites majuscules espacées (le teal est déjà posé plus haut).
   Même remarque de spécificité que plus haut pour les MudSimpleTable. */
.mud-table .mud-table-head .mud-table-cell,
.mud-table .mud-table-head .mud-table-sort-label,
.mud-simple-table table thead tr > th {
    text-transform: uppercase;
    font-size: 0.68rem;
    letter-spacing: 0.05em;
}

/* Toute la ligne ouvre la version : le curseur doit l'annoncer, sinon rien ne distingue la ligne
   d'un tableau simplement consultable. */
.cfg-row-clickable {
    cursor: pointer;
}

/* Vue par offre : l'en-tête de colonnes est déjà porté par la vue à plat et par le titre du panneau.
   Le répéter dans chacun des accordéons dépliés remplirait l'écran d'intitulés en majuscules. */
.cfg-versions-groupe .mud-table-head {
    display: none;
}

/* Survol de ligne en teal très léger (au lieu du gris MudBlazor). */
.mud-table-hover tbody .mud-table-row:hover {
    background-color: var(--cfg-accent-tint) !important;
}

/* Navigation latérale : survol teal discret. */
.mud-navmenu .mud-nav-link:hover {
    background-color: var(--cfg-accent-tint);
}

/* Carte utilisateur en tête du tiroir : avatar (initiales dégradé teal ou image) + nom + rôle,
   sur fond léger bordé (maquette). */
.sidebar-user {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px;
    /* Bordure et fond teintés à l'accent plutôt qu'aux neutres : la carte utilisateur jouxte le
       logo et les icônes du menu, tous deux à l'accent, et tranchait en gris au milieu. */
    border: 1px solid var(--cfg-accent-line);
    border-radius: 8px;
    background: var(--cfg-accent-tint);
}

.sidebar-user-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: conic-gradient(from 210deg, var(--cfg-accent), var(--cfg-accent-strong));
    color: #fff;
    font-size: 0.72rem;
    font-weight: 700;
    display: grid;
    place-items: center;
    flex: none;
    overflow: hidden;
}

.sidebar-user-info {
    min-width: 0;
    line-height: 1.2;
    flex: 1;
}

    /* Le nom porte l'accent : c'est le mot par lequel on se reconnaît, et il raccroche la carte au
       reste du tiroir. Le prénom suit en dessous, dans le gris de texte secondaire — deux lignes de
       même corps, une seule identité, et non un titre et son sous-titre. */
    .sidebar-user-info b {
        display: block;
        font-size: 0.82rem;
        font-weight: 700;
        color: var(--cfg-accent);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Même troncature sur les deux lignes : les noms longs débordaient de la carte. */
    .sidebar-user-info span {
        display: block;
        font-size: 0.82rem;
        color: var(--cfg-muted);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

/* Carte de totaux (récap en bas de page) : liseré teal à gauche, comme le bandeau de la maquette. */
.mud-paper:has(> .prix-resume-detaille) {
    border-left: 3px solid var(--mud-palette-primary);
}

/* Un peu plus d'air à l'intérieur des cartes de contenu (rythme de la maquette). */
.mud-card-content { padding: 16px; }

/* Tuiles KPI (Statistiques) : fin liseré teal à gauche, accent "instrument" — jamais de fond primary.
   Les chiffres teal/monospace viennent de Color.Primary + .prix-num posés dans le razor. */
.stat-kpi { border-left: 3px solid var(--mud-palette-primary); }

/* Graphe étiré sur toute la largeur de sa carte.
   Le SVG de MudChart a un viewBox de proportions fixes ; avec une hauteur imposée, le navigateur
   conserve ce rapport (preserveAspectRatio) et centre le dessin, d'où les larges marges vides de
   part et d'autre. En laissant la hauteur se déduire de la largeur, le tracé occupe toute la carte.
   min-width:fit-content de MudBlazor l'empêchait par ailleurs de suivre son conteneur. */
.cfg-graph .mud-chart {
    width: 100%;
    min-width: 0;
    height: auto !important;
}

    /* Pas de max-height : elle rétablissait la mise en boîte que height:auto vient justement d'éviter.
       Le viewBox de MudChart étant de proportions fixes, occuper toute la largeur implique une hauteur
       proportionnelle — c'est le prix à payer pour un tracé non déformé (preserveAspectRatio="none"
       étirerait aussi les libellés d'axe). */
    .cfg-graph .mud-chart svg {
        width: 100% !important;
        height: auto !important;
    }

    /* Libellés d'axe et de barres : lisibles quelle que soit l'échelle du SVG. */
    .cfg-graph .mud-chart text {
        font-family: var(--cfg-mono);
        font-size: 11px;
        fill: var(--cfg-muted);
    }

/* Titre de groupe de la barre latérale, avec la valeur active EN DESSOUS du nom du menu plutôt
   qu'accolée sur la même ligne — le nom du menu reste ainsi immédiatement lisible. */
.cfg-nav-titre {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    min-width: 0;
}

    .cfg-nav-titre small {
        font-size: 0.64rem;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: var(--cfg-accent);
        font-weight: 700;
        margin-top: 2px;
    }

/* Légende du graphe, qui fait aussi office de sélecteur de séries. */
.cfg-graph-legende {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    justify-content: center;
    margin-top: 10px;
}

.cfg-legende-item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--cfg-ink);
    font: inherit;
    font-size: 0.78rem;
    padding: 3px 9px;
    border-radius: 999px;
    cursor: pointer;
}

    .cfg-legende-item:hover {
        border-color: var(--cfg-accent-line);
        background: var(--cfg-accent-tint);
    }

    /* Série masquée : texte barré et estompé, pour qu'on voie qu'elle existe mais n'est pas tracée. */
    .cfg-legende-item.off {
        color: var(--cfg-faint);
        text-decoration: line-through;
    }

    /* Légende purement descriptive (graphe d'évolution) : rien à cliquer, donc pas de curseur ni de
       survol qui laisseraient croire le contraire. */
    .cfg-legende-item.statique {
        cursor: default;
    }

        .cfg-legende-item.statique:hover {
            border-color: transparent;
            background: transparent;
        }

    /* Estompé ≠ masqué : dans le donut, seule la part survolée reste vive. Pas de texte barré, qui
       signifierait « série désactivée » (voir .off ci-dessus). */
    .cfg-legende-item.estompe {
        color: var(--cfg-faint);
    }

.cfg-legende-pastille {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: none;
}

.cfg-legende-trait {
    width: 16px;
    height: 3px;
    border-radius: 2px;
    flex: none;
}

/* Graphe d'évolution et donut : SVG écrits par l'application (et non par MudChart), donc stylables
   en CSS — les variables de thème y fonctionnent, contrairement aux attributs de présentation que
   MudChart écrit lui-même. */
.cfg-graph-combo svg,
.cfg-donut svg {
    width: 100%;
    height: auto;
    display: block;
    font-family: var(--cfg-ui);
}

.cfg-donut svg {
    max-width: 320px;
    margin: 0 auto;
}

.cfg-graph-combo .g-grille {
    stroke: var(--cfg-line-soft);
    stroke-width: 1;
}

.cfg-graph-combo .g-axe {
    stroke: var(--cfg-line);
    stroke-width: 1.5;
}

.cfg-graph-combo .g-texte {
    fill: var(--cfg-muted);
    font-size: 13px;
    font-family: var(--cfg-mono);
}

.cfg-donut .s {
    transition: opacity 120ms ease;
    cursor: default;
}

    .cfg-donut .s.off {
        opacity: 0.35;
    }

/* Infobulle du donut : position:fixed, donc posée dans le repère du viewport — c'est ce que fournit
   ClientX/ClientY. Le décalage de 16px la sort de sous le pointeur, et pointer-events:none l'empêche
   de voler le survol au secteur, ce qui la ferait clignoter. */
.cfg-donut-bulle {
    position: fixed;
    z-index: 1400;
    transform: translate(16px, 16px);
    pointer-events: none;
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-width: 260px;
    padding: 8px 12px;
    border-radius: 8px;
    border: 1px solid var(--cfg-line);
    background: var(--cfg-surface);
    box-shadow: var(--cfg-shadow);
    font-size: 0.8rem;
    color: var(--cfg-ink);
}

    .cfg-donut-bulle .b-titre {
        display: inline-flex;
        align-items: center;
        gap: 7px;
        font-weight: 600;
    }

    .cfg-donut-bulle .b-ligne {
        font-family: var(--cfg-mono);
        color: var(--cfg-muted);
    }

    .cfg-donut-bulle .b-montant {
        color: var(--cfg-accent);
    }

/* Tableaux de détail des Statistiques : jamais d'ascenseur horizontal. Les colonnes se compressent
   (table-layout auto + césure autorisée) et la carte passe en pleine largeur quand le mode
   d'affichage en ouvre beaucoup. Chiffres un cran plus petits pour tenir sans rogner. */
.cfg-tableau-stats {
    max-width: 100%;
    overflow-x: hidden;
}

    /* Retour à la ligne AUX ESPACES uniquement. Un overflow-wrap:anywhere coupait au milieu des mots
       ("PÉRIOD E", "TRANSPOR T") et scindait les montants ("26 708,87" sur deux lignes). */
    .cfg-tableau-stats .mud-table-cell {
        font-size: 0.78rem;
        padding-left: 6px;
        padding-right: 6px;
        white-space: normal;
        overflow-wrap: normal;
        word-break: normal;
        hyphens: none;
    }

    /* Un montant ou un pourcentage ne doit jamais être coupé : il devient illisible. */
    .cfg-tableau-stats .mud-table-cell.prix-num {
        white-space: nowrap;
    }

    /* En-têtes : ils peuvent tenir sur deux lignes, mais chaque mot reste entier. */
    .cfg-tableau-stats .mud-table-head .mud-table-cell {
        line-height: 1.25;
        vertical-align: bottom;
    }

    /* MudTable impose une largeur minimale au tableau interne, qui provoquerait le débordement. */
    .cfg-tableau-stats .mud-table-root {
        min-width: 0;
        table-layout: auto;
    }

    /* Ligne de synthèse (FooterContent) : détachée des lignes triées par un liseré, sinon elle se
       confond avec une ligne de plus, alors qu'elle résume TOUTE la période/répartition. */
    .cfg-tableau-stats .cfg-tableau-stats-total {
        font-weight: 700;
        border-top: 2px solid var(--mud-palette-primary);
    }

/* ===========================================================================
   Rangées "sur une seule ligne" des Statistiques (filtres et indicateurs).
   Flex plutôt que MudGrid : une grille à 12 colonnes impose une largeur fixe par cellule, alors que
   ces blocs doivent se dimensionner d'après leur contenu — un montant à 7 chiffres n'occupe pas la
   même place qu'un compteur à 2 chiffres. Le nombre de cartes varie en plus selon le rôle et le mode
   d'affichage (le revendeur n'a ni Client ni certains montants), d'où un nombre de colonnes qui ne
   peut pas être écrit en dur.
   =========================================================================== */
.cfg-stats-row {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: stretch;
}

    /* Chaque élément prend au moins sa largeur de contenu et se partage l'espace restant. */
    .cfg-stats-row > * {
        flex: 1 1 auto;
        min-width: 0;
    }

/* Filtres : largeur de base confortable, mais ils se resserrent pour tenir sur une ligne. */
.cfg-stats-row.cfg-stats-filtres > * {
    flex: 1 1 200px;
}

/* Indicateur : valeur et évolution CÔTE À CÔTE (l'évolution était sous la valeur et étirait la
   carte en hauteur), le tout dimensionné par son contenu. */
.stat-kpi {
    display: flex;
    flex-direction: column;
    gap: 2px;
    justify-content: center;
}

    .stat-kpi .stat-kpi-valeur {
        display: flex;
        align-items: baseline;
        gap: 10px;
        flex-wrap: wrap;
    }

/* Sous 900px, les indicateurs repassent sur deux par ligne plutôt que de se comprimer à l'illisible. */
@media (max-width: 900px) {
    .cfg-stats-row > * { flex: 1 1 45%; }
}

@media (max-width: 600px) {
    .cfg-stats-row > * { flex: 1 1 100%; }
}

/* Titre de section facon "card-head" de la maquette : petit tick teal + titre teal en majuscules.
   Posé en Class sur les MudText de titre de carte (Transport, Documents, Statistiques, Versions...). */
.cfg-section-title {
    color: var(--mud-palette-primary);
    text-transform: uppercase;
    font-size: 0.8rem;
    letter-spacing: 0.05em;
    font-weight: 700;
    display: flex;
    align-items: center;
    gap: 9px;
}

    .cfg-section-title::before {
        content: "";
        width: 3px;
        height: 14px;
        border-radius: 2px;
        background: var(--mud-palette-primary);
        flex: none;
    }

/* Petit intitulé de colonne (Mode / Destination du transport) : teal, majuscules, sans tick (.colh maquette). */
.cfg-colh {
    color: var(--mud-palette-primary);
    text-transform: uppercase;
    font-size: 0.68rem;
    letter-spacing: 0.06em;
    font-weight: 700;
}

/* Bouton "ajouter un produit non configurable" en pointillés (maquette). */
.btn-dashed { border-style: dashed !important; }

/* Avatar de repli du propriétaire (planche : .owner .av) : initiales sur teinte d'accent. */
.cfg-avatar-initiales {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--cfg-accent-tint);
    color: var(--cfg-accent);
    display: grid;
    place-items: center;
    font-size: 0.62rem;
    font-weight: 700;
    flex: none;
}

/* ---------------------------------------------------------------------------
   Couleurs des badges d'état (EtatChip). Elles ne servent QU'À CELA et ne sont donc pas versées
   dans la palette : gris, vert, orange et rouge reprennent les roles neutres deja presents
   (--cfg-muted / success / warning / critical), qui suivent le theme d'eux-memes.

   Le violet de l'expiration est la seule couleur reellement nouvelle, et aucun emplacement de la
   palette ne pouvait la porter : Primary, Secondary, Tertiary et Info portent l'accent CHOISI par
   l'utilisateur et viraient au vert ou au rouge selon son choix, faisant dire n'importe quoi au
   badge. Il lui faut deux valeurs — un violet lisible sur blanc est trop sombre pour la surface
   sombre, et l'inverse — d'ou le marqueur data-cfg-theme pose sur <html> (App.razor au rendu
   serveur, layoutInterop.setThemeAttribute a la bascule). MudBlazor n'expose aucun marqueur de ce
   genre : il se contente de reecrire ses propres variables.

   Le fond reprend la teinte du texte a 12 %, comme la pastille de la planche.
   --------------------------------------------------------------------------- */
.cfg-etat.mud-chip {
    color: var(--cfg-etat-teinte);
    background-color: color-mix(in srgb, var(--cfg-etat-teinte) 12%, transparent);
    max-width: 100%;
}

/* Une seule ligne, tronquée avec puce si la colonne État est plus étroite que le libellé (les
   libellés de publication sont bien plus longs que "Validée"/"Expirée") : le texte complet reste
   accessible via l'infobulle du chip (title). min-width:0 est nécessaire pour qu'un enfant flex
   accepte de rétrécir sous sa largeur naturelle — sans lui, l'ellipse ne se déclenche jamais. */
.cfg-etat-texte {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.cfg-etat-neutre    { --cfg-etat-teinte: var(--cfg-muted); }
.cfg-etat-valide    { --cfg-etat-teinte: var(--cfg-success); }
.cfg-etat-encours   { --cfg-etat-teinte: var(--cfg-warning); }
.cfg-etat-erreur    { --cfg-etat-teinte: var(--cfg-critical); }
.cfg-etat-expire    { --cfg-etat-teinte: #6B4FA8; }

[data-cfg-theme="dark"] .cfg-etat-expire { --cfg-etat-teinte: #B49BE8; }

/* Publication en cours (EtatChip) : le sablier de MudBlazor remplace le point fixe. La couleur d'un
   état transitoire (orange) ne se distinguait pas d'un état simplement en attente ; une animation, si. */
.cfg-etape-spinner {
    width: 10px !important;
    height: 10px !important;
    margin-right: 6px;
    flex: none;
    /* MudProgressCircular se peint en --mud-palette-text-secondary : le sablier restait gris au
       milieu d'une pastille orange. Le trait suit currentColor, il suffit d'heriter de la pastille. */
    color: inherit;
}

/* Rien à animer pour qui a demandé moins de mouvement : le sablier reste, figé, et la couleur
   ainsi que l'infobulle continuent de porter l'information. */
@media (prefers-reduced-motion: reduce) {
    .cfg-etape-travail .mud-progress-circular-circle {
        animation: none;
    }
}

/* Radios du rail : un libellé sur plusieurs lignes ("Transport inclus, détaillé par produit" dans
   une colonne de 360px) centrait la puce verticalement, loin de la première ligne de texte. */
.mud-radio {
    align-items: flex-start;
}

/* Champ du rail (planche : .field) : libellé statique en petites majuscules AU-DESSUS du champ,
   au lieu du libellé flottant de MudBlazor. */
.cfg-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.cfg-field-label {
    font-size: 0.64rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--cfg-muted);
    font-weight: 600;
}

/* Carte Documents pendant la publication : lignes fantômes à la place des documents à venir.
   Les hauteurs et l'écartement reprennent ceux d'un MudListItem dense, pour que la liste réelle
   prenne exactement la place des fantômes sans décaler la page à la fin de la génération. */
.cfg-doc-attente {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 4px 0;
}

    .cfg-doc-attente .cfg-doc-attente-ligne {
        display: flex;
        align-items: center;
        gap: 12px;
        height: 24px;
    }

/* Titre de page du topbar (planche : .crumb h1) : titre et numéro sur une seule ligne. */
.cfg-page-title {
    margin: 0;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--cfg-ink);
}

/* Point de la pastille d'état (planche : .pill .dot) : reprend la couleur du texte de la pastille. */
.mud-chip .cfg-dot,
.cfg-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    display: inline-block;
    flex: none;
    margin-right: 6px;
}

/* ===========================================================================
   Grille du détail d'offre (planche : .content). Une colonne principale fluide + un rail de
   largeur FIXE 360px. MudGrid ne sait faire que du proportionnel : md="4" donnait un rail à 33 %,
   soit ~560px sur un écran large, très loin de la planche.
   align-items:start évite que les cartes s'étirent à la hauteur de la colonne voisine.
   =========================================================================== */
.cfg-detail-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: 18px;
    align-items: start;
}

    /* Colonnes : les cartes s'empilent avec le même rythme que la planche (.col). */
    .cfg-detail-grid > .cfg-detail-col {
        display: flex;
        flex-direction: column;
        gap: 18px;
        min-width: 0; /* sans quoi un tableau large déborde de la colonne au lieu de défiler */
    }

@media (max-width: 1240px) {
    .cfg-detail-grid { grid-template-columns: minmax(0, 1fr); }
}

/* Pied des tableaux produit (planche : tfoot tr.unit / tr.ensembles). La ligne de prix unitaire est
   en retrait (texte secondaire), la ligne "nombre d'ensembles" ferme le tableau entre deux liserés
   et son intitulé passe en accent teal majuscules. Sélecteur profond pour battre
   .mud-simple-table table * tr>td (0,1,4) de MudBlazor. */
.mud-simple-table table tfoot tr.cfg-foot-unit > td {
    border-top: 2px solid var(--cfg-accent-line);
    color: var(--cfg-muted);
}

/* Pas de border-bottom ici : la dernière ligne du pied coïncide avec le bas du tableau, qui porte
   déjà son propre liseré. Les deux se cumulaient en un trait de 4px, deux fois plus épais que le
   liseré du haut. */
.mud-simple-table table tfoot tr.cfg-foot-total > td {
    font-weight: 700;
    border-top: 2px solid var(--cfg-accent-line);
}

    .mud-simple-table table tfoot tr.cfg-foot-total > td:first-child {
        color: var(--cfg-accent);
        text-transform: uppercase;
        font-size: 0.7rem;
        letter-spacing: 0.05em;
    }

/* ===========================================================================
   Pages d'authentification (AuthShell + connexion / mot de passe). Thème-aware
   (variables de palette) : rendu cohérent en clair et en sombre.
   =========================================================================== */
.auth-page {
    min-height: 100dvh;
    display: grid;
    place-items: center;
    padding: 24px 16px;
    background: radial-gradient(1100px 560px at 50% -12%, var(--cfg-accent-tint), transparent 62%), var(--cfg-ground);
}

.auth-card {
    width: 100%;
    max-width: 430px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 16px;
    box-shadow: var(--cfg-shadow);
    padding: 40px 36px;
}

.auth-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 28px;
}

.auth-mark {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: var(--cfg-accent-tint);
    border: 1px solid var(--cfg-accent-line);
    color: var(--mud-palette-primary);
    display: grid;
    place-items: center;
    flex: none;
}

    /* 30 et non 24 : le tracé ne remplit pas son viewBox (voir AuthShell.razor), la marque paraissait
       perdue au milieu de la tuile de 44px. */
    .auth-mark svg { width: 30px; height: 30px; }

.auth-name {
    font-weight: 800;
    letter-spacing: 0.02em;
    font-size: 1.05rem;
    line-height: 1.05;
    color: var(--mud-palette-text-primary);
}

    .auth-name small {
        display: block;
        font-weight: 600;
        color: var(--cfg-faint);
        font-size: 0.6rem;
        letter-spacing: 0.16em;
        margin-top: 3px;
    }

.auth-title {
    text-align: center;
    margin: 0 0 5px;
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--mud-palette-text-primary);
}

.auth-subtitle {
    margin: 0 0 20px;
    color: var(--mud-palette-text-secondary);
    font-size: 0.9rem;
    line-height: 1.4;
}

.auth-body {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

    /* La page de connexion enveloppe tout son contenu dans un <EditForm> : c'est alors un enfant
       flex unique, et le gap de .auth-body ne separe plus rien. Le formulaire porte donc son propre
       rythme, au lieu des marges mt-3/mt-4 posees au cas par cas dans le razor. */
    .auth-body form {
        display: flex;
        flex-direction: column;
        gap: 20px;
    }

/* Champs "maison" du formulaire de connexion (SSR statique : pas de MudTextField interactif). */
.auth-field {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

    .auth-field > label {
        font-size: 0.72rem;
        font-weight: 650;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: var(--mud-palette-text-secondary);
    }

.auth-input-wrap {
    position: relative;
    display: flex;
    align-items: center;
}

    .auth-input-wrap .auth-lead {
        position: absolute;
        left: 12px;
        display: grid;
        place-items: center;
        color: var(--cfg-faint);
        pointer-events: none;
    }

        .auth-input-wrap .auth-lead svg { width: 18px; height: 18px; }

.auth-input {
    width: 100%;
    box-sizing: border-box;
    padding: 13px 42px 13px 40px;
    border: 1px solid var(--mud-palette-lines-default);
    border-bottom: 2px solid var(--cfg-accent-line);
    border-radius: 10px;
    background: var(--cfg-surface-2);
    color: var(--mud-palette-text-primary);
    font-size: 0.95rem;
    font-family: inherit;
    transition: border-color 0.15s, box-shadow 0.15s;
}

    .auth-input:focus {
        outline: none;
        border-color: var(--mud-palette-primary);
        box-shadow: 0 0 0 3px var(--cfg-accent-tint);
    }

.auth-toggle {
    position: absolute;
    right: 8px;
    border: none;
    background: transparent;
    cursor: pointer;
    color: var(--cfg-faint);
    padding: 6px;
    border-radius: 8px;
    display: grid;
    place-items: center;
}

    .auth-toggle:hover {
        color: var(--mud-palette-primary);
        background: var(--cfg-accent-tint);
    }

    .auth-toggle svg { width: 18px; height: 18px; }
    .auth-toggle .eye-off { display: none; }
    .auth-toggle.on .eye-on { display: none; }
    .auth-toggle.on .eye-off { display: inline; }

.auth-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

/* Bouton d'action un cran plus detache que le reste du rythme. */
.auth-body form > .mud-button-root {
    margin-top: 6px;
}

.auth-remember {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 0.86rem;
    color: var(--mud-palette-text-secondary);
    cursor: pointer;
}

.auth-link {
    color: var(--mud-palette-primary);
    font-weight: 600;
    text-decoration: none;
    font-size: 0.86rem;
}

    .auth-link:hover { text-decoration: underline; }

.auth-foot {
    margin-top: 18px;
    text-align: center;
}

/* Checklist des règles de mot de passe (validation live). */
.auth-rules {
    list-style: none;
    margin: 2px 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

    .auth-rules li {
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: 0.8rem;
        color: var(--cfg-faint);
        transition: color 0.15s;
    }

        .auth-rules li.ok { color: var(--mud-palette-success); }

        .auth-rules li .tick {
            width: 16px;
            height: 16px;
            flex: none;
            display: grid;
            place-items: center;
        }

            .auth-rules li .tick svg { width: 16px; height: 16px; }

/* Thème "dashboard" (maquette Statistiques) : fond de page gris clair (AppTheme.Default.Background)
   visible derrière les cartes blanches, avec des ombres plus douces que l'élévation Material par
   défaut de MudBlazor (trop marquée pour ce rendu plus plat). */
body {
    /* Suit la palette du thème (clair : gris froid AppTheme.FondPage ; sombre : fond sombre MudBlazor),
       de sorte que le mode sombre s'applique aussi au fond de page. Le contraste avec les cartes
       blanches (mode clair) fait ressortir les cartes, comme la maquette. */
    background-color: var(--mud-palette-background);
}

.mud-paper.mud-elevation-1, .mud-paper.mud-elevation-2 {
    box-shadow: var(--cfg-shadow) !important;
    /* Variable de lignes du thème : bordure visible aussi bien en clair (gris) qu'en sombre (clair). */
    border: 1px solid var(--cfg-line);
}

/* Légendes/libellés en Color.Secondary (KPI, champs de filtre...) : petites majuscules espacées,
   comme dans la maquette, plutôt que du texte minuscule classique. */
.mud-typography-caption.mud-secondary-text {
    text-transform: uppercase;
    letter-spacing: .03em;
}


h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--cfg-success);
}

.invalid {
    outline: 1px solid var(--cfg-critical);
}

.validation-message {
    color: var(--cfg-critical);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

.cursor-pointer {
    cursor: pointer;
}

.dashboard-table .mud-table-container {
    max-height: 22rem;
    overflow-y: auto;
}

/* Pas de display:block ici : la classe est portée par des CELLULES. Sur un <td> de la vue par
   offre — qui n a pas les surcharges de MudTable — elle sortait la cellule du flux du tableau et
   les colonnes se superposaient. text-overflow suffit sur une table-cell qui a un max-width. */
.dashboard-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ===========================================================================
   LISTES DE VERSIONS — deux rendus, un seul visible
   ===========================================================================
   Le tableau (.cfg-liste-large) et la liste de cartes (.cfg-liste-etroite) sont écrits tous les deux
   dans le DOM ; ces règles n'en montrent qu'un. Faire rétrécir un unique tableau de 8 à 11 colonnes
   jusqu'au téléphone a été tenté et échoue : l'empilement automatique de MudBlazor se déclenche sur
   la largeur de la FENÊTRE, alors que la place disponible dépend aussi du tiroir latéral (240px).
   Tiroir ouvert, la fenêtre annonce 1400px quand le tableau n'en a que 900 — d'où les colonnes qui
   se superposaient. Le composant est donc en Breakpoint.None et tout se décide ici, sur la largeur
   du conteneur. */

/* Le seul point de mesure de tout ce qui suit. */
.cfg-vue-liste {
    container-type: inline-size;
    container-name: liste;
}

.cfg-liste-etroite,
.cfg-barre-tri {
    display: none;
}

/* Quatre paliers, un par nombre de colonnes affichées (rôle, mode d'affichage des prix, contexte).
   C'est VersionsListeTable.LargeurMiniTableau() qui additionne les colonnes et choisit la classe :
   une requête de conteneur ne peut pas prendre de valeur calculée dans sa condition, d'où des
   paliers discrets plutôt qu'une largeur exacte. Les valeurs ci-dessous doivent rester accordées à
   celles de ClasseSeuil(). */
@container liste (max-width: 720px) {
    .cfg-seuil-s .cfg-liste-large,
    .cfg-seuil-s .cfg-groupes-entete { display: none; }
    .cfg-seuil-s .cfg-liste-etroite { display: block; }
    .cfg-seuil-s .cfg-barre-tri { display: flex; }
}

@container liste (max-width: 920px) {
    .cfg-seuil-m .cfg-liste-large,
    .cfg-seuil-m .cfg-groupes-entete { display: none; }
    .cfg-seuil-m .cfg-liste-etroite { display: block; }
    .cfg-seuil-m .cfg-barre-tri { display: flex; }
}

@container liste (max-width: 1060px) {
    .cfg-seuil-l .cfg-liste-large,
    .cfg-seuil-l .cfg-groupes-entete { display: none; }
    .cfg-seuil-l .cfg-liste-etroite { display: block; }
    .cfg-seuil-l .cfg-barre-tri { display: flex; }
}

@container liste (max-width: 1180px) {
    .cfg-seuil-xl .cfg-liste-large,
    .cfg-seuil-xl .cfg-groupes-entete { display: none; }
    .cfg-seuil-xl .cfg-liste-etroite { display: block; }
    .cfg-seuil-xl .cfg-barre-tri { display: flex; }
}

/* ---------------------------------------------------------------------------
   Rendu large : le tableau
   ---------------------------------------------------------------------------
   Il ne s'affiche plus que lorsqu'il a la place : ses colonnes reprennent donc des largeurs fixes,
   accordées une à une aux valeurs additionnées par LargeurMiniTableau(). Plus de clamp(), plus de
   pourcentages, plus de min-width ni de défilement horizontal — c'est la simplification que les deux
   rendus achètent. Une seule colonne reste élastique, celle de la référence : c'est un texte libre,
   de longueur imprévisible, alors que les composants forment une pile de "Qté × CODE" dont la
   largeur est connue — cette colonne est donc fixée à ce qu'elle demande. */
.cfg-versions-table .mud-table-root {
    table-layout: fixed;
    width: 100%;
}

.cfg-versions-table .cfg-col-liseré { width: 0.4rem; padding: 0; }
.cfg-versions-table .cfg-col-numero { width: 7rem; }
.cfg-versions-table .cfg-col-commentaire { width: 2rem; }
.cfg-versions-table .cfg-col-client,
.cfg-versions-table .cfg-col-contact { width: 8rem; }
.cfg-versions-table .cfg-col-reference { width: auto; min-width: 8rem; }
.cfg-versions-table .cfg-col-etat { width: 6.5rem; }
.cfg-versions-table .cfg-col-composants { width: 11rem; overflow: hidden; }
.cfg-versions-table .cfg-col-prix { width: 6.5rem; }
.cfg-versions-table .cfg-col-proprietaire { width: 7rem; }
.cfg-versions-table .cfg-col-date { width: 6.5rem; }
.cfg-versions-table .cfg-col-actions { width: 2.5rem; }

/* Là où l'offre est déjà nommée au-dessus (groupe déplié, panneau du détail), la colonne ne porte
   qu'un numéro de version à deux chiffres. */
.cfg-versions-vseule .cfg-col-numero {
    width: 2.5rem;
    white-space: nowrap;
}

/* Là, la référence est elle aussi portée par l'en-tête et sa colonne disparaît : sans colonne
   élastique, table-layout: fixed étirerait toutes les autres au prorata. Les composants reprennent
   ce rôle, comme avant. */
.cfg-versions-vseule .cfg-col-composants { width: auto; }

/* MudBlazor réserve 16px à gauche et 24px à droite de chaque cellule, soit 40px de gouttière entre
   deux colonnes voisines. Sur une table qui en compte jusqu'à onze, cet air devenait du vide. */
.cfg-versions-table.mud-table-dense * .mud-table-row .mud-table-cell {
    padding-inline-start: 8px;
    padding-inline-end: 8px;
}

/* ---------------------------------------------------------------------------
   Noms et date : des formes rédigées, pas une forme qui rétrécit
   ---------------------------------------------------------------------------
   Les colonnes Propriétaire et Contact font 7rem et 8rem, avatar compris : "Administrateur
   Com-figure" n'y tiendra jamais sur une ligne. Le nom passe donc sur DEUX lignes quand une seule ne
   suffit pas — même parti que la date, dont l'heure tombe sous le jour — au lieu d'être tronqué
   ("Administrateur Com-figur") ou replié sur l'initiale du prénom. Prénom et nom sont chacun
   insécables : la coupure tombe entre les deux, jamais au milieu de l'un d'eux. Le titre reste
   complet dans tous les cas. */
.cfg-nom {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    max-width: 100%;
}

/* flex-wrap plutôt qu'un retour à la ligne du texte : le navigateur couperait aussi sur les traits
   d'union ("Com-" / "figure"). Ici la seule coupure possible est celle entre les deux morceaux. */
.cfg-nom-texte {
    display: flex;
    flex-wrap: wrap;
    column-gap: 0.25em;
    min-width: 0;
}

/* Un morceau plus large que la colonne s'abrège lui-même — il ne descend pas d'une ligne. */
.cfg-nom-mot {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cfg-nom .cfg-avatar-initiales { white-space: nowrap; }

@container liste (min-width: 1400px) {
    .cfg-liste-large .cfg-col-proprietaire { width: 11rem; }
    .cfg-liste-large .cfg-col-contact { width: 11rem; }
}

.cfg-date {
    display: inline-flex;
    flex-wrap: wrap;
    column-gap: 0.35em;
    font-variant-numeric: tabular-nums;
}

.cfg-date .cfg-heure {
    font-style: italic;
    color: var(--mud-palette-text-secondary);
}

/* Dans le tableau, la colonne de date fait 6.5rem : "03/07/2026 11:56" y déborderait d'une ligne.
   L'heure passe sous la date, sauf quand la largeur revient (même palier que le nom entier). */
.cfg-liste-large .cfg-date { flex-direction: column; }

@container liste (min-width: 1400px) {
    .cfg-liste-large .cfg-date { flex-direction: row; }
}

/* ---------------------------------------------------------------------------
   Rendu étroit : les cartes
   --------------------------------------------------------------------------- */
.cfg-cartes {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px 0;
}

.cfg-carte {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 10px 12px;
    background-color: var(--cfg-surface);
    border: 1px solid var(--cfg-line);
    border-radius: 8px;
    cursor: pointer;
    transition: border-color .12s ease, background-color .12s ease;
}

.cfg-carte:hover {
    border-color: var(--cfg-accent-line);
    background-color: var(--cfg-accent-tint);
}

/* Version en cours de consultation, dans le panneau du détail : même liseré que la ligne
   correspondante du tableau (.vrow-selected). */
.cfg-carte-courante {
    border-color: var(--mud-palette-primary);
    background-color: var(--cfg-accent-tint);
    box-shadow: inset 3px 0 0 var(--mud-palette-primary);
}

.cfg-carte-tete {
    display: flex;
    align-items: center;
    gap: 8px;
}

.cfg-carte-num {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Le menu d'actions est repoussé au bord, là où le pouce le cherche. */
.cfg-carte-menu { margin-left: auto; }

/* Client, contact et référence sur une seule ligne, sans intitulés : trois libellés pèseraient plus
   que les valeurs elles-mêmes sur un téléphone. Le point médian est posé par le CSS pour qu'il
   disparaisse avec la valeur qui le suit. */
.cfg-carte-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 8px;
    color: var(--mud-palette-text-secondary);
    font-size: 0.86rem;
}

.cfg-carte-meta span + span::before {
    content: "·";
    margin-right: 8px;
    color: var(--mud-palette-text-disabled);
}

.cfg-carte-pied {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    padding-top: 6px;
    border-top: 1px solid var(--cfg-line-soft);
    font-size: 0.86rem;
}

.cfg-carte-prix {
    font-weight: 650;
    font-variant-numeric: tabular-nums;
}

/* Dernière information de la carte, calée à droite comme la colonne qu'elle remplace. */
.cfg-carte-pied .cfg-date { margin-left: auto; }

/* ---------------------------------------------------------------------------
   Barre de tri du mode cartes
   ---------------------------------------------------------------------------
   Sans en-tête de colonnes, le tri disparaîtrait. (MudBlazor y substituait une liste déroulante, qui
   triait les versions d'UNE offre — déjà ordonnées par numéro — et venait s'intercaler entre le
   titre de l'offre et ses versions.) */
.cfg-barre-tri {
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 8px 0;
}

.cfg-barre-tri-libelle {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--mud-palette-text-secondary);
    margin-right: 2px;
}

.cfg-barre-tri .cfg-tri-entete {
    border: 1px solid var(--cfg-line);
    border-radius: 999px;
    padding: 2px 10px;
    font-size: 0.8rem;
    color: var(--mud-palette-text-secondary);
}

.cfg-barre-tri .cfg-tri-actif {
    border-color: var(--mud-palette-primary);
    background-color: var(--cfg-accent-tint);
}

/* Intitulé de tri, commun à la barre compacte et à la grille d'en-tête des offres. */
.cfg-tri-entete {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}

.cfg-tri-entete:hover { color: var(--mud-palette-primary); }

.cfg-tri-entete:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
    border-radius: 3px;
}

.cfg-tri-actif {
    color: var(--mud-palette-primary);
    font-weight: 600;
}

.cfg-tri-fleche { font-size: 0.9rem !important; }

/* ===========================================================================
   VUE PAR OFFRE
   ===========================================================================
   L'en-tête des offres (une grille CSS, répétée dans le titre de chaque accordéon) et le tableau des
   versions que porte l'accordéon doivent tomber en face l'un de l'autre. Leurs deux boîtes sont donc
   ramenées au même gabarit — 16px de gouttière de part et d'autre, chevron compris — et leurs deux
   dernières colonnes sont déclarées une seule fois, ci-dessous : c'est ce qui fait tomber la date de
   l'offre au-dessus de celles de ses versions. */
.cfg-vue-liste {
    --cfg-col-date: 6.5rem;
    --cfg-col-actions: 2.5rem;
}

.cfg-groupes-entete,
.cfg-groupe-titre {
    display: grid;
    align-items: center;
    column-gap: 0;
    width: 100%;
    min-width: 0;
}

/* Gouttière portée par les cellules et non par un gap : un gap s'ajouterait aux largeurs et
   décalerait la grille par rapport au tableau. */
.cfg-groupes-entete > *,
.cfg-groupe-titre > * {
    min-width: 0;
    padding-right: 12px;
}

.cfg-g-espace,
.cfg-g-chevron { padding-right: 0; }

.cfg-g-date { white-space: nowrap; }

/* Colonnes : numéro | nb de versions | [client, Comège seul] | référence | écarteur | date |
   chevron. L'écarteur absorbe le surplus : sans lui, la référence s'étirait sur toute la largeur
   libre et éloignait la date de son intitulé. */
.cfg-grille-offre {
    grid-template-columns: 7rem 6rem minmax(0, 16rem) minmax(0, 1fr) var(--cfg-col-date) var(--cfg-col-actions);
}

.cfg-grille-offre-comege {
    grid-template-columns: 7rem 6rem minmax(0, 16rem) minmax(0, 16rem) minmax(0, 1fr) var(--cfg-col-date) var(--cfg-col-actions);
}

.cfg-groupes-entete {
    padding: 6px 16px;
    border-bottom: 1px solid var(--cfg-line);
    color: var(--mud-palette-text-secondary);
    text-transform: uppercase;
    font-size: 0.68rem;
    letter-spacing: 0.05em;
}

/* C'est le numéro qui identifie la carte d'offre. */
.cfg-groupe-numero { font-weight: 700; }

.cfg-groupe-titre .cfg-g-client,
.cfg-groupe-titre .cfg-g-reference,
.cfg-groupe-titre .cfg-g-date {
    color: var(--mud-palette-text-secondary);
    font-size: 0.86rem;
}

/* En mode cartes il n'y a plus de colonnes auxquelles s'aligner : la grille cède la place à une
   ligne qui se replie, et les cellules vides ne réservent plus d'espace. */
@container liste (max-width: 720px) {
    .cfg-seuil-s .cfg-groupe-titre {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 4px 10px;
    }

    .cfg-seuil-s .cfg-groupe-titre > * { padding-right: 0; }
    .cfg-seuil-s .cfg-groupe-titre > :empty { display: none; }
    .cfg-seuil-s .cfg-groupe-titre .cfg-g-date { margin-left: auto; }
}

/* Le chevron passe en position absolue dans la colonne que lui réserve la grille (.cfg-g-chevron) :
   en flux, il amputait le titre de sa largeur, et l'en-tête — qui n'en a pas — ne pouvait alors
   structurellement pas s'aligner dessus. */
.cfg-groupes .mud-expand-panel-header {
    position: relative;
    padding-left: 16px;
    padding-right: 16px;
}

.cfg-groupes .mud-expand-panel-header .mud-expand-panel-icon {
    position: absolute;
    right: 16px;
    top: calc(50% - 12px);
}

/* 24px par défaut : le tableau des versions rentrait alors de 8px par rapport à l'en-tête et toutes
   ses colonnes s'en trouvaient décalées d'autant. */
.cfg-groupes .mud-expand-panel-content.mud-expand-panel-gutters {
    padding-left: 16px;
    padding-right: 16px;
}

/* Chaque offre se lit comme une carte : dépliée, ses versions occupent toute la hauteur de l'écran
   et plus rien ne disait où l'offre commençait ni où elle finissait. */
.cfg-groupes .mud-expand-panel {
    border: 1px solid var(--cfg-line);
    border-radius: 10px;
    margin: 0 0 8px;
    overflow: hidden;
}

/* Dépliée, la carte s'affirme : liseré d'accent à gauche et en-tête teinté, pour que le titre de
   l'offre ne se confonde pas avec sa première version. */
.cfg-groupes .mud-expand-panel.mud-panel-expanded {
    border-color: var(--cfg-accent-line);
    box-shadow: inset 3px 0 0 var(--mud-palette-primary);
}

.cfg-groupes .mud-expand-panel.mud-panel-expanded .mud-expand-panel-header {
    background-color: var(--cfg-accent-tint);
    border-bottom: 1px solid var(--cfg-line-soft);
}

/* Champs d'édition inline du tableau produit (remise/marge/quantité) : bordure teal + monospace,
   comme les qty-field/marge-field de la maquette — un champ éditable se distingue immédiatement du
   texte du tableau. */
.produit-edit-input {
    border: 1px solid var(--cfg-accent-line);
    border-radius: 7px;
    background: var(--cfg-surface);
    color: var(--cfg-ink);
    padding: 2px 7px;
    font-family: var(--cfg-mono);
    font-variant-numeric: tabular-nums;
    text-align: right;
    /* content-box : la largeur ci-dessous compte des CARACTÈRES, pas des caractères moins le
       padding. C'est ce qui rend prévisible un dimensionnement exprimé en ch. */
    box-sizing: content-box;
}

/* Les largeurs ci-dessous réservent ~2.5ch aux flèches natives EN PLUS des caractères à afficher :
   elles se dessinent dans la zone de contenu et s'y prélèvent, ce qui tronquait les valeurs en "3,"
   ou "24," quand la largeur ne comptait que le texte. */

/* Pourcentage : 0 à 100 avec deux décimales, soit "100,00". */
.produit-edit-pct {
    width: 8.5ch;
}

/* Quantité : 1 à 100, sans décimale. */
.produit-edit-qte {
    width: 5.5ch;
}

    .produit-edit-input:hover {
        border-color: var(--cfg-accent);
    }

    .produit-edit-input:focus {
        border-color: var(--cfg-accent);
        outline: 2px solid var(--cfg-accent-line);
        outline-offset: -1px;
    }

/* Lignes "Inclus" / PGAB du tableau produit (classe .inclus posée sur le <tr>) : texte tertiaire
   en italique, comme la maquette — la ligne se lit comme une note, pas comme une ligne de prix. Le
   code article (1re cellule) reste en style normal. */
.mud-simple-table tbody tr.inclus td {
    color: var(--cfg-faint);
    font-style: italic;
}

/* ...sauf la quantité : c'est une donnée du produit, au même titre que sur les autres lignes.
   Seule la mention explicative ("Inclus", "Inclus dans le transport") s'efface. La seule quantité
   volontairement grise est celle de la ligne "Prix unitaire" du pied (.cfg-foot-unit), où le 1 ne
   fait que rappeler l'unité de référence. td:first-of-type = la quantité, la ligne commençant
   par un th (le code article). */
.mud-simple-table tbody tr.inclus > td:first-of-type {
    color: var(--mud-palette-text-primary);
    font-style: normal;
}

/* Tableau de la carte produit : il occupe toute la largeur de la carte et ne s'arrondit pas.
   MudSimpleTable est un MudPaper, il héritait donc des 12px de rayon du thème — un tableau posé
   dans une carte déjà arrondie donnait deux arrondis concentriques, et les liserés d'accent haut
   et bas s'y interrompaient avant les bords. */
/* Le tableau court d'un bord à l'autre de la carte. Ses liserés d'accent marquent le début et la
   fin de la liste : arrêtés à 16px des bords par le padding de MudCardContent, ils laissaient une
   gouttière de part et d'autre et ne se lisaient plus comme les bornes du bloc. La marge négative
   vaut ce padding — les deux doivent rester accordées. */
/* Vignettes des familles de produit (ConfigurateurSelectionDialog). MudCardMedia pose
   background-size:cover, qui remplit la zone en rognant ce qui dépasse : sur des produits détourés
   aux proportions variées, cela coupait potences et portiques. contain les montre en entier, la
   zone restante étant comblée par le fond de la carte. */
.cfg-config-media {
    background-size: contain !important;
    background-repeat: no-repeat;
    background-position: center;
}

/* Nuancier du dialogue de couleur : carrés cliquables, le choix courant cerclé d'un anneau.
   L'anneau est un box-shadow et non une bordure — une bordure réduirait l'aire colorée et ferait
   sautiller les carrés d'un état à l'autre. */
.cfg-couleur-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
    gap: 8px;
}

.cfg-couleur-carre {
    aspect-ratio: 1;
    border: 0;
    padding: 0;
    border-radius: 8px;
    cursor: pointer;
    box-shadow: 0 0 0 1px var(--cfg-line);
}

    .cfg-couleur-carre:hover {
        box-shadow: 0 0 0 2px var(--cfg-line);
    }

.cfg-couleur-actif {
    box-shadow: 0 0 0 2px var(--mud-palette-surface), 0 0 0 4px var(--cfg-accent) !important;
}

.cfg-couleur-apercu {
    width: 22px;
    height: 22px;
    border-radius: 6px;
    display: inline-block;
    flex: none;
    box-shadow: 0 0 0 1px var(--cfg-line);
}

.cfg-produit-table-zone {
    overflow-x: auto;
    margin-left: -16px;
    margin-right: -16px;
}

/* Les liserés d'accent bornent la liste des composants : le padding de MudCardContent (16px)
   ajoutait une bande blanche juste avant le premier et juste après le second, qui les détachait du
   reste de la carte. Les marges négatives valent ce padding — les trois valeurs doivent rester
   accordées. Conditionnées par :first-child / :last-child pour ne pas remonter le tableau sur les
   produits divers, dont le panneau d'édition le précède, ni le faire chevaucher la liste des plans,
   qui suit le corps quand elle est affichée. */
.cfg-produit-corps > .cfg-produit-table-zone:first-child {
    margin-top: -16px;
}

.cfg-produit-corps:last-child > .cfg-produit-table-zone:last-child {
    margin-bottom: -16px;
}

.cfg-produit-table {
    border-radius: 0 !important;
    width: 100%;
}

    .cfg-produit-table table {
        width: 100%;
    }

/* Survol de ligne du tableau produit (planche : table.bom tbody tr:hover td). MudSimpleTable
   n'applique son survol qu'avec Hover="true", que ces tableaux n'activent pas ; et la règle de
   MudBlazor (.mud-simple-table.mud-table-hover ... , 0,2,4) impose ce niveau de spécificité. */
.mud-simple-table table tbody tr:hover > td,
.mud-simple-table table tbody tr:hover > th {
    background-color: var(--cfg-accent-tint);
}

    .mud-simple-table tbody tr.inclus td:first-child {
        font-style: normal;
    }

/* Chevron séparateur entre les maillons de la chaîne de sous-totaux (carte de totaux). */
.prix-resume-detaille .prix-chevron {
    color: var(--cfg-accent-line);
}

/* Ligne de la version courante dans le panneau "Versions de l'offre" (classe posée via RowClassFunc) :
   fond teal très léger + liseré teal à gauche, sans aplat plein (règle "jamais de fond primary"). */
.mud-table tbody tr.vrow-selected {
    background: var(--cfg-accent-tint) !important;
}

    .mud-table tbody tr.vrow-selected td:first-child {
        box-shadow: inset 3px 0 0 var(--mud-palette-primary);
    }

/* Vignette de l'en-tête d'une carte produit (image ou icône teal de repli), comme la maquette. */
.prod-thumb {
    width: 72px;
    height: 72px;
    border-radius: 10px;
    border: 1px solid var(--mud-palette-lines-default);
    background: var(--cfg-surface-2);
    display: grid;
    place-items: center;
    overflow: hidden;
    color: var(--mud-palette-primary);
}

    /* Suit la vignette : une icône de repli restée à 1.9rem aurait flotté dans un cadre agrandi. */
    .prod-thumb .mud-icon-root {
        font-size: 2.4rem;
    }

    /* place-self:stretch annule le centrage de la grille POUR L'IMAGE seule (l'icône de repli, elle,
       reste centrée) : la case occupe alors toute la hauteur du cadre, hauteur définie sur laquelle
       le 100 % ci-dessous peut se résoudre. Sans cela l'image gardait sa taille native et se posait
       en haut du cadre. object-fit:contain préserve ses proportions. */
    .prod-thumb .mud-image {
        place-self: stretch;
        width: 100%;
        height: 100%;
        object-fit: contain;
    }

/* Plus d'AppBar dans le layout : supprimer l'espace réservé en haut du contenu principal. */
.mud-main-content {
    padding-top: 0 !important;
}

/* MudThemeProvider (App.razor) génère --mud-appbar-height à partir de Theme.LayoutProperties
   (64px par défaut) que l'on ait ou non un MudAppBar : la règle MudBlazor pour ClipMode="Always"
   (top/height calculés à partir de cette variable) réserve donc en permanence cette hauteur en
   haut du tiroir, alors qu'il n'y a pas d'AppBar dans ce layout (MudToolBar en bas à la place).
   Ciblée via une classe posée directement sur le MudDrawer (SidebarMenu.razor) plutôt que sur les
   classes internes générées par MudBlazor (mud-drawer-fixed/responsive/clipped-always), pour ne
   pas dépendre d'une combinaison de classes qui pourrait changer selon la config du composant. */
/* Tiroir latéral sur toute la hauteur de la fenêtre.
   - position/top : MudBlazor réserve --mud-appbar-height en haut d'un tiroir clipped-always, ce qui
     laissait un vide au-dessus du logo puisque cette application n'a pas de MudAppBar ;
   - height/bottom : il s'arrêtait à hauteur d'écran et laissait apparaître son bord inférieur dès
     qu'on faisait défiler la page ;
   - overflow-y : le menu déplié (Paramètres + Offres) dépasse la hauteur d'écran, il doit défiler
     dans le tiroir et non pousser celui-ci.
   La barre d'action du bas étant décalée de la largeur du tiroir, celui-ci peut descendre jusqu'en bas. */
.app-sidebar-drawer {
    position: fixed !important;
    top: 0 !important;
    bottom: 0 !important;
    height: 100dvh !important;
    /* hidden et non auto : le défilement est délégué au .mud-navmenu ci-dessous. Laissé sur le
       tiroir, il rendait l'en-tête solidaire du menu et donc défilant avec lui. */
    overflow-y: hidden;
}

/* MudDrawerHeader réserve par défaut un padding-top de 12px (et un min-height calé sur
   --mud-appbar-height, 64px) : sur un fond de tiroir identique au fond de page (blanc), cet
   espace interne avant le logo se lit comme un vide au-dessus de la sidebar plutôt que comme
   du padding normal. */
.app-sidebar-drawer .mud-drawer-header {
    padding-top: 0;
    min-height: 0;
    /* MudBlazor fait du tiroir une COLONNE FLEX défilante. L'en-tête en était alors le seul élément
       compressible : dès que le menu déplié dépassait la hauteur d'écran, il écrasait le logo et la
       carte utilisateur, que la liste paraissait donc envahir. flex:none le fige à sa taille. */
    flex: none;
}

/* Le défilement appartient au MENU, pas au tiroir : l'en-tête reste ainsi hors de la zone
   défilante, où il ne peut être ni recouvert ni comprimé. (Un position:sticky ne suffisait pas :
   un élément déjà écrasé n'a plus rien à faire adhérer.) */
.app-sidebar-drawer .mud-navmenu {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Icônes de la barre latérale à l'accent, y compris les puces de choix (radios) des groupes
   Affichage / Couleur / Langue : elles portaient le gris de texte par défaut et ne se rattachaient
   visuellement à rien. Les icônes ayant une couleur explicite (mud-success-text sur la bascule
   d'envoi d'email, par exemple) sont exclues : cette couleur-là porte un sens.
   Aucune règle de taille ici : la hauteur des lignes du menu reste celle de MudBlazor. */
/* L'accent ne marque plus QUE l'entrée de la page courante : coloré partout, il ne distinguait
   plus rien et ne disait pas où l'on se trouve. Les icônes à couleur explicite (mud-success-text
   sur la bascule d'envoi d'email) restent exclues, cette couleur-là porte un sens. */
.app-sidebar-drawer .mud-nav-link.active .mud-nav-link-icon:not(.mud-success-text):not(.mud-warning-text):not(.mud-error-text) {
    color: var(--cfg-accent);
}

/* Reset explicite : évite la marge par défaut du user-agent (8px) en haut/à gauche du body,
   visible un instant avant que le CSS de l'app ne soit pleinement appliqué. */
html, body {
    margin: 0;
    height: 100%;
}

/* Page Configurer (VersionOffre/{id}/Configurateur|Configuration) : mis dans app.css plutôt que dans
   un <HeadContent> de la page, qui ne s'est pas révélé fiable pour cette page en @rendermode
   InteractiveServer (le <style> n'atteignait jamais le <head> rendu, laissant #recap sans son
   float/largeur et donc empilé sous le viewer, invisible sans scroller la page entière). */
/* Fond aligné sur celui du configurateur pour qu'il n'y ait pas de couture visible entre notre
   panneau et l'iframe. C'était un #f0f0f0 en dur, le gris de KBmax : depuis que KbmaxThemeMiddleware
   réécrit sa définition de thème, l'iframe prend --cfg-ground et suit le clair/sombre. Le gris fixe
   produisait donc exactement la couture qu'il visait à éviter — un bandeau clair contre un
   configurateur sombre. */
body:has(#viewer) { margin: 0; height: 100dvh; width: 100%; background: var(--cfg-ground); }
/* Flex plutôt que float : #viewerContainer est un bloc normal (non flottant), donc un #recap flottant
   qui le suit se retrouve poussé sous lui par le flux normal au lieu de se placer à côté. */
#viewerContainer, #recap { height: 100dvh; box-sizing: border-box; flex-shrink: 0; }
.partial-width { width: 75%; }
.full-width { width: 100%; }
.hidden { display: none; }
/* position + z-index : l'iframe KBmax (#viewer > iframe) est en position:absolute, donc peinte
   au-dessus des éléments non positionnés quel que soit l'ordre dans le DOM. */
#recap { width: 25%; overflow-y: auto; background: var(--cfg-ground); color: var(--cfg-ink); position: relative; z-index: 1; }
#viewerContainer { transition: width 0.3s ease-in-out; }

/* Styles du tableau récapitulatif (portés de Configurateur/Views/Configurateur/Configurer.cshtml,
   host MVC gelé depuis 2026-07-16), générés par RecapHtmlBuilder. */
.mytable {
    font-size: 12px;
    border-left: 1px solid;
    border-right: 1px solid;
    border-color: var(--cfg-accent);
    border-spacing: 0px;
}

/* Seul --cfg-accent-fixe subsistant, et pour une raison precise : c'est le seul APLAT d'accent de
   l'application, et il porte du texte blanc. --cfg-accent suit le theme et s'eclaircit fortement en
   mode sombre (un vert-vif y devient #00FF63) : du blanc dessus serait illisible. La variante claire,
   elle, est contrastee pour du texte clair par construction. Voir AppTheme.Info. */
.mytitre {
    font-size: 18px;
    font-weight: bold;
    text-align: center;
    background-color: var(--cfg-accent-fixe);
    padding: 5px;
    margin: 0px;
    color: white;
}

.infos {
    padding: 5px;
    width: 50%;
}

/* Ligne d'en-tete des colonnes (Code / Qte / P.U. / P.T.). Meme traitement que les en-tetes de
   tableau du reste du site : libelles en texte secondaire sur un fond leger, et non un aplat gris
   avec du texte blanc (#bdc9cb, qui ne tenait ni le mode sombre ni le contraste). */
.legende {
    font-size: 10px;
    background-color: var(--cfg-surface-2);
    color: var(--cfg-muted);
    font-weight: 600;
}

.options {
    padding: 5px;
}

.droite {
    text-align: right;
    padding: 5px;
}

.gauche {
    text-align: left;
    padding: 5px;
}

/* Ligne de total. Elle etait rendue comme une ligne ordinaire — texte courant et filet en
   currentColor — alors que c'est la valeur que l'on vient lire. Mise en avant comme les totaux du
   reste du site (ProduitCard, PrixResumeAffiche) : accent et gras, le montant en chiffres
   monospace tabulaires pour que les colonnes s'alignent. */
.droiteBorder,
.gaucheBorder {
    padding: 5px;
    border-bottom: 1px solid var(--cfg-accent-line);
    font-size: 12px;
    color: var(--cfg-accent);
    font-weight: 700;
}

.gaucheBorder {
    text-align: left;
}

.droiteBorder {
    text-align: right;
    font-family: var(--cfg-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

.mytableBorder {
    border-left: 1px solid;
    border-right: 1px solid;
    border-top: 1px solid;
    border-color: var(--cfg-accent);
    border-spacing: 0px;
}
