/*
 * Base de l'application. Aucune valeur en clair : tout vient de
 * css/kofreo-tokens.css (charte v2 depuis le 23/09/2026, UI-086).
 */

html,
body {
    margin: 0;
    padding: 0;
    height: 100%;
}

/*
 * Le conteneur de tout l'écran (UI-123). Les seuils de mise en page s'écrivent
 * en requêtes de conteneur « ecran », jamais en @media : ils mesurent ainsi la
 * largeur ZOOMÉE. À 125 % dans Mon affichage, un écran de 1 280 px n'en offre
 * plus que 1 024, et une fiche doit s'y disposer comme sur un écran de 1 024 —
 * ce que fait le zoom du navigateur, et qu'un @media, qui lit l'écran réel, ne
 * voyait pas : la fiche gardait son volet à côté et coupait ses dates.
 *
 * Un conteneur ne devient pas le repère des éléments fixes : fenêtres, tiroir
 * et voiles restent posés sur l'écran (mesuré le 03/10/2026, #app décalé).
 */
#app {
    container: ecran / inline-size;
}

body {
    font-family: var(--police);
    font-size: var(--taille);
    line-height: 1.5;
    color: var(--texte);
    background-color: var(--fond-travail);
    -webkit-font-smoothing: antialiased;
}

/* Tous les nombres, montants et pourcentages s'alignent en colonne (charte v2
   §1.6). Posé sur tout le document plutôt que cellule par cellule : Manrope
   dessine ses chiffres à chasse variable, et un seul oubli décale une colonne. */
body {
    font-variant-numeric: tabular-nums;
}

h1 {
    font-size: var(--taille-titre-ecran);
    font-weight: 800;
    letter-spacing: -0.01em;
    line-height: 1.15;
    margin: 0 0 var(--espace-blocs) 0;
}

/*
 * Le titre d'un écran de module porte l'icône de ce module, dans sa pastille,
 * exactement comme la liste des applications la dessine. C'est le même dessin
 * que celui du menu : on arrive par un lien ou un signet, et on reconnaît où
 * on est sans relire la colonne de gauche.
 */
.titre-module {
    display: flex;
    align-items: center;
    gap: var(--espace-champs);
}

/* Le titre, son compteur et sa précision sur une même ligne (charte v2 §3.1). */
.entete-titre-groupe {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.compteur {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 7px;
    box-sizing: border-box;
    border-radius: var(--rayon-pastille);
    background-color: var(--compteur-fond);
    color: var(--texte-compteur);
    font-size: var(--taille-pastille);
    font-weight: 700;
}

.entete-precision {
    color: var(--texte-libelle);
    font-size: var(--taille-secondaire);
}

/* Une précision qui presse : « 3 en retard » (charte v2 §3.5). */
.entete-precision-alerte {
    color: var(--rouge);
    font-weight: 700;
}

/*
 * La pastille, dans le ton d'accent — celui que la liste des applications
 * donne à une application ALLUMÉE. Et c'est la seule teinte possible ici :
 * sur l'écran d'un module, ce module est forcément allumé, sans quoi l'API
 * refuserait tout et l'entrée aurait disparu du menu (SOC-010).
 *
 * Mêmes jetons que le carré d'icône d'une carte allumée (Applications.razor.css),
 * et pas une nuance à elle : les
 * deux pastilles se voient à trente secondes d'intervalle, l'une en allumant
 * l'application, l'autre en arrivant sur son écran.
 */
.titre-icone {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: var(--hauteur-entete);
    height: var(--hauteur-entete);
    border-radius: var(--rayon-menu);
    background: var(--pastille-accent-fond);
    color: var(--pastille-accent-texte);
}

/* --- L'en-tête d'un écran (UI-053, 21/09/2026) ---
 *
 * Le titre à gauche, les boutons principaux à droite, sur la même ligne et
 * tout en haut. Renald, le 21/09/2026 : « utiliser la zone qui est
 * complètement en haut à droite pour afficher les boutons principaux ».
 *
 * Ils étaient dans la barre de commande, à côté des filtres. Le défaut n'était
 * pas la place perdue, c'est qu'ils BOUGEAIENT : un filtre de plus, une
 * fenêtre plus étroite, et l'action principale se retrouvait ailleurs qu'au
 * dernier écran. L'angle haut-droit, lui, est le même partout et sur tous les
 * écrans.
 */
.entete-ecran {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--espace-blocs);
    flex-wrap: wrap;

    /*
     * IL RESTE SOUS LES YEUX PENDANT LE DÉFILEMENT, comme la barre de commande
     * qu'il surplombe (charte §5). L'action principale y a déménagé : elle
     * était visible du haut en bas d'une liste de trois cents lignes, elle doit
     * le rester.
     *
     * « top: 0 » l'arrête à la marge de la fenêtre et non contre son bord :
     * dans un conteneur qui défile, un décalage collant se compte depuis la
     * boîte de contenu, marge interne déduite. Il s'immobilise donc à vingt
     * pixels du haut, exactement là où le bouton du menu, lui, est fixe — les
     * deux se retrouveraient décalés dès le premier tour de molette.
     */
    position: sticky;
    top: 0;
    z-index: 15;
    background-color: var(--fond-travail);

    /*
     * Et il repeint les vingt pixels au-dessus de lui. Une ombre sans flou ni
     * étalement, simplement décalée vers le haut : elle ne déplace rien — une
     * marge interne, elle, décalerait le titre — et elle empêche la liste de
     * défiler dans la bande laissée libre entre le haut de la fenêtre et lui.
     */
    box-shadow: 0 calc(-1 * var(--marge-fenetre)) 0 var(--fond-travail);
}

/*
 * La barre de commande vient se ranger SOUS l'en-tête, et non par-dessus.
 *
 * Seulement sur les écrans qui en portent un : les autres — ceux qui n'ont pas
 * encore été repris — la gardent collée en haut, là où elle a toujours été.
 * Trois classes pour passer devant sa propre feuille de style, chargée après
 * celle-ci.
 */
.content .entete-ecran ~ .barre {
    top: var(--hauteur-entete);
}

/*
 * Sur un téléphone, rien ne colle en haut que la barre de commande. Un en-tête
 * de quarante pixels y prendrait un dixième de la hauteur utile, et le titre
 * de l'écran n'est pas ce qu'on vient y lire.
 */
@container ecran (max-width: 900px) {
    .entete-ecran {
        position: static;
        box-shadow: none;
    }

    .content .entete-ecran ~ .barre {
        top: 0;
    }
}

/* Le titre porte déjà l'écart des blocs par la zone de travail. */
.entete-ecran h1 {
    margin: 0;
}

.entete-actions {
    display: flex;
    align-items: center;
    gap: var(--espace-champs);
    flex-wrap: wrap;
}

/*
 * LA HAUTEUR DE LA PASTILLE, et c'est la zone qui la donne (demandé par Renald
 * le 21/09/2026 : « les boutons pourraient avoir la même hauteur que l'icône
 * qui est à gauche du titre »).
 *
 * Ici et non dans le composant Bouton : c'est une propriété de l'endroit, pas
 * du bouton. Un bouton posé dans cet en-tête la prend sans rien demander, et
 * aucun écran n'a à s'en souvenir — ce qui est exactement ce qu'un écran
 * oublie.
 *
 * Trois classes pour passer devant la feuille de style du composant, qui est
 * chargée après celle-ci et gagnerait à égalité.
 */
.entete-ecran .entete-actions .bouton {
    min-height: var(--hauteur-entete);
    padding: 0 14px;
}

.entete-ecran .entete-actions .bouton-icone {
    width: var(--hauteur-entete);
    min-width: var(--hauteur-entete);
    padding: 0;
}

/* Le dessin suit le bouton : seize pixels au milieu de quarante se perdent.
   Vingt, comme la pastille du titre en fait vingt-quatre dans ses quarante —
   les deux se lisent sur la même ligne (charte §6). */
.entete-ecran .entete-actions .bouton svg {
    width: 20px;
    height: 20px;
}

/*
 * ET L'INFOBULLE S'OUVRE VERS LE BAS.
 *
 * Elle paraît au-dessus du bouton partout ailleurs, ce qui est le bon choix au
 * milieu d'un écran. Ici, le bouton est à vingt pixels du haut de la fenêtre :
 * la bulle sortirait par le haut et on ne lirait rien. Or c'est exactement là
 * qu'elle compte, puisque ces boutons n'ont plus de mot.
 */
/*
 * L'infobulle des boutons d'en-tête s'ouvre VERS LE BAS et s'aligne À DROITE.
 *
 * Vers le bas : à vingt pixels du haut de la fenêtre, une bulle posée au-dessus
 * sort par le haut et ne se lit pas.
 *
 * À droite, depuis le 22/09/2026 (UI-074) : ces boutons sont collés au bord de
 * l'écran, et une bulle CENTRÉE sur un carré de 34 px déborde de la fenêtre dès
 * que son mot dépasse — « Nouvelle tâche » fait une trentaine de pixels de trop.
 * Or une infobulle masquée par « visibility: hidden » OCCUPE TOUJOURS SA PLACE,
 * contrairement à « display: none » : elle compte donc dans le débordement même
 * quand personne ne la voit. Résultat, une barre de défilement horizontale au
 * bas de chaque écran, en permanence — ce que Renald a vu en recette. Alignée
 * sur le bord droit de son bouton, la bulle reste dans la fenêtre.
 *
 * Et les outils en tête d'une fenêtre de tâche ou d'échange, depuis le
 * 28/09/2026 (UI-120) : la croix « Fermer la fenêtre » est au coin haut de la
 * fenêtre, et sa bulle, posée au-dessus, sortait par le haut — Renald n'en
 * lisait que « Fermer la fenê », rognée par le bord.
 */
.entete-ecran .entete-actions .bouton[data-infobulle]::after,
.fiche-entete-actions .bouton[data-infobulle]::after,
.tache-entete-outils .bouton[data-infobulle]::after,
.echange-entete-outils .bouton[data-infobulle]::after {
    bottom: auto;
    top: calc(100% + 6px);
    left: auto;
    right: 0;
    transform: none;
}

h2 {
    font-size: var(--taille-titre-section);
    font-weight: 800;
    line-height: 1.15;
    margin: 0 0 var(--espace-champs) 0;
}

a {
    color: var(--accent);
}

a:hover {
    color: var(--accent-survol);
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Écran de chargement, avant que l'application ne prenne la main. */
.loading-progress {
    display: block;
    width: 6rem;
    height: 6rem;
    margin: calc(20vh / var(--zoom)) auto 1rem auto;
}

.loading-progress circle {
    fill: none;
    stroke: var(--bordure);
    stroke-width: 0.4rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: var(--accent);
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
    text-align: center;
    color: var(--texte-attenue);
}

/*
 * Bandeau d'erreur irrécupérable. Le texte vient de index.html : il dit ce qui
 * s'est passé et quoi faire, conformément à la charte §7.
 */
#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    padding: 0.8rem var(--marge-fenetre);
    background: var(--pastille-rouge-fond);
    color: var(--pastille-rouge-texte);
    border-top: 1px solid var(--rouge);
    box-shadow: var(--ombre-flottante);
}

#blazor-error-ui .reload {
    color: var(--pastille-rouge-texte);
    margin-left: 0.5rem;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    float: right;
}

/* --- Formulaires de compte (SOC-023) --- */

.formulaire {
    display: flex;
    flex-direction: column;
    gap: var(--espace-blocs);
}

.formulaire .intro {
    margin: 0;
    color: var(--texte-attenue);
}

/*
 * Commandes en bas dans un formulaire court : on lit avant de valider. Les
 * commandes vont en haut dans une LISTE, où l'on fait défiler (charte §8).
 */
.formulaire .actions {
    display: flex;
    justify-content: flex-end;
}

.liens,
.apres {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 0;
    font-size: var(--taille-secondaire);
    color: var(--texte-attenue);
}

.separateur {
    color: var(--bordure);
}

/* --- Sélecteur de rôle (SOC-003) --- */

.role {
    height: var(--hauteur-champ);
    padding: 0 8px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
    color: var(--texte);
    font-family: var(--police);
    font-size: var(--taille);
}

.role:hover {
    border-color: var(--texte-attenue);
}

/* Le contour de focus reste : une bordure qui change de teinte sur 1 px
   se rate au clavier (QUAL-008). */
.role:focus {
    border-color: var(--accent);
}

.note {
    margin: 0;
    max-width: 70ch;
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

/* Les icônes sont au trait (charte v2 §2.18) ; la poignée de glisser-déposer
   est seule à rester pleine, et c'est cette classe qui la remplit. */
.icone .plein {
    fill: currentColor;
    stroke: none;
}

/*
 * LIBELLÉ ET AIDE D'UN CHAMP ÉCRIT À LA MAIN DANS UN ÉCRAN (charte v2 §2.3).
 * Field et Select les dessinent dans leur feuille de portée, qui ne franchit pas
 * la frontière du composant : six écrans et quatre composants qui écrivent
 * « champ-libelle » eux-mêmes — un nuancier, une case, une zone de texte —
 * l'affichaient jusqu'ici en texte nu, sans que rien ne le signale (trouvé le
 * 23/09/2026 en passant les jetons à la v2). Même dessin que le composant ;
 * sa feuille de portée, plus précise, garde la main chez lui.
 */
.champ-libelle {
    font-size: var(--taille-libelle);
    font-weight: 600;
    color: var(--texte-libelle);
}

.champ-aide {
    margin: 0;
    font-size: var(--taille-aide);
    color: var(--texte-attenue);
}

legend.champ-libelle {
    margin-bottom: var(--espace-champs);
    padding: 0;
}

/*
 * ET LEUR MISE EN PAGE, qui manquait de la même façon (UI-109) : la règle qui
 * pose le libellé au-dessus de la zone ne vivait que dans la feuille de portée
 * de Field. Ailleurs, le libellé et la zone restaient sur une même ligne, le
 * libellé tombé au pied d'une zone de texte plus étroite que les autres
 * champs. Vu par Renald en recette le 25/09/2026 sur les fenêtres d'Édition
 * logicielle ; huit écrans l'avaient, dont la page où un client répond à son
 * devis.
 *
 * « div » et non la classe seule : deux nuanciers de couleurs sont des
 * <fieldset class="champ …"> rangés en ligne, qu'une colonne empilerait.
 */
div.champ {
    display: flex;
    flex-direction: column;
    gap: var(--espace-champs);
}

/* --- Paramètres société (SOC-005) --- */

/*
 * Deux colonnes, et les champs longs — raison sociale, adresse — en occupent
 * deux : une adresse dans une demi-largeur se lit mal et se corrige moins bien.
 */
.grille {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--espace-blocs);
    align-items: start;
}

.grille .large {
    grid-column: 1 / -1;
    max-width: 620px;
}

/* Le sélecteur de couleur libre des étiquettes de tâches (SOC-051) : une
   étiquette peut prendre n'importe quelle teinte, l'accent non (voir le
   nuancier ci-dessous). */
.couleur {
    width: 64px;
    height: var(--hauteur-champ);
    padding: 2px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
    cursor: pointer;
}

.couleur:disabled {
    cursor: not-allowed;
}

/* Le nuancier de la couleur d'accent (charte v2 §8.3) : cinq pastilles de
   38 px, la choisie cernée de sa propre couleur. Le bouton radio reste dans
   la page, invisible mais atteignable au clavier : c'est lui qui porte le
   focus, et la pastille qui le montre. */
.nuancier {
    display: flex;
    flex-direction: column;
    gap: var(--espace-champs);
    margin: 0;
    padding: 0;
    border: none;
    min-width: 0;
}

.nuancier-choix {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

/* Les couleurs des contacts (CTC-045) : un couple par ligne, l'aperçu de la
   pastille devant son nuancier. */
.couleurs-contacts {
    display: flex;
    flex-direction: column;
    gap: var(--espace-champs);
}

.couleur-couple-rangee {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
}

.nuance {
    position: relative;
    display: flex;
    cursor: pointer;
}

.nuance input {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    cursor: inherit;
}

.nuance-pastille {
    width: var(--hauteur-champ);
    height: var(--hauteur-champ);
    border: 3px solid var(--surface);
    border-radius: var(--rayon-champ);
    background-color: var(--nuance);
    box-shadow: 0 0 0 1px var(--bouton-bordure);
    box-sizing: border-box;
}

.nuance input:checked + .nuance-pastille {
    box-shadow: 0 0 0 2px var(--nuance);
}

.nuance input:focus-visible + .nuance-pastille {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
}

.nuancier:disabled .nuance {
    cursor: not-allowed;
}

/*
 * Choix des applications (SOC-010). Une case seule n'apprend rien : chaque
 * entrée dit en une ligne ce que l'activation ajoute, et la carte entière est
 * cliquable — viser une case de 13 pixels n'est pas un geste.
 */
.modules {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 12px;
}

.module {
    display: flex;
    gap: 10px;
    padding: 12px 14px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-surface);
    background-color: var(--surface);
    cursor: pointer;
}

.module:hover {
    border-color: var(--accent);
}

.module-actif {
    border-color: var(--accent);
    box-shadow: inset 3px 0 0 0 var(--accent);
}

.module:has(input:disabled) {
    cursor: not-allowed;
}

.module:has(input:disabled):hover {
    border-color: var(--bordure-controle);
}

.module:has(input:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.module input {
    margin-top: 2px;
    accent-color: var(--accent);
}

.module-texte {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.module-nom {
    color: var(--texte);
    font-weight: 500;
}

.module-aide {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

/* --- Contacts (CTC-001 à CTC-003) --- */

.recherche {
    height: var(--hauteur-champ);
    min-width: 240px;
    padding: 0 10px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
    color: var(--texte);
    font-family: var(--police);
    font-size: var(--taille);
}

.recherche:hover {
    border-color: var(--texte-attenue);
}

/* Le contour de focus reste : une bordure qui change de teinte sur 1 px
   se rate au clavier (QUAL-008). */
.recherche:focus {
    border-color: var(--accent);
}

.rangee {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/*
 * Les cases à cocher d'un champ : la case et son libellé forment une seule
 * cible, parce que viser un carré de treize pixels n'est pas un geste.
 */
.rangee-cases {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}

.case {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--texte);
    font-size: var(--taille);
    cursor: pointer;
}

.case input {
    accent-color: var(--accent);
}

.case:has(input:disabled) {
    cursor: not-allowed;
    color: var(--texte-attenue);
}

.lien-fiche {
    color: var(--texte);
    text-decoration: none;
}

.lien-fiche:hover {
    color: var(--accent);
    text-decoration: underline;
}

/* --- Fiche --- */

.entete-fiche {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--espace-blocs);
    flex-wrap: wrap;
}

.entete-fiche h1 {
    margin: 4px 0 2px;
}

.fil-ariane {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
    text-decoration: none;
}

.fil-ariane:hover {
    color: var(--accent);
}

/*
 * Adresses et interlocuteurs : une ligne par entrée, ses commandes à droite.
 * Un tableau serait de trop — trois adresses ne se trient ni ne se filtrent.
 */
.liste-blocs {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.bloc {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--espace-blocs);
    padding: 10px 12px;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon-champ);
    background-color: var(--fond-travail);
}

.bloc-texte {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.bloc-titre {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    color: var(--texte);
    font-weight: 500;
}

.bloc-etiquette {
    color: var(--texte-attenue);
    font-weight: 400;
}

.bloc-detail {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.bloc-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

/*
 * TOUTE ZONE DE TEXTE, aux mesures de la charte v2 (§2.3) : pleine largeur
 * comme les autres champs, 80 px au moins, les marges et les coins d'un
 * encart. Tranché par Renald le 26/09/2026 (UI-111), après avoir vu en recette
 * la zone des notes d'un contact rester à 70 caractères de large — un plafond
 * d'avant la v2, qu'aucun autre champ n'a.
 */
.zone-texte {
    /* La bordure et les marges internes comptées DANS la largeur. Sans cela,
       « width: 100% » vaut cent pour cent plus vingt-huit pixels, et la zone
       déborde de son conteneur : invisible dans une carte large, une barre de
       défilement horizontale dans une fenêtre modale. */
    box-sizing: border-box;
    width: 100%;
    min-height: 80px;
    padding: 12px 14px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-encart);
    background-color: var(--surface);
    color: var(--texte);
    font-family: var(--police);
    font-size: var(--taille);
    resize: vertical;
}

/* Le contour de focus reste : une bordure qui change de teinte sur 1 px
   se rate au clavier (QUAL-008). */
.zone-texte:focus {
    border-color: var(--accent);
}

.zone-texte:disabled {
    background-color: var(--fond-travail);
    color: var(--texte-attenue);
}

/* --- Numérotation (SOC-006) --- */

/*
 * Un préfixe fait trois lettres et un séparateur un caractère : un champ pleine
 * largeur pour trois lettres laisse croire qu'on en attend trente.
 *
 * Une largeur fixe et non un maximum : en flex, chaque champ se dimensionnait
 * sur son contenu, et la rangée se retrouvait avec quatre champs de quatre
 * largeurs différentes selon ce qu'on venait d'y taper.
 */
.etroit {
    width: 120px;
    flex: 0 0 auto;
}

.numerotation {
    flex: 1;
    gap: 8px;
}

.numerotation .rangee {
    align-items: flex-end;
    gap: 12px;
}

/* --- Marges (CAT-001) --- */

/*
 * Les trois chiffres côte à côte, chacun sous son nom. C'est la présentation
 * qui empêche la confusion : « 50 % » seul sous le mot « marge » laisse le
 * lecteur choisir lequel des deux taux il croit lire.
 */
.marges {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.marge {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 150px;
    padding: 12px 14px;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon-surface);
    background-color: var(--fond-travail);
}

.marge-valeur {
    color: var(--texte);
    font-size: var(--taille-sous-titre);
    font-weight: 600;
}

.marge-libelle {
    color: var(--texte);
    font-size: var(--taille-secondaire);
}

.marge-aide {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

/* --- Devis (DEV-001, DEV-002) --- */

.lignes {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/*
 * Une ligne de devis n'est pas une ligne de tableau : elle se déplace, porte
 * un montant à droite, et change d'allure selon qu'elle chiffre, titre ou
 * commente. Trois classes pour trois rôles, et l'œil suit la structure du
 * document sans la lire.
 */
.ligne {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
}

.ligne[draggable="true"] {
    cursor: grab;
}

.ligne-section {
    background-color: var(--fond-travail);
    border-color: var(--accent);
    font-weight: 600;
}

.ligne-note {
    background-color: var(--fond-travail);
    border-style: dashed;
}

.ligne-note .ligne-libelle {
    color: var(--texte-attenue);
    font-style: italic;
}

.poignee-ligne {
    color: var(--texte-attenue);
    font-size: var(--taille-sous-titre);
    line-height: 1;
    user-select: none;
}

.ligne-texte {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}

.ligne-libelle {
    color: var(--texte);
}

.ligne-reference {
    color: var(--texte-attenue);
    font-family: var(--police);
    margin-right: 6px;
}

.ligne-detail {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

/* La marge d'une ligne n'est pas au même plan que ce que le client lit : elle
   se distingue par la couleur d'accent, sans crier. Elle ne part sur aucun
   document (DEV-008, CLAUDE.md §6). */
.ligne-marge {
    color: var(--accent);
    white-space: nowrap;
}

/* Ce qui est arrivé sur une ligne de commande (ACH-003). Au même plan que le
   reste du détail : c'est une information de travail, pas une alerte. Ce qui
   reste dû se lit dans la même phrase, là où on compte les cartons. */
.ligne-reception {
    white-space: nowrap;
}

/* L'écart entre le prix commandé et ce que le catalogue sait du prix chez ce
   fournisseur (ACH-003). Ambre, parce que la charte §1 lui donne le sens de
   « ce qui demande un contrôle » : un fournisseur a le droit d'augmenter, ce
   n'est pas une erreur, mais c'est ce qu'on est venu voir.

   Le ton de pastille plutôt que --ambre, et ce n'est pas un choix de goût :
   l'ambre plein ne donne que 3,2:1 sur du blanc, et ce texte fait treize
   pixels. Le WCAG en demande 4,5. */
.ligne-ecart {
    color: var(--pastille-ambre-texte);
    white-space: nowrap;
}

/* Les montants s'alignent à droite : c'est ainsi qu'on les additionne. */
.ligne-montant {
    flex-shrink: 0;
    min-width: 110px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* Le devis vu par son client (DEV-006).

   Une page lue une fois, par quelqu'un qui n'a pas de compte et ne reviendra
   pas apprendre l'interface. Tout y est plus grand et plus aéré que dans
   l'application : rien à mémoriser, rien à chercher. */
.client-entete {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
}

.client-societe {
    margin: 0;
    font-size: var(--taille-titre-ecran);
    color: var(--accent);
}

.client-adresse {
    margin: 4px 0 0;
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.client-repere {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

/* Le numéro en chiffres tabulaires : c'est la référence que le client
   recopiera dans un email ou dictera au téléphone. */
.client-numero {
    margin: 0;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.client-dates {
    display: flex;
    flex-wrap: wrap;
    gap: 24px;
    margin: 20px 0 0;
}

.client-dates dt {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.client-dates dd {
    margin: 2px 0 0;
    font-variant-numeric: tabular-nums;
}

/* Les retours à la ligne du texte saisi par la société sont conservés : une
   introduction écrite en trois paragraphes doit se lire en trois paragraphes. */
.client-texte {
    margin: 0;
    white-space: pre-wrap;
}

.client-section {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    margin-top: 16px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--bordure);
    font-weight: 600;
}

.client-section-titre {
    color: var(--accent);
}

.client-ligne {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    padding: 10px 0;
    border-bottom: 1px solid var(--bordure);
}

.client-ligne-texte {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.client-ligne-libelle {
    overflow-wrap: anywhere;
}

.client-ligne-detail {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.client-mentions {
    margin: 24px 0 0;
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
    text-align: center;
}

/* L'historique des envois d'un devis (DEV-005).

   Une liste plutôt qu'un tableau : trois informations par ligne, dont deux
   courtes, et un tableau à trois colonnes dont deux sont presque vides se lit
   moins bien qu'une phrase. */
.envois {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.envoi {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    font-size: var(--taille-secondaire);
}

/* La date en chiffres tabulaires : une colonne de dates qui ne s'aligne pas se
   parcourt à la lecture au lieu d'un coup d'oeil. */
.envoi-quand {
    color: var(--texte-attenue);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.envoi-qui {
    /* Une adresse longue se coupe plutôt que d'élargir la carte. */
    overflow-wrap: anywhere;
}

.totaux {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-width: 520px;
    margin-left: auto;
}

.total {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--espace-blocs);
}

.total-libelle {
    color: var(--texte-attenue);
}

.total-base {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.total-valeur {
    font-variant-numeric: tabular-nums;
}

.total-ttc {
    padding-top: 8px;
    border-top: 1px solid var(--bordure);
    font-size: var(--taille-sous-titre);
    font-weight: 600;
}

.total-ttc .total-libelle {
    color: var(--texte);
}

/* --- Import d'un fichier (CTC-005, CAT-005) ---
 *
 * L'aperçu est un tableau brut : il montre ce qui a été lu, pas ce qui sera
 * écrit. Le mettre en forme laisserait croire que Kofreo a déjà interprété les
 * colonnes, alors que c'est justement la question posée au-dessus.
 */

/* « min(520px, 100%) » et non « 520px », et l'arithmétique est la raison :
   la fenêtre fait 520 px de large, son corps en retire deux fois --marge-fenetre
   de rembourrage, donc le contenu dispose de 480. Un panneau qui en exigeait 520
   débordait de quarante pixels et la fenêtre poussait une barre de défilement
   HORIZONTALE sous la liste — c'est-à-dire qu'il fallait faire glisser pour lire
   la fin d'une phrase d'avertissement. Vu à l'écran le 18/09/2026, jamais dans
   le code. */
.import {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: min(520px, 100%);
    max-width: 760px;
}

.import-fichier {
    padding: 10px;
    border: 1px dashed var(--bordure-controle);
    border-radius: var(--rayon-champ);
    background-color: var(--surface-douce);
}

/* UNE CORRESPONDANCE PAR LIGNE, et c'est une question de lisibilité avant
   d'être une question de mise en page.

   Un champ compact met son libellé À CÔTÉ de son contrôle, et son libellé ne se
   coupe pas — « white-space: nowrap » dans Select.razor.css, ce qui est juste :
   ailleurs, une barre de commande à trois sélecteurs doublerait de hauteur si on
   l'enlevait. Mesuré dans la vraie page, à la vraie police : « TVA
   intracommunautaire » réclame 143 px, plus 6 de gouttière, plus le sélecteur.
   Dans une piste de 234, ça ne rentre pas — et le sélecteur est ÉLASTIQUE,
   puisque sa largeur suit le plus long nom de colonne du fichier importé.

   Deux colonnes donnaient donc une grille de 480 px pour 639 px de contenu sur
   un fichier aux en-têtes bavards, et la fenêtre poussait une barre de
   défilement HORIZONTALE. Une seule colonne : 480 pour 480.

   250 et non 240 : à 240, deux pistes tiendraient dans un corps de fenêtre un
   peu plus large et le défaut reviendrait par la bande. */
.import-colonnes {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 8px 12px;
}

/* Et le sélecteur cède plutôt que de pousser : un fichier dont une colonne
   s'appelle « Prix d'achat unitaire HT au 01/01/2026 » ne doit pas décider de
   la largeur de la fenêtre. Quatre classes pour passer devant la règle du
   composant, dont la CSS isolée ajoute un attribut de portée. */
.import-colonnes .champ.champ-compact {
    min-width: 0;
}

.import-colonnes .champ.champ-compact .champ-choix {
    flex: 1;
    min-width: 0;
}

.import-apercu {
    max-height: 200px;
    overflow: auto;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon-champ);
}

.import-apercu table {
    border-collapse: collapse;
    font-size: var(--taille-secondaire);
    white-space: nowrap;
}

.import-apercu th,
.import-apercu td {
    padding: 4px 8px;
    border-bottom: 1px solid var(--bordure);
    text-align: left;
}

.import-apercu th {
    position: sticky;
    top: 0;
    background-color: var(--surface-douce);
    color: var(--texte-attenue);
}

.import-problemes {
    max-height: 220px;
    margin: 0;
    padding-left: 18px;
    overflow-y: auto;
    font-size: var(--taille-secondaire);
    color: var(--texte-attenue);
}

/* Ce qui empêche d'importer se distingue de ce qui est seulement signalé :
   la première liste est à corriger, la seconde est à savoir. */
.import-bloquant {
    color: var(--texte);
}

/* La rangée de tuiles en tête d'écran (UI-007).

   Elle vit dans app.css et non dans StatTile : c'est la PAGE qui décide
   combien de tuiles se posent côte à côte, la tuile ne sait que se dessiner.
   Une grille plutôt qu'un flex : trois tuiles de largeurs différentes se
   lisent moins bien que trois tuiles égales, parce que l'œil compare les
   chiffres et non les boîtes. */
/* auto-FILL et non auto-fit, et cela se voit dès qu'une liste n'a qu'un seul
   chiffre à montrer : auto-fit supprime les colonnes vides, donc la tuile
   solitaire du catalogue s'étalait sur 764 pixels pour annoncer « 1 ». Un
   bandeau pleine largeur pour un nombre crie, et la charte §1 demande le calme
   au repos. auto-fill garde les colonnes ; les listes à trois tuiles ne bougent
   pas d'un pixel. */
.tuiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: var(--espace-blocs);
}

/* --- Vue 360° (CTC-004) ---
 *
 * Les chiffres d'abord, en grand, parce que c'est ce qu'on cherche quand le
 * client est au téléphone. La même forme que les marges : une valeur, ce
 * qu'elle est, et une ligne qui la situe.
 */

.chiffres {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.chiffre {
    display: flex;
    flex: 1 1 180px;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon-champ);
    background-color: var(--surface-douce);
}

.chiffre-valeur {
    font-size: var(--taille-chiffre);
    font-variant-numeric: tabular-nums;
}

.chiffre-libelle {
    color: var(--texte-attenue);
}

.chiffre-aide {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

/* Un bloc entier cliquable : la cible est la ligne, pas le mot. */
.bloc-lien {
    color: inherit;
    text-decoration: none;
}

.bloc-lien:hover,
.bloc-lien:focus {
    border-color: var(--accent);
}

/* --- Choix du gabarit de document (DOC-003) ---
 *
 * Le choix à gauche, l'aperçu à droite, côte à côte : la question posée est
 * « à quoi ressemblera mon devis », et la seule façon d'y répondre est de le
 * montrer pendant qu'on choisit.
 */

.gabarits {
    display: grid;
    grid-template-columns: minmax(260px, 1fr) minmax(300px, 1.1fr);
    gap: 16px;
    align-items: start;
}

.gabarits-choix {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.gabarit {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
    color: var(--texte);
    font-family: var(--police);
    font-size: var(--taille);
    text-align: left;
    cursor: pointer;
}

.gabarit:hover:not(:disabled) {
    border-color: var(--texte-attenue);
}

.gabarit:disabled {
    cursor: default;
    opacity: 0.6;
}

/* L'accent porte le choix, comme partout ailleurs dans l'interface. */
.gabarit-choisi,
.gabarit-choisi:hover:not(:disabled) {
    border-color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
}

.gabarit-nom {
    font-weight: 600;
}

.gabarit-aide {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

/* L'aperçu est une page A4 : le fond gris derrière lui dit que c'est du papier,
   pas un écran. */
.gabarits-apercu {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    min-height: 220px;
    padding: 10px;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon-champ);
    background-color: var(--surface-douce);
}

.gabarits-apercu img {
    max-width: 100%;
    box-shadow: var(--ombre-flottante);
}

/* Sous 900 px, l'aperçu passe sous le choix plutôt que de se réduire à une
   vignette illisible. */
@container ecran (max-width: 900px) {
    .gabarits {
        grid-template-columns: 1fr;
    }
}

/* --- Annuaire des entreprises (CTC-007) ---
 *
 * Le bloc ouvre la carte d'identité : on cherche d'abord, on corrige ensuite.
 * Le filet à gauche le sépare des champs qu'il remplit sans en faire une carte
 * de plus — c'est un outil au service des champs qui suivent, pas une section.
 */

.annuaire {
    /* Toute la largeur de la grille de la carte : l'outil précède les champs
       qu'il remplit. Rangé dans une colonne, il les repoussait sous la ligne
       de flottaison — on cherchait une entreprise sans voir la fiche se
       remplir. */
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 4px;
    padding-left: 12px;
    border-left: 2px solid var(--bordure);
}

/* La liste des résultats ne pousse pas la page : au-delà de quelques
   entreprises elle défile sur elle-même. */
.annuaire-resultats {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 260px;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    list-style: none;
}

.annuaire-choix {
    display: flex;
    flex-direction: column;
    gap: 2px;
    box-sizing: border-box;
    width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
    color: var(--texte);
    font-family: var(--police);
    font-size: var(--taille);
    text-align: left;
    cursor: pointer;
}

.annuaire-choix:hover:not(:disabled) {
    border-color: var(--accent);
}

.annuaire-choix:disabled {
    cursor: default;
    opacity: 0.6;
}

.annuaire-nom {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
}

/* Le SIREN, la ville et l'année : de quoi distinguer deux homonymes sans
   ouvrir une autre fenêtre. */
.annuaire-detail {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.annuaire-adresse {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--bordure);
}

/* --- Journal d'audit (SOC-008) ---
 *
 * Des blocs et non un tableau : chaque ligne porte un détail dépliable, et une
 * grille rend mal ce qui a une deuxième hauteur. La date à gauche, ce qui s'est
 * passé au milieu, qui l'a fait à droite — l'ordre dans lequel on lit un
 * journal.
 */

.journal {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.journal-ligne {
    padding: 8px 0;
    border-bottom: 1px solid var(--bordure);
}

.journal-ligne:last-child {
    border-bottom: none;
}

.journal-entete {
    display: grid;
    grid-template-columns: 130px 1fr auto;
    align-items: baseline;
    gap: 10px;
}

.journal-quand {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
    font-variant-numeric: tabular-nums;
}

.journal-quoi {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 6px;
}

.journal-type {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.journal-libelle {
    font-weight: 600;
}

.journal-qui {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
    text-align: right;
}

/* Le détail se déplie : la plupart des lignes se lisent sans lui, et celles
   qu'on ouvre, on les ouvre une par une. */
.journal-detail {
    margin-top: 6px;
    margin-left: 140px;
}

.journal-detail > summary {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
    cursor: pointer;
}

.journal-champs {
    margin-top: 6px;
    border-collapse: collapse;
    font-size: var(--taille-secondaire);
}

.journal-champs th,
.journal-champs td {
    padding: 2px 8px 2px 0;
    font-weight: 400;
    text-align: left;
    vertical-align: top;
}

.journal-champs th {
    color: var(--texte-attenue);
}

/* L'avant barré, l'après en clair : la direction se lit sans la flèche, et la
   flèche la répète pour qui lit vite. */
.journal-avant {
    color: var(--texte-attenue);
    text-decoration: line-through;
}

.journal-fleche {
    color: var(--texte-attenue);
}

.journal-apres {
    font-weight: 600;
}

/* Sous 720 px, l'en-tête s'empile : trois colonnes dans un écran de téléphone
   coupent le libellé au milieu d'un mot. */
@container ecran (max-width: 720px) {
    .journal-entete {
        grid-template-columns: 1fr;
        gap: 2px;
    }

    .journal-qui {
        text-align: left;
    }

    .journal-detail {
        margin-left: 0;
    }
}

/* --- Les tâches (TAC-001) ---
 *
 * Une tâche faite s'atténue sans disparaître : elle reste lisible, parce que
 * « je l'ai fait quand ? » est une question qu'on pose. Barrée plutôt que
 * grisée seule — le gris seul se confond avec « désactivé ».
 */

.case-tache {
    align-self: start;
    padding-top: 2px;
}

.bloc-fait .bloc-titre {
    color: var(--texte-attenue);
    text-decoration: line-through;
}

.bloc-fait .bloc-detail {
    color: var(--texte-attenue);
}

/* --- Ce qui presse, et qui n'est pas une étiquette (SOC-054, SOC-059) ---
 *
 * Une flèche et un mot, sans fond. Les étiquettes, elles, sont des pastilles
 * pleines aux couleurs de la société : une société qui appelle l'une d'elles
 * « Urgent » — le premier mot que tout le monde écrit — se retrouvait sinon
 * avec deux marques presque identiques sur la même ligne, l'une disant
 * « Urgent » et l'autre « Urgente ». Vu à l'écran le 21/09/2026, et invisible
 * pour toute épreuve.
 *
 * Les deux se distinguent donc PAR LA FORME. Un mot que la société a choisi et
 * un niveau sur lequel le logiciel trie cessent d'avoir l'air de la même chose.
 *
 * La flèche indique le sens — vers le haut ce qui passe devant, vers le bas ce
 * qui peut attendre — pour que la marque ne tienne pas à la teinte seule
 * (charte §5). Elle est décorative : le mot porte le sens.
 */

.priorite {
    font-weight: 600;
    white-space: nowrap;

    /* Pas de marge ici : l'espace est un vrai caractère, écrit dans le balisage
       en &#32; parce que Razor ravale celui qu'on taperait entre deux éléments.
       Une marge aurait séparé les deux mots POUR L'ŒIL seulement — le texte de
       la ligne disait « CritiqueKarim Dupuis », et c'est ce qu'une synthèse
       vocale lisait. */
}

.priorite::before {
    margin-right: 2px;
}

.priorite-critique {
    color: var(--pastille-rouge-texte);
}

.priorite-critique::before {
    content: "▴";
}

.priorite-haute {
    color: var(--pastille-ambre-texte);
}

.priorite-haute::before {
    content: "▴";
}

/* « Basse » se dit aussi : quelqu'un a décidé que ça pouvait attendre, ce qui
   n'est pas la même chose que n'avoir rien dit. Mais discrètement. */
.priorite-basse {
    color: var(--texte-attenue);
    font-weight: 400;
}

.priorite-basse::before {
    content: "▾";
}

/* --- Les images d'une tâche (SOC-048) ---
 *
 * Des vignettes carrées, en ligne, avec leur bouton de retrait. Carrées et
 * recadrées par « object-fit » : une photo de chantier est tantôt en hauteur
 * tantôt en largeur, et une rangée de vignettes de hauteurs différentes se lit
 * comme un dégât d'affichage.
 *
 * Ce qui est montré est ce qui est stocké : le serveur a déjà borné la photo à
 * 1024 px, et le navigateur la rétrécit ici. Une seconde taille stockée
 * économiserait du réseau — c'est le jour où la fiche pèsera qu'on la fera, et
 * pas avant.
 */

.images-tache {
    display: flex;
    flex-direction: column;
    gap: var(--espace-champs);
}

.images-liste {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.image-vignette {
    position: relative;
}

.image-tache {
    display: block;
    width: 96px;
    height: 96px;
    object-fit: cover;
    border: 1px solid var(--bordure);
    border-radius: var(--rayon-champ);
    background: var(--fond-travail);
}

/* Le cadre pendant que les octets arrivent : la fiche garde sa place plutôt
   que de sauter quand la cinquième photo se pose. */
.image-attente {
    border-style: dashed;
}

/* Le retrait se pose SUR la vignette, en haut à droite : une rangée de boutons
   sous les images doublerait la hauteur de la section pour cinq icônes. */
.image-vignette > button {
    position: absolute;
    top: 2px;
    right: 2px;
    background: var(--surface);
}

.image-ajout {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--taille-secondaire);
    color: var(--texte-attenue);
}

.image-refus {
    color: var(--pastille-rouge-texte);
}

/* --- À qui la tâche est attribuée (SOC-053) ---
 *
 * Des boutons à deux états plutôt qu'une liste déroulante à choix multiple :
 * dans une TPE la liste des collègues tient en une ligne ou deux, on voit qui
 * est dessus sans rien ouvrir, et on ajoute quelqu'un d'un clic. Un
 * « select multiple » demanderait de garder Ctrl enfoncé — ce que personne ne
 * devine, et ce qui ne se fait pas du tout au doigt.
 */

.personnes {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.personne {
    border: 1px solid var(--bouton-bordure);
    border-radius: var(--rayon-pastille);
    background: var(--bouton);
    color: var(--texte);
    padding: 3px 12px;
    font: inherit;
    cursor: pointer;
}

.personne:hover {
    background: var(--bouton-survol);
    border-color: var(--bouton-bordure-survol);
}

.personne:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Choisi : l'accent, et une coche devant. Jamais la couleur seule — elle ne se
   voit pas de la même façon selon les yeux (charte §5). */
.personne-choisie {
    border-color: var(--accent);
    background: var(--pastille-accent-fond);
    color: var(--pastille-accent-texte);
    font-weight: 600;
}

.personne-choisie::before {
    content: "\2713\00a0";
}

/* --- Deux boutons de la charte v2 (§2.1), communs aux écrans ---
 *
 * Le lien d'action — un verbe à l'accent, sans cadre (« Tout afficher »,
 * « Transférer vers un autre tableau ») — et le bouton pointillé, qui ajoute
 * ce qui manque (« Nouveau tableau », « Rattacher un client »). Posés ici le
 * 24/09/2026 pour les tâches (SOC-076) ; les fiches de contact gardent leur
 * copie isolée tant qu'elles ne sont pas reprises.
 */

.lien-action {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 8px;
    padding: 0;
    border: none;
    background: none;
    color: var(--accent);
    font: inherit;
    font-size: var(--taille-libelle);
    font-weight: 700;
    /* Un lien aussi (« Saisir son adresse » mène à la fiche) : souligné au survol seulement. */
    text-decoration: none;
    cursor: pointer;
}

.lien-action:hover {
    color: var(--accent-survol);
    text-decoration: underline;
}

/* Le bouton pointillé de la charte §2.1 : « ajouter » quelque chose qui manque. */
.bouton-pointille {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: var(--hauteur-bouton-compact);
    padding: 0 12px;
    border: 1px dashed var(--pointille);
    border-radius: var(--rayon-pastille);
    background: none;
    color: var(--texte-compteur);
    font: inherit;
    font-size: var(--taille-libelle);
    font-weight: 600;
    cursor: pointer;
}

.bouton-pointille:hover {
    border-color: var(--accent);
    color: var(--accent-fonce);
}

/* --- La fiche d'une tâche et le tableau des tâches ---
 *
 * Passés au gabarit v2 le 24/09/2026 (SOC-076, SOC-077) et rangés dans les
 * feuilles isolées de TodoSheet et de TaskBoard : ce qu'un seul composant
 * dessine vit avec lui.
 */

/* --- Les étiquettes d'une tâche (SOC-051) ---
 *
 * SEUL endroit de l'application où une couleur ne vient pas des jetons, et la
 * seule exception que la charte §10 admette : ces deux couleurs SONT la donnée.
 * Elles sont posées en style sur l'élément, depuis la base, et le domaine
 * garantit qu'on peut lire l'une sur l'autre. Rien n'est écrit en dur ici —
 * cette feuille ne connaît que des formes.
 */
.etiquettes {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 4px;
    vertical-align: middle;
}

.etiquette {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px 8px;
    border-radius: var(--rayon-pastille);
    font-size: var(--taille-pastille);
    font-weight: 700;
    line-height: 1.6;
    white-space: nowrap;
}

/* Choisir les étiquettes d'une tâche : les mêmes pastilles, cliquables. */
.etiquettes-choix {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/*
 * Les mêmes encore, dans la barre de commande, pour rétrécir la liste
 * (SOC-058). Elles s'alignent sur les autres filtres et se replient quand la
 * société en a beaucoup — la barre garde sa hauteur d'une ligne tant que trois
 * ou quatre étiquettes suffisent, ce qui est le cas ordinaire.
 */
.etiquettes-filtre {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.etiquette-bouton {
    border: 0;
    font-family: inherit;
    cursor: pointer;
}

/*
 * Ce qui est pris porte un anneau d'accent ET une coche.
 *
 * Deux marques et non une, parce qu'aucune ne suffit seule : l'anneau se perd
 * sur une étiquette dont le fond est déjà sombre, et la coche seule demande de
 * comparer une pastille à l'autre pour voir laquelle en a une. Griser les non
 * choisies aurait été plus court à écrire et illisible : on grise alors du
 * texte de douze pixels, ce que la charte interdit ailleurs pour de bonnes
 * raisons.
 */
.etiquette-prise {
    box-shadow: 0 0 0 2px var(--accent);
}

.etiquette-bouton:disabled {
    cursor: not-allowed;
    opacity: 0.4;
}

/* Les nuances proposées : le fond et le texte d'un coup, sur un « A ». */
.nuances {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.nuance {
    width: var(--hauteur-champ);
    height: var(--hauteur-champ);
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-champ);
    font-family: inherit;
    font-size: var(--taille-pastille);
    font-weight: 700;
    cursor: pointer;
}

.reglage-etiquettes {
    display: flex;
    flex-direction: column;
    gap: var(--espace-blocs);
}

/* « portée par 12 tâches » : ce qu'on perd en supprimant, dit avant. */
.reglage-compte {
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
    white-space: nowrap;
}

/* --- Les sous-actions d'une tâche (SOC-040) ---
 *
 * Un libellé toujours modifiable plutôt qu'un mode « édition » : on corrige une
 * check-list en tapant dedans. Le champ ne se dessine qu'au survol et au focus,
 * sinon douze bordures grises transformeraient trois lignes en formulaire.
 */
.sous-actions {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: var(--espace-champs);
}

.sous-actions-liste {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.sous-action,
.sous-action-ajout {
    display: flex;
    align-items: center;
    gap: var(--espace-champs);
}

.sous-action-libelle {
    flex: 1 1 auto;
    min-width: 0;
    height: var(--hauteur-champ);
    padding: 0 8px;
    border: 1px solid transparent;
    border-radius: var(--rayon-champ);
    background-color: transparent;
    color: var(--texte);
    font: inherit;
}

.sous-action-libelle:hover {
    border-color: var(--bordure-controle);
}

/* Le contour de focus n'est pas retiré : la teinte de bordure s'y ajoute,
   elle ne le remplace pas (QUAL-008). */
.sous-action-libelle:focus {
    border-color: var(--accent);
    background-color: var(--surface);
}

.sous-action-faite .sous-action-libelle {
    color: var(--texte-attenue);
    text-decoration: line-through;
}

.sous-action-commandes {
    display: flex;
    gap: 2px;
    opacity: 0;
}

.sous-action:hover .sous-action-commandes,
.sous-action:focus-within .sous-action-commandes {
    opacity: 1;
}

@media (hover: none) {
    .sous-action-commandes {
        opacity: 1;
    }
}

/* Le champ d'ajout, lui, se voit toujours : c'est là qu'on écrit. */
.sous-action-ajout .sous-action-libelle {
    border-color: var(--bordure-controle);
    background-color: var(--surface);
}

/*
 * « Sous-actions (2/3) » sous une tâche : un bouton qui a l'air d'un lien. Ni
 * l'une des quatre variantes de bouton (charte §5) ni une icône — c'est un
 * dépliant, et le libellé dit ce qu'il contient avant qu'on l'ouvre.
 */
.lien-discret {
    align-self: flex-start;
    padding: 0;
    border: 0;
    background: none;
    color: var(--texte-attenue);
    font: inherit;
    font-size: var(--taille-secondaire);
    text-decoration: underline;
    cursor: pointer;
}

.lien-discret:hover {
    color: var(--accent);
}

/* --- Organiser les tableaux et leurs colonnes (SOC-039) --- */
.reglage-tableaux {
    display: flex;
    flex-direction: column;
    gap: var(--espace-blocs);
}

.reglage-titre {
    margin: 0;
    color: var(--texte-attenue);
    font-weight: 700;
    font-size: var(--taille-entete-colonne);
    text-transform: uppercase;
}

.reglage-liste {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: var(--espace-champs) 0;
    padding: 0;
    list-style: none;
}

.reglage-ligne,
.reglage-ajout {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--espace-champs);
}

.reglage-nom {
    flex: 1 1 14ch;
    min-width: 0;
    height: var(--hauteur-champ);
    padding: 0 8px;
    border: 1px solid var(--bordure-controle);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
    color: var(--texte);
    font: inherit;
}

.reglage-nom:focus {
    border-color: var(--accent);
}

.reglage-case {
    font-size: var(--taille-secondaire);
    white-space: nowrap;
}

/* Un bouton seul dans une carte : le corps d'une carte est une colonne flex,
   qui étire ses enfants sur toute la largeur. Un bouton étiré sur 620 pixels
   pour trois mots ne ressemble plus à un bouton. */
.action-seule {
    display: flex;
}

/* Un nom dans la liste des accès : même gabarit qu'un champ voisin, sans la
   bordure — il se lit, il ne se corrige pas ici. */
.reglage-personne {
    flex: 1 1 14ch;
    min-width: 0;
    overflow: hidden;
    color: var(--texte);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.reglage-pied {
    display: flex;
    justify-content: flex-end;
}

/* --- L'infobulle d'une icône seule (UI-042) ---
 *
 * Dessinée, et non celle du navigateur. « title » attend une seconde avant de
 * paraître : sur une icône seule — le seul endroit où l'infobulle est ce qui
 * NOMME l'action — cette seconde suffit à ce qu'on clique au hasard plutôt qu'à
 * ce qu'on lise.
 *
 * Au survol ET au focus clavier : ce qui ne se découvre qu'à la souris n'existe
 * pas pour qui navigue au clavier.
 *
 * « pointer-events: none » sur la bulle, sinon elle s'interpose entre le
 * curseur et le bouton qu'elle décrit, et le survol clignote.
 */

.bouton[data-infobulle] {
    position: relative;
}

.bouton[data-infobulle]::after {
    content: attr(data-infobulle);
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 30;

    padding: 4px 8px;
    border-radius: 4px;
    background: var(--texte);
    color: var(--surface);
    font-size: var(--taille-secondaire);
    line-height: 1.4;

    /*
     * « max-content » d'abord, plafonné ensuite : une bulle est positionnée en
     * absolu, donc sa largeur disponible est celle du bouton — 34 px. Sans
     * « max-content », « Retenir par défaut » se replierait en cinq lignes d'un
     * mot. Avec, elle tient sur une ligne, et seules les infobulles qui portent
     * une phrase entière vont à la ligne.
     */
    width: max-content;
    max-width: 32ch;
    white-space: normal;

    /*
     * RETIRÉE de la mise en page tant qu'on ne la montre pas, et non seulement
     * rendue invisible (24/09/2026). Une bulle en « visibility: hidden » occupe
     * toujours sa place : collée au bord droit, elle faisait déborder l'écran
     * et apparaître une barre de défilement horizontale en permanence — deux
     * fois vue par Renald en recette, sur l'en-tête d'écran (UI-074) puis sur
     * celui d'une fiche. « display: none » règle le cas partout d'un coup ;
     * « allow-discrete » et « @starting-style » gardent le fondu.
     */
    display: none;
    opacity: 0;
    transition: opacity 80ms ease-out, display 80ms allow-discrete;
    pointer-events: none;
}

.bouton[data-infobulle]:hover::after,
.bouton[data-infobulle]:focus-visible::after {
    display: block;
    opacity: 1;
}

@starting-style {
    .bouton[data-infobulle]:hover::after,
    .bouton[data-infobulle]:focus-visible::after {
        opacity: 0;
    }
}

/* Rien au survol d'un bouton éteint : il ne fait rien, et nommer un geste
 * impossible invite à le tenter. */
.bouton[data-infobulle]:disabled::after {
    content: none;
}

/* --- L'empreinte d'un document archivé (DOC-004) ---
 *
 * En chasse fixe et coupée aux mots : soixante-quatre caractères hexadécimaux
 * se lisent à voix haute ou se comparent à l'œil, et une proportionnelle fait
 * confondre un « 0 » avec un « O ». Sélectionnable, parce qu'on la copie.
 */

.empreinte {
    margin: 0;
    font-family: ui-monospace, "Cascadia Mono", "Consolas", monospace;
    font-size: var(--taille-secondaire);
    color: var(--texte-attenue);
    overflow-wrap: anywhere;
    user-select: all;
}

/* --- Les règlements d'une facture (FAC-004) --- */

/*
 * Le solde et sa pastille sur une seule ligne, poussés aux deux bords : le
 * chiffre est ce qu'on vient lire, le mot est ce qui le qualifie.
 */
.rangee-solde {
    justify-content: space-between;
    margin-bottom: 12px;
}

.solde {
    margin: 0;
    font-size: var(--taille-chiffre-fort);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/*
 * Le trop-perçu en rouge : la société détient de l'argent qui ne lui appartient
 * pas. Ce n'est pas une alerte décorative, c'est une dette (charte §5).
 */
.solde-trop {
    color: var(--pastille-rouge-texte);
}

/* Les lignes d'un devis qu'aucun fournisseur principal ne couvre (ACH-002).
   Nommées une par une, avec leur puce : « 2 lignes » ne dit pas lesquelles, et
   c'est la moitié du résultat sur laquelle il reste à agir. */
.liste-non-placees {
    margin: 0;
    padding-left: 18px;
    color: var(--texte-attenue);
    font-size: var(--taille-secondaire);
}

.liste-reglements {
    margin: 0 0 12px;
    padding: 0;
    list-style: none;
}

.reglement {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    box-sizing: border-box;
    width: 100%;
    padding: 8px 0;
    border-top: 1px solid var(--bordure);
}

.reglement:first-child {
    border-top: none;
}

/* Le montant, la date et le moyen se lisent l'un sous l'autre. */
.reglement > div:first-child {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.reglement strong {
    font-variant-numeric: tabular-nums;
}

/*
 * Un règlement annulé (FAC-004) : barré et atténué, pas caché. Il reste dans
 * la liste parce que c'est lui qui explique le solde — une facture soldée par
 * erreur puis corrigée doit pouvoir se raconter. Le barré dit « ceci ne compte
 * plus » à la lecture, avant même qu'on lise la pastille.
 */
.reglement-annule strong {
    text-decoration: line-through;
    color: var(--texte-attenue);
}

/* --- Le tableau de bord (FAC-009) --- */

/*
 * Les chiffres du tableau de bord sont passés à StatTile le 17/09/2026 : même
 * forme qu'ici, plus l'icône teintée, et surtout UN SEUL composant pour un
 * chiffre-clé. La liste des factures montre « reste dû » elle aussi, et deux
 * présentations du même chiffre finissent toujours par diverger.
 *
 * .chiffre-alerte est parti avec eux : la teinte d'alerte est maintenant celle
 * de la pastille d'icône, et elle ne s'allume toujours que lorsqu'il y a un
 * geste à faire — un tableau de bord où tout est rouge ne signale plus rien
 * (charte §5).
 */

.classement {
    margin: 0;
    padding: 0;
    list-style: none;
}

.classement-ligne {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    box-sizing: border-box;
    width: 100%;
    padding: 8px 0;
    border-top: 1px solid var(--bordure);
}

.classement-ligne:first-child {
    border-top: none;
}

.classement-montant {
    font-variant-numeric: tabular-nums;
}

/*
 * --- Gabarit « fiche » et « document » de la charte v2 (§3.2, §3.3) ---
 *
 * Communs à toutes les fiches : la fiche d'un contact les portait seule, la
 * fiche d'un devis les reprend (DEV-017 et suivants). Une seule copie, pour
 * que deux fiches ne divergent pas d'un pixel à la première retouche.
 */

/* Une métadonnée de l'en-tête : icône discrète, puis le texte. */
.meta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.meta svg {
    color: var(--texte-attenue);
}

.meta-alerte,
.meta-alerte svg {
    color: var(--pastille-ambre-texte);
}

/* Colonne principale et rail (charte v2 §1.7).
 *
 * LE RAIL PASSE SOUS LA COLONNE QUAND LA PLACE MANQUE, quelle qu'en soit la
 * cause — fenêtre étroite, menu élargi, tiroir ouvert à côté —, et non plus
 * seulement sous 1 100 px de fenêtre : une règle sur la fenêtre ne voit pas le
 * tiroir, et la colonne principale d'une fiche contact tombait à 73 px à côté
 * d'un tiroir large (aperçu du 02/10/2026, décision de Renald, IA-019). La
 * colonne ne descend jamais sous --largeur-fiche-min à côté du rail : sans
 * tiroir, menu ouvert, c'est à peu près le seuil d'avant.
 *
 * Le motif d'une barre latérale qui se replie : à côté du rail, la colonne
 * prend presque toute la place gagnée (999 contre 1) et le rail garde sa
 * largeur ; seul sur sa ligne, le rail prend toute la largeur.
 */
.fiche-corps {
    display: flex;
    flex-wrap: wrap;
    gap: var(--espace-colonnes);
    align-items: flex-start;
}

.fiche-principale,
.fiche-rail {
    display: flex;
    flex-direction: column;
    gap: var(--espace-blocs);
    min-width: 0;
}

.fiche-principale {
    flex: 999 1 0;
    min-width: min(100%, var(--largeur-fiche-min));
}

.fiche-rail {
    flex: 1 1 var(--largeur-rail);
}

.fiche-paire {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--espace-blocs);
    align-items: start;
}

@container ecran (max-width: 1100px) {
    .fiche-paire {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Les valeurs d'une carte du rail : le libellé à gauche, la valeur à droite. */
.rail-valeurs {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 10px 16px;
    margin: 0;
}

.rail-valeurs dt {
    color: var(--texte-libelle);
}

.rail-valeurs dd {
    margin: 0;
    min-width: 0;
    overflow-wrap: anywhere;
    color: var(--texte);
    font-weight: 600;
    text-align: right;
}

/* Les actions rapides du rail (charte v2 §3.2). */
.actions-rapides-liste {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.action-rapide {
    display: flex;
    align-items: center;
    gap: 10px;
    height: var(--hauteur-bouton);
    padding: 0 14px;
    box-sizing: border-box;
    border: 1px solid var(--bouton-bordure);
    border-radius: var(--rayon-champ);
    background-color: var(--surface);
    color: var(--texte-bouton);
    font-family: var(--police);
    font-size: var(--taille);
    font-weight: 600;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.action-rapide:hover:not(:disabled) {
    background-color: var(--surface-douce);
    border-color: var(--pointille);
}

.action-rapide svg {
    color: var(--texte-libelle);
}

/* La zone privée : ce que le client ne voit jamais (charte v2 §5). */
.zone-privee {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: var(--marge-carte-rail-haut) var(--marge-carte-rail) var(--marge-carte-rail);
    border: 1px solid var(--prive-bordure);
    border-radius: var(--rayon-surface);
    background-color: var(--prive-fond);
}

.zone-privee-entete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}

.zone-privee h2 {
    margin: 0;
    font-size: var(--taille-titre-section);
}

.zone-privee-mention {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--prive-texte);
    font-size: var(--taille-aide);
    font-weight: 600;
}

.zone-privee-texte,
.zone-privee-vide {
    margin: 0;
    white-space: pre-wrap;
}

.zone-privee-vide {
    color: var(--texte-attenue);
}

/* La ligne de création, au bas du rail (charte v2 §3.2). */
.fiche-meta {
    margin: 0;
    color: var(--texte-attenue);
    font-size: var(--taille-aide);
}

/* --- L'étiquette d'un article, imprimée (CAT-020) ---
 *
 * Une page NOMMÉE, et non la page de tout le document : seule l'étiquette la
 * prend (« page: etiquette », Pages/CatalogueLabel.razor.css), et toute autre
 * impression de Kofreo garde la feuille que le navigateur propose. Le format
 * d'une étiquette de 70 × 37 mm, sans marge — c'est l'étiquette qui porte la
 * sienne.
 */
@page etiquette {
    size: 70mm 37mm;
    margin: 0;
}

/*
 * L'impression n'est jamais zoomée (UI-123) : une étiquette mesure 70 × 37 mm,
 * et un document imprimé n'a pas à grossir avec l'écran de qui l'imprime.
 * « !important » l'emporte sur le zoom que Mon affichage pose en ligne sur la
 * racine ; « --zoom » revient à 1 avec lui, pour que les hauteurs qui s'en
 * servent retrouvent leur valeur.
 */
@media print {
    :root {
        zoom: 1 !important;
        --zoom: 1 !important;
    }
}
