/*
 * Retouches du back-office.
 *
 * Palette : on repart des couleurs de la marque (sarcelle #008080 / #00b8b4,
 * ambre #faac19) plutôt que des classes contextuelles de Bootstrap, dont les
 * verts, rouges et cyans saturés fatiguent sur un outil utilisé toute la
 * journée. Les surfaces restent claires, la couleur ne sert qu'à hiérarchiser :
 * une seule action colorée par écran, le reste en gris neutre.
 */

:root {
    --od-primary: #0f7a78;
    --od-primary-hover: #0b625f;
    --od-quiet-border: #cfd6da;
    --od-quiet-text: #41525c;
    --od-quiet-hover: #eef2f4;
    --od-danger: #a4544f;
    --od-danger-hover: #f6ecec;
}

/* ------------------------------------------------- barre d'actions du form */

.od-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 12px 0;
}

/* Pousse la suppression à l'opposé des actions d'enregistrement : elle reste
   accessible sans être voisine du bouton que l'on clique cent fois par jour. */

.od-actions .od-actions-end {
    margin-left: auto;
}

.od-btn {
    display: inline-block;
    padding: 7px 16px;
    cursor: pointer;
    text-decoration: none;
    border: 1px solid transparent;
    border-radius: 4px;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.4;
    transition: background-color .12s ease, border-color .12s ease;
}

.od-btn:focus-visible {
    outline: 2px solid var(--od-primary);
    outline-offset: 2px;
}

/* L'action principale : la seule pleinement colorée. */

.od-btn-primary,
.od-btn-primary:hover,
.od-btn-primary:focus {
    background: var(--od-primary);
    border-color: var(--od-primary);
    color: #fff;
}

.od-btn-primary:hover {
    background: var(--od-primary-hover);
    border-color: var(--od-primary-hover);
}

/* Les actions secondaires : contour neutre, elles ne se disputent pas l'œil. */

.od-btn-quiet,
.od-btn-quiet:focus {
    background: #fff;
    border-color: var(--od-quiet-border);
    color: var(--od-quiet-text);
}

.od-btn-quiet:hover {
    background: var(--od-quiet-hover);
    border-color: #b6c0c6;
    color: var(--od-quiet-text);
}

/* La suppression : discrète au repos, explicite au survol. */

.od-btn-danger,
.od-btn-danger:focus {
    background: #fff;
    border-color: #d9c2c0;
    color: var(--od-danger);
}

.od-btn-danger:hover {
    background: var(--od-danger-hover);
    border-color: var(--od-danger);
    color: var(--od-danger);
}

/* ------------------------------------------------------- outils d'objet ---
   « Historique » a rejoint la barre d'actions (cf. admin/submit_line.html).
   Ce qui reste ici couvre les autres écrans qui utilisent encore .object-tools. */

.object-tools {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 0;
    margin: 0 0 12px;
    list-style: none;
}

.object-tools li {
    list-style: none;
}

.object-tools a,
.object-tools .btn {
    display: inline-block;
    padding: 7px 16px;
    background: #fff;
    border: 1px solid var(--od-quiet-border);
    border-radius: 4px;
    color: var(--od-quiet-text);
    font-size: 14px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
}

.object-tools a:hover,
.object-tools .btn:hover {
    background: var(--od-quiet-hover);
    border-color: #b6c0c6;
    color: var(--od-quiet-text);
}

/* Les liens de la barre d'actions (« Historique », « Supprimer ») héritent
   sinon du `a { color: #007bff }` d'AdminLTE. On qualifie explicitement par
   l'élément pour passer devant, plutôt que de recourir à !important. */

.od-actions a.od-btn-quiet,
.od-actions a.od-btn-quiet:hover,
.od-actions a.od-btn-quiet:focus {
    color: var(--od-quiet-text);
}

.od-actions a.od-btn-danger,
.od-actions a.od-btn-danger:hover,
.od-actions a.od-btn-danger:focus {
    color: var(--od-danger);
}

/* ------------------------------------------------------- champs de saisie --
 * Jazzmin pose sur une même ligne Bootstrap tous les champs qu'un fieldset
 * groupe dans le même tuple. Les enfants s'y succèdent ainsi : libellé, champ,
 * libellé, champ. Quand la somme des largeurs dépasse la ligne, le retour se
 * fait entre deux enfants quelconques — donc régulièrement entre un libellé et
 * le champ qu'il désigne, qui se retrouvent sur deux lignes distinctes. Le
 * formulaire devient illisible, et le remède dépend de la longueur des
 * libellés autant que de la largeur de l'écran.
 *
 * On repasse ces lignes en grille de deux colonnes. Les enfants se placent
 * alors dans l'ordre : libellé en colonne 1, champ en colonne 2, la paire
 * suivante sur la ligne d'après. Un champ par ligne, et plus aucune paire
 * coupée, quels que soient les libellés et la taille de la fenêtre.
 *
 * Les lignes de cases à cocher gardent la disposition d'origine : quatre cases
 * tiennent très bien côte à côte, et les empiler allongerait le formulaire
 * sans rien y gagner. On les reconnaît à une case fille directe de la boîte du
 * champ. La case « Effacer » d'un champ fichier, elle, est enfouie deux niveaux
 * plus bas (`.fieldBox > p.file-upload > span > input`) : ces lignes-là passent
 * bien en grille, comme les autres.
 */

.form-group.row:not(:has(> * > input[type="checkbox"])) {
    display: grid;
    /* La meme premiere colonne que les lignes a deux champs, plus bas. Elle
       valait 9 a 16 rem, contre 7 a 13 : le champ d'une ligne seule demarrait
       quarante-huit pixels plus a droite que le premier champ d'une paire, et
       le formulaire avait deux bords gauches. */
    grid-template-columns: 12rem minmax(11rem, 1fr);
    column-gap: 1.25rem;
    row-gap: 0.4rem;
    align-items: baseline;
}

/* Une ligne de deux champs tient sur une ligne.
 *
 * La règle ci-dessus met une paire l'une sous l'autre : c'était le remède au
 * retour à la ligne entre un libellé et le champ qu'il désignait, et il
 * fonctionne — mais il range aussi en hauteur ce que le fieldset avait groupé
 * pour le voir côte à côte. Numéro de rue et suffixe, code et nom de cedex,
 * code postal et ville forment chacun un couple que l'on lit d'un coup.
 *
 * Quatre colonnes au lieu de deux quand la ligne porte exactement quatre
 * enfants — libellé, champ, libellé, champ. La borne haute vise les deux
 * `:nth-child` : une ligne de trois champs, le projet en compte une, garde la
 * disposition en hauteur, où elle est plus lisible qu'en six colonnes.
 *
 * Le repli reste acquis : sous la largeur où les colonnes ne tiennent plus,
 * `minmax` laisse la grille se resserrer, et jamais un libellé ne se sépare de
 * son champ — ils sont dans la même rangée de grille, pas dans le même flux.
 */
.form-group.row:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])) {
    grid-template-columns:
        12rem minmax(11rem, 1fr)
        12rem minmax(11rem, 1fr);
}

/* --- Ce que la grille sacrifie quand la place manque ---------------------------
 *
 * Les colonnes de valeur valaient `minmax(0, 1fr)` : un minimum de zéro. La
 * grille les écrasait donc **avant** de toucher aux intitulés, qui gardaient
 * leurs treize rem. Relevé sur la fiche client, les quatre colonnes :
 *
 *     1920 px   208 / 301 / 208 / 301
 *     1600 px   208 / 181 / 208 / 181
 *     1366 px   208 /  93 / 208 /  93
 *     1280 px   208 /  61 / 208 /  61
 *
 * À 1366, le champ de date affichait « 02/1 » et l'icône du calendrier mangeait
 * le reste. Un champ texte de soixante et un pixels n'était pas plus utilisable.
 *
 * Deux changements renversent l'ordre. L'intitulé prend une largeur **fixe** :
 * toutes les lignes ouvrent alors leur champ au même endroit, qu'elles en
 * portent un ou deux — c'est le même alignement que l'on avait rétabli en
 * donnant la même première colonne aux deux grilles. Et la colonne de valeur
 * reçoit un **plancher**, en deçà duquel la grille cesse de la réduire.
 *
 * Sous la largeur où même cela ne tient plus, les paires s'empilent —
 * ci-dessous.
 *
 * **Les deux valeurs sont douze rem et onze rem**, et ce paragraphe disait
 * treize et dix : ce sont les chiffres d'un premier jet, restés dans le texte
 * quand la règle a changé. Les bons se déduisent de la mesure. Chrome demande
 * 135 px de contenu pour rendre une date et l'icône de son calendrier, soit
 * 159 px avec les marges ; onze rem de colonne donnent 161 px de champ. Et à
 * 1600, quatre colonnes font 2 x 192 + 2 x 176 + 60 de gouttières, soit
 * 796 px pour 824 de zone — treize rem d'intitulé n'y tenaient pas.
 *
 * Un commentaire qui annonce d'autres chiffres que la règle est pire qu'un
 * commentaire absent : c'est lui qu'on relit pour décider d'y toucher.
 */

/* La zone qui porte les lignes devient un conteneur de requête.
 *
 * `inline-size` et non `size` : seule la largeur est contenue, la hauteur reste
 * celle du contenu. La requête porte sur cette zone et non sur la fenêtre : la
 * colonne des onglets lui prend deux cent trente-quatre pixels fixes, de sorte
 * qu'une même fenêtre laisse des largeurs très différentes selon la fiche.
 */
/* **Les deux formes de zone, et c'etait le second trou.** La declaration ne
 * portait que sur `.card-body`, or `admin/includes/fieldset.html` rend un
 * fieldset **sans nom** en `<div class="p-5">` tout court — la classe de carte
 * ne vient qu'avec un titre. Un fieldset anonyme n'etait donc jamais un
 * conteneur, et la requete ci-dessous ne s'y appliquait pas : ses paires
 * d'adresse ne se superposaient **jamais**. `AddressInline` en fait partie.
 *
 * Les deux selecteurs plutot qu'un `.p-5` seul : `p-5` est une classe
 * utilitaire de Bootstrap, employee ailleurs, et on ne declare pas conteneur
 * tout ce qui porte une marge interieure. Le `:has(> .form-group.row)` est ce
 * qui restreint aux zones de formulaire. */
.card-body:has(> .form-group.row),
.p-5:has(> .form-group.row) {
    container-type: inline-size;
}

@container (max-width: 50rem) {
    /* Quatre colonnes demandent 2 x 192 + 2 x 176 + 60 de gouttières, soit
       796 px. La zone en offre 824 à 1600 de fenêtre, 648 à 1366 : le seuil
       se pose donc juste au-dessus du minimum, et les paires s'empilent dès
       qu'elles ne tiennent plus. */
    /* Le meme selecteur que la regle a quatre colonnes, au `:not` du champ
       fichier pres : sans lui la regle d'au-dessus est plus specifique, et
       c'est elle qui l'emporte malgre l'ordre. Mesure avant correction : la
       requete de conteneur s'appliquait bien, et ne changeait rien. */
    .form-group.row:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])) {
        grid-template-columns: 12rem minmax(11rem, 1fr);
    }
}

/* Un contrôle ne déborde pas de sa colonne.
 *
 * Les champs de l'admin de Django (`vTextField`, `vIntegerField`) n'ont pas de
 * largeur en feuille : ils prennent leur taille intrinsèque, deux cent vingt
 * pixels environ. Sur deux colonnes, en dessous de quatorze cents pixels de
 * fenêtre, cette largeur dépasse la colonne et le champ passait sous
 * l'intitulé du suivant. `max-width` ne fait que plafonner : au-dessus de
 * cette largeur, rien ne bouge.
 */
.form-group.row:not(:has(> * > input[type="checkbox"])) > div > input,
.form-group.row:not(:has(> * > input[type="checkbox"])) > div > select,
.form-group.row:not(:has(> * > input[type="checkbox"])) > div > textarea,
.form-group.row:not(:has(> * > input[type="checkbox"])) > div > .select2 {
    max-width: 100%;
}

/* Les classes de colonne de Bootstrap plafonnent la largeur en pourcentage de
   la ligne entière ; dans la grille, c'est la colonne qui fait ce travail. */

.form-group.row:not(:has(> * > input[type="checkbox"])) > .col-sm-3,
.form-group.row:not(:has(> * > input[type="checkbox"])) > .col-sm-7,
.form-group.row:not(:has(> * > input[type="checkbox"])) > .col-auto {
    max-width: none;
    flex: none;
    width: auto;
}

/* ------------------------------------------------ pastilles d'état --------
 * Les trois colonnes d'état de la liste des dossiers. Elles portaient les
 * classes contextuelles de Bootstrap 4, dont la palette échoue le contraste
 * par construction avec du texte blanc :
 *
 *     btn-success   #ffffff sur #28a745 = 3,13:1
 *     btn-primary   #ffffff sur #007bff = 3,98:1
 *     btn-warning   #ffffff sur #ffc107 = 1,63:1      (seuil : 4,5:1)
 *
 * Sur une liste de cent dossiers, cela faisait à soi seul 236 des 352
 * manquements de contraste relevés sur la page.
 *
 * Les teintes ci-dessous sont choisies pour passer le seuil avec du blanc, et
 * nommées par l'étape qu'elles décrivent plutôt que par leur couleur : la
 * feuille de style peut changer d'avis sans qu'on touche au code Python.
 */

.od-etat {
    display: inline-block;
    padding: 0.28rem 0.6rem;
    border-radius: 0.28rem;
    font-size: 0.86rem;
    line-height: 1.25;
    white-space: nowrap;
    color: #fff;
}

.od-etat--obtenu  { background: #1a7f37; }   /* 5,08:1 */
.od-etat--recu,
.od-etat--envoye  { background: #0b5ed7; }   /* 5,84:1 */
.od-etat--demande { background: #8a5200; }   /* 6,39:1 */
.od-etat--absent  { background: #b42318; }   /* 6,57:1 */

/* « Sans objet » n'est pas un état mais une absence de démarche : pas de
   pastille, juste une mention discrète — qui reste au-dessus du seuil de
   4,5:1 sur les deux fonds alternés du tableau (#ffffff et #f2f2f2). */
.od-etat--sans-objet {
    color: #595f66;
    background: none;
    padding-left: 0;
}

/* ------------------------------------------- contrastes hérités d'AdminLTE -
 * Deux familles, qui ne viennent pas de notre code mais que notre feuille
 * corrige, faute de pouvoir toucher celle du thème — Jazzmin embarque AdminLTE
 * 3.1.0 minifié, sans sources.
 *
 * 1. Les liens des tableaux héritent du `a { color: #007bff }` d'AdminLTE, qui
 *    donne 3,98:1 sur blanc et 3,55:1 sur le gris des lignes alternées. C'est
 *    le gros du reste : une centaine d'occurrences sur une liste de cent
 *    lignes. #0b5ed7 passe les deux fonds (5,84:1 et 5,22:1) en restant
 *    reconnaissable comme un lien.
 *
 *    On vise les liens du contenu, pas ceux du menu latéral ni de la barre du
 *    haut, qui sont posés sur des fonds sombres et ont leurs propres règles.
 */

#content a:not(.btn):not(.nav-link):not(.dropdown-item),
#content-header a:not(.btn) {
    color: #0b5ed7;
}

#content a:not(.btn):not(.nav-link):not(.dropdown-item):hover,
#content-header a:not(.btn):hover {
    color: #093f8f;
}

/* 2. Les intitulés de section du menu latéral — « Courriels », « Dossiers » —
 *    sont en #717579 sur le #343a40 de la barre : 2,47:1, le pire rapport de
 *    l'application. #a8b0b8 monte à 5,24:1 sans éclaircir le menu.
 */

.nav-sidebar .nav-header {
    color: #a8b0b8;
}

/* Les mêmes couleurs, là où Bootstrap les pose en fond plutôt qu'en texte.
   `btn-success` donne 3,13:1 avec du blanc, `btn-primary` 3,98:1 — et le lien
   actif du menu latéral porte le même bleu en fond. On reprend les teintes des
   pastilles, pour que l'ensemble reste cohérent. */

.btn-primary {
    background-color: #0b5ed7;
    border-color: #0b5ed7;
}

/* Meme raison : AdminLTE pose le fond du lien actif par
   `.sidebar-dark-primary .nav-sidebar > .nav-item > .nav-link.active`. */
.sidebar-dark-primary .nav-sidebar > .nav-item > .nav-link.active {
    background-color: #0b5ed7;
}

.btn-primary:hover,
.btn-primary:focus {
    background-color: #093f8f;
    border-color: #093f8f;
}

.btn-success {
    background-color: #1a7f37;
    border-color: #1a7f37;
}

.btn-success:hover,
.btn-success:focus {
    background-color: #14602a;
    border-color: #14602a;
}

/* Le fil d'Ariane vit dans `.content-wrapper`, hors des conteneurs visés
   plus haut. Son dernier élément, celui de la page courante, est à 4,33:1. */

.accent-primary .breadcrumb a:not(.dropdown-item):not(.btn-app):not(.nav-link):not(.brand-link):not(.page-link):not(.btn) {
    color: #0b5ed7;
}

.breadcrumb-item.active {
    color: #5f666d;
}

/* Le décompte de résultats est un lien au milieu d'une phrase, distingué de
   son voisinage par la seule couleur — c'est le critère 3.1 de WCAG, que la
   règle `link-in-text-block` relève. Un soulignement le rend identifiable
   sans recourir à la couleur. */

#changelist-search .quiet a {
    text-decoration: underline;
}

/* Le pied de page — la mention de version — est en #869099 sur blanc :
   3,25:1. #697079 monte a 5,01:1 sans changer son caractere discret. */

.main-footer {
    color: #697079;
}

/* Le cyan de `btn-info` — les raccourcis du tableau de bord — donne 3,04:1
   avec du blanc, le plus faible rapport qui restait. #12798a monte à 5,09:1. */

.btn-info {
    background-color: #12798a;
    border-color: #12798a;
}

.btn-info:hover,
.btn-info:focus {
    background-color: #0d5c69;
    border-color: #0d5c69;
}

/* Les onglets d'une fiche gardent leur intitulé en #007bff sur blanc, 3,97:1.
   Le sélecteur reprend celui d'AdminLTE — `.accent-primary .nav-tabs .nav-link`
   — pour l'emporter à spécificité égale.

   Ne pas étendre la règle à `.nav-pills` : c'est aussi la classe du menu
   latéral, posé sur fond sombre, qu'un bleu foncé rendrait illisible. */

.accent-primary .nav-tabs .nav-link {
    color: #0b5ed7;
}

/* L'écran de connexion n'est pas servi par `admin/base.html` : il n'a ni
   `#content` ni `.accent-primary`, donc les règles de liens posées plus haut
   ne l'atteignent pas. */

.jazzmin-login-page a {
    color: #0b5ed7;
}

/* Prise de focus visible (RGAA 10.7). Certains liens du thème — le repli du
   menu, les raccourcis de la barre du haut — sont habillés en boutons sans
   variante colorée : Bootstrap ne leur applique alors aucune ombre de focus,
   et rien ne signalait où l'on se trouvait au clavier.

   `:focus-visible` n'affiche le contour qu'à la navigation au clavier. */

.main-header a:focus-visible,
.main-sidebar a:focus-visible,
#content a:focus-visible,
#content button:focus-visible,
#content input:focus-visible,
#content select:focus-visible,
#content textarea:focus-visible {
    outline: 3px solid #f0c030;
    outline-offset: 2px;
}

/* Le lien d'évitement : premier élément focalisable, invisible tant qu'il n'a
   pas le focus. `display:none` le retirerait du parcours clavier ; on le sort
   de l'écran par un décalage. */

.lien-evitement {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 2000;
    padding: 0.6rem 1rem;
    background: #fff;
    color: #0b5ed7;
    border: 2px solid #0b5ed7;
    text-decoration: underline;
}

.lien-evitement:focus {
    left: 0;
}

#contenu:focus {
    outline: none;
}


/* --- Champs de date natifs ------------------------------------------------
 *
 * Voir `backoffice/formulaires.py` : les champs de date sont des
 * `<input type="date">`, pas le widget maison de Django. La feuille de jazzmin
 * habille `.vDateField`, `input[type="text"]` et `input[type="number"]` ; elle
 * ne connaît pas `input[type="date"]`. On reprend donc la même boîte, à
 * l'identique, pour que le changement de widget ne se voie pas.
 */
input.vDateNatif {
    height: calc(2.25rem + 2px);
    /* Le navigateur rend la date *et* l'icone du calendrier. Le champ n'a plus
       de largeur minimale propre : c'est la grille qui garantit desormais
       onze rem a la colonne de valeur, et le champ s'y loge. (Le chiffre
       annonce ici etait douze : c'est l'intitule qui en fait douze, pas la
       valeur.) Un plancher ici
       l'emportait sur le `max-width: 100%` pose plus haut, et faisait deborder
       la colonne ; sans plancher du tout, le champ tombait a quarante-six
       pixels des que la fenetre se reduisait.

       `max-width` parce que l'inverse se produit aussi : seul sur sa ligne, le
       champ s'etirait sur cinq cent soixante-seize pixels. Une date n'en
       demande pas tant.

       Pas de marge droite particuliere, et c'est la correction d'une erreur :
       le navigateur pose l'indicateur du calendrier a la fin de la **boite de
       contenu**, pas contre la bordure. Une marge droite le pousse donc vers
       l'interieur *et* retire autant de place au texte — on perdait trois
       caracteres au lieu d'en gagner. La place de l'icone se donne par la
       largeur de la colonne, pas par la marge. */
    min-width: 0;
    width: 100%;
    margin-bottom: 5px;
    padding: .375rem .75rem;
    display: inline-block;
    font-size: 1rem;
    font-weight: 400;
    line-height: 1.5;
    color: #495057;
    background-color: #fff;
    background-clip: padding-box;
    border: 1px solid #ced4da;
    border-radius: .25rem;
}

/* Le bouton d'ouverture du calendrier est fourni par le navigateur ; il doit
 * rester visible au contraste comme le reste du champ. */
/* Le plafond est pose ici et non dans la regle ci-dessus : le `max-width: 100%`
   des controles de la grille est plus specifique, et l'emportait. Mesure avant
   correction : quatre cent vingt pixels pour une date, seule sur sa ligne. */
.form-group.row:not(:has(> * > input[type="checkbox"])) > div > input.vDateNatif {
    max-width: 15rem;
}

input.vDateNatif::-webkit-calendar-picker-indicator {
    opacity: .75;
    cursor: pointer;
}

input.vDateNatif:focus-visible {
    outline: 3px solid #0b5ed7;
    outline-offset: 1px;
}


/* --- Les pastilles d'etat : l'icone sans police d'icones -------------------
 *
 * Ces cinq pictogrammes venaient de Bootstrap Icons, qui coute 84 Ko de
 * feuille de style et 128 Ko de police — 212 Ko sur chaque page du
 * back-office, pour cinq dessins. Ils sont ici en clair, extraits de cette
 * meme police : environ 1,2 Ko au total, aucune requete supplementaire.
 *
 * Ils sont poses en `mask` sur un pseudo-element, et non dans une balise
 * `<i>` : sur la liste des dossiers, cette balise etait repetee trois fois
 * par ligne, soit trois cents elements de DOM pour de la decoration. Le
 * `mask` prend sa couleur de `currentColor`, donc de la variante.
 *
 * `content: ""` n'est pas restitue par les lecteurs d'ecran : le libelle de
 * la pastille dit deja ou en est la demarche, l'icone ne fait que le repeter.
 */
.od-etat::before {
    content: "";
    display: inline-block;
    width: 1em;
    height: 1em;
    margin-right: .25em;
    vertical-align: -.125em;
    background-color: currentColor;
    -webkit-mask: var(--od-icone) center / contain no-repeat;
            mask: var(--od-icone) center / contain no-repeat;
}

/* La demarche hors sujet n'a pas de pictogramme. */
.od-etat--sans-objet::before {
    display: none;
}

.od-icone--check2-square {
    --od-icone: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2016%2016%22%3E%3Cpath%20d=%22M2.987%2014.507Q2.4%2014.507%201.947%2014.053Q1.493%2013.6%201.493%2013.013V2.987Q1.493%202.4%201.947%201.947Q2.4%201.493%202.987%201.493H10.987Q11.2%201.493%2011.36%201.653Q11.52%201.813%2011.52%202Q11.52%202.187%2011.36%202.347Q11.2%202.507%2010.987%202.507H2.987Q2.773%202.507%202.64%202.64Q2.507%202.773%202.507%202.987V13.013Q2.507%2013.227%202.64%2013.36Q2.773%2013.493%202.987%2013.493H13.013Q13.227%2013.493%2013.36%2013.36Q13.493%2013.227%2013.493%2013.013V8Q13.493%207.787%2013.653%207.653Q13.813%207.52%2014%207.52Q14.187%207.52%2014.347%207.653Q14.507%207.787%2014.507%208V13.013Q14.507%2013.6%2014.053%2014.053Q13.6%2014.507%2013.013%2014.507ZM8.373%2010.347%2015.36%203.36Q15.52%203.2%2015.52%202.987Q15.52%202.773%2015.36%202.64Q15.2%202.507%2014.987%202.507Q14.773%202.507%2014.667%202.667L8%209.28L5.333%206.667Q5.227%206.507%205.013%206.507Q4.8%206.507%204.64%206.64Q4.48%206.773%204.48%206.987Q4.48%207.2%204.64%207.36L7.627%2010.347Q7.787%2010.507%208%2010.507Q8.213%2010.507%208.373%2010.347Z%22/%3E%3C/svg%3E");
}

.od-icone--clipboard-x {
    --od-icone: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2016%2016%22%3E%3Cpath%20d=%22M6.133%207.147Q6.293%206.987%206.507%206.987Q6.72%206.987%206.88%207.147L8%208.267L9.12%207.147Q9.333%206.933%209.627%207.013Q9.92%207.093%2010%207.36Q10.08%207.627%209.867%207.84L8.693%209.013L9.867%2010.133Q10.027%2010.293%2010.027%2010.507Q10.027%2010.72%209.867%2010.853Q9.707%2010.987%209.493%2010.987Q9.28%2010.987%209.12%2010.88L8%209.707L6.88%2010.88Q6.72%2010.987%206.507%2010.987Q6.293%2010.987%206.133%2010.853Q5.973%2010.72%205.973%2010.507Q5.973%2010.293%206.133%2010.133L7.307%209.013L6.133%207.84Q5.973%207.733%205.973%207.52Q5.973%207.307%206.133%207.147ZM4%201.493H2.987Q2.187%201.493%201.6%202.08Q1.013%202.667%201.013%203.52V13.973Q1.013%2014.827%201.6%2015.413Q2.187%2016%202.987%2016H13.013Q13.813%2016%2014.4%2015.413Q14.987%2014.827%2014.987%2013.973V3.52Q14.987%202.667%2014.4%202.08Q13.813%201.493%2013.013%201.493H12V2.507H13.013Q13.44%202.507%2013.733%202.8Q14.027%203.093%2014.027%203.52V13.973Q14.027%2014.4%2013.733%2014.693Q13.44%2014.987%2013.013%2014.987H2.987Q2.56%2014.987%202.293%2014.693Q2.027%2014.4%202.027%2013.973V3.52Q2.027%203.093%202.293%202.8Q2.56%202.507%202.987%202.507H4ZM9.493%201.013Q9.707%201.013%209.867%201.147Q10.027%201.28%2010.027%201.493V2.507Q10.027%202.72%209.867%202.853Q9.707%202.987%209.493%202.987H6.507Q6.293%202.987%206.16%202.853Q6.027%202.72%205.973%202.507V1.493Q6.027%201.28%206.16%201.147Q6.293%201.013%206.507%201.013ZM6.507%200Q5.867%200%205.44%200.427Q5.013%200.853%205.013%201.493V2.507Q5.013%203.147%205.44%203.573Q5.867%204%206.507%204H9.493Q10.133%204%2010.56%203.573Q10.987%203.147%2010.987%202.507V1.493Q10.987%200.853%2010.56%200.427Q10.133%200%209.493%200Z%22/%3E%3C/svg%3E");
}

.od-icone--send-check {
    --od-icone: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2016%2016%22%3E%3Cpath%20d=%22M15.947%200.693Q16.107%200.373%2015.867%200.133Q15.627%20-0.107%2015.307%200.053L0.747%205.867Q0.32%206.027%200.293%206.48Q0.267%206.933%200.64%207.2L5.653%2010.347L7.147%2012.747Q7.307%2012.96%207.493%2012.987Q7.68%2013.013%207.84%2012.907Q8%2012.8%208.053%2012.613Q8.107%2012.427%208%2012.213L6.613%2010.08L14.133%202.56L12.213%207.307Q12.107%207.573%2012.293%207.813Q12.48%208.053%2012.773%208Q13.067%207.947%2013.173%207.68ZM13.44%201.867%205.92%209.387%201.6%206.613ZM16%2012.48Q16%2013.44%2015.52%2014.24Q15.04%2015.04%2014.24%2015.52Q13.44%2016%2012.507%2016Q11.573%2016%2010.747%2015.52Q9.92%2015.04%209.467%2014.24Q9.013%2013.44%209.013%2012.507Q9.013%2011.573%209.467%2010.747Q9.92%209.92%2010.747%209.467Q11.573%209.013%2012.507%209.013Q13.44%209.013%2014.24%209.467Q15.04%209.92%2015.52%2010.747Q16%2011.573%2016%2012.48ZM14.027%2010.827Q13.813%2010.72%2013.627%2010.773Q13.44%2010.827%2013.333%2010.987L12.16%2012.96L11.627%2012.373Q11.467%2012.267%2011.253%2012.267Q11.04%2012.267%2010.907%2012.4Q10.773%2012.533%2010.773%2012.747Q10.773%2012.96%2010.88%2013.12L11.68%2013.867Q11.947%2014.133%2012.293%2014.08Q12.64%2014.027%2012.853%2013.707L14.187%2011.52Q14.293%2011.307%2014.24%2011.12Q14.187%2010.933%2014.027%2010.827Z%22/%3E%3C/svg%3E");
}

.od-icone--send-x {
    --od-icone: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2016%2016%22%3E%3Cpath%20d=%22M15.947%200.693Q16.107%200.373%2015.867%200.133Q15.627%20-0.107%2015.307%200.053L0.747%205.867Q0.32%206.027%200.293%206.48Q0.267%206.933%200.64%207.2L5.653%2010.347L7.147%2012.747Q7.307%2012.96%207.493%2012.987Q7.68%2013.013%207.84%2012.907Q8%2012.8%208.053%2012.613Q8.107%2012.427%208%2012.213L6.613%2010.08L14.133%202.56L12.213%207.307Q12.107%207.573%2012.293%207.813Q12.48%208.053%2012.773%208Q13.067%207.947%2013.173%207.68ZM13.44%201.867%205.92%209.387%201.6%206.613ZM16%2012.48Q16%2013.44%2015.52%2014.24Q15.04%2015.04%2014.24%2015.52Q13.44%2016%2012.507%2016Q11.573%2016%2010.747%2015.52Q9.92%2015.04%209.467%2014.24Q9.013%2013.44%209.013%2012.507Q9.013%2011.573%209.467%2010.747Q9.92%209.92%2010.747%209.467Q11.573%209.013%2012.507%209.013Q13.44%209.013%2014.24%209.467Q15.04%209.92%2015.52%2010.747Q16%2011.573%2016%2012.48ZM11.147%2011.147Q10.987%2011.307%2010.987%2011.52Q10.987%2011.733%2011.147%2011.84L11.787%2012.48L11.147%2013.12Q10.987%2013.28%2010.987%2013.493Q10.987%2013.707%2011.147%2013.867Q11.307%2014.027%2011.52%2014.027Q11.733%2014.027%2011.84%2013.867L12.48%2013.227L13.12%2013.867Q13.28%2014.027%2013.493%2014.027Q13.707%2014.027%2013.867%2013.867Q14.027%2013.707%2014.027%2013.493Q14.027%2013.28%2013.867%2013.12L13.227%2012.48L13.867%2011.84Q14.027%2011.733%2014.027%2011.52Q14.027%2011.307%2013.867%2011.147Q13.707%2010.987%2013.493%2010.987Q13.28%2010.987%2013.12%2011.147L12.48%2011.787L11.84%2011.147Q11.733%2010.987%2011.52%2010.987Q11.307%2010.987%2011.147%2011.147Z%22/%3E%3C/svg%3E");
}

.od-icone--send-arrow-down {
    --od-icone: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2016%2016%22%3E%3Cpath%20d=%22M15.84%200.16Q16.107%200.373%2015.947%200.693L13.173%207.68Q13.067%207.947%2012.773%208Q12.48%208.053%2012.293%207.813Q12.107%207.573%2012.213%207.307L14.133%202.56L6.613%2010.08L8%2012.213Q8.16%2012.48%208.027%2012.747Q7.893%2013.013%207.6%2013.013Q7.307%2013.013%207.147%2012.747L5.653%2010.347L0.64%207.2Q0.267%206.933%200.293%206.48Q0.32%206.027%200.747%205.867L15.307%200.053Q15.627%20-0.107%2015.84%200.16ZM5.92%209.387%2013.44%201.867%201.6%206.613ZM12.48%2016Q13.44%2016%2014.24%2015.52Q15.04%2015.04%2015.52%2014.24Q16%2013.44%2016%2012.507Q16%2011.573%2015.52%2010.747Q15.04%209.92%2014.24%209.467Q13.44%209.013%2012.507%209.013Q11.573%209.013%2010.747%209.467Q9.92%209.92%209.467%2010.747Q9.013%2011.573%209.013%2012.507Q9.013%2013.44%209.467%2014.24Q9.92%2015.04%2010.747%2015.52Q11.573%2016%2012.48%2016ZM12.853%2014.347Q12.693%2014.507%2012.48%2014.507Q12.267%2014.507%2012.107%2014.347L10.987%2013.067Q10.773%2012.853%2010.88%2012.587Q10.987%2012.32%2011.253%2012.267Q11.52%2012.213%2011.733%2012.427L12%2012.693V10.987Q12%2010.773%2012.133%2010.64Q12.267%2010.507%2012.48%2010.507Q12.693%2010.507%2012.853%2010.64Q13.013%2010.773%2013.013%2010.987V12.8L13.387%2012.373Q13.547%2012.267%2013.76%2012.267Q13.973%2012.267%2014.107%2012.4Q14.24%2012.533%2014.24%2012.747Q14.24%2012.96%2014.08%2013.12Z%22/%3E%3C/svg%3E");
}


/* --- L'icône du menu utilisateur ------------------------------------------
 *
 * `far fa-user` — la silhouette en contour de la barre du haut — était la
 * seule icône de tout le projet à venir de Font Awesome *Regular*. Une police
 * entière de 25 Ko, et une requête, pour un dessin.
 *
 * Basculer en `fas` aurait coûté zéro octet mais changé le rendu : le Solid
 * est une silhouette pleine, le Regular un contour. Le tracé est donc repris
 * tel quel, en masque, comme les douze autres du projet.
 *
 * La balise ne porte plus aucune classe de Font Awesome — ni `far`, ni
 * `fa-user` — et c'est volontaire. Garder `far` suffisait à faire télécharger
 * la police : la classe la référence par `font-family`, que l'icône s'affiche
 * ou non. Et garder `fa-user` aurait laissé la règle `::before` de Font
 * Awesome injecter son caractère à côté du masque, donc un carré vide.
 *
 * `admin/base.html` charge toujours Font Awesome pour le reste de la barre et
 * du menu latéral : un nom qui n'appartient qu'à nous évite toute collision.
 */
.icone-utilisateur {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -.125em;
    background-color: currentColor;
    --od-icone: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%20-456%20448%20528%22%3E%3Cpath%20d=%22M304%20-320Q303%20-365%20264%20-389Q224%20-411%20184%20-389Q145%20-365%20144%20-320Q145%20-275%20184%20-251Q224%20-229%20264%20-251Q303%20-275%20304%20-320ZM96%20-320Q96%20-355%20113%20-384Q130%20-413%20160%20-431Q190%20-448%20224%20-448Q258%20-448%20288%20-431Q318%20-413%20335%20-384Q352%20-355%20352%20-320Q352%20-285%20335%20-256Q318%20-227%20288%20-209Q258%20-192%20224%20-192Q190%20-192%20160%20-209Q130%20-227%20113%20-256Q96%20-285%2096%20-320ZM49%2016H399H49H399Q391%20-33%20356%20-64Q320%20-95%20270%20-96H178Q128%20-95%2093%20-64Q57%20-33%2049%2016ZM0%2034Q2%20-41%2052%20-92Q103%20-142%20178%20-144H270Q345%20-142%20396%20-92Q446%20-41%20448%2034Q448%2047%20439%2055Q431%2064%20418%2064H30Q17%2064%209%2055Q0%2047%200%2034Z%22/%3E%3C/svg%3E");
    -webkit-mask: var(--od-icone) center / contain no-repeat;
            mask: var(--od-icone) center / contain no-repeat;
}


/* --- Les listes remplacées sans rechargement -------------------------------
 *
 * Voir `admin/change_list.html`. Deux besoins seulement : une annonce que
 * seuls les lecteurs d'écran perçoivent, et un signe visible que la zone est
 * en train d'être remplacée.
 */
.od-hors-ecran {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* htmx pose cette classe sur la cible pendant la requête. La transition est
 * assez lente pour ne pas clignoter sur une réponse immédiate. */
#od-liste.htmx-request {
    opacity: .55;
    transition: opacity .25s ease-in .15s;
}

/* La zone reçoit le focus après chaque remplacement, pour que l'utilisateur au
 * clavier ne reparte pas du haut de la page. Ce focus-là est programmatique :
 * l'entourer d'un liseré n'apprendrait rien et surprendrait. */
#od-liste:focus {
    outline: none;
}

/* --- Les booléens ----------------------------------------------------------
 *
 * Voir `backoffice/booleens.py`. Trois dessins qui diffèrent par la forme
 * autant que par la couleur — la couleur seule ne porte jamais le sens — et
 * dont l'intitulé est annoncé par `aria-label`.
 *
 * Les teintes sont celles des pastilles d'état, déjà mesurées au contraste.
 */
.od-booleen {
    font-style: normal;
}

/* La cellule porte elle-même l'icône — voir `backoffice/booleens.py`. Font
   Awesome impose `display: inline-block` à tout ce qui porte `.fa` ; sur un
   `<td>` cela effondre la cellule de 157 à 36 pixels. On lui rend sa nature,
   et l'alignement que le `<i>` tenait de sa ligne de base. */
td.fa, td.fas, td.far,
th.fa, th.fas, th.far {
    display: table-cell;
    vertical-align: middle;
    line-height: inherit;
}

.od-booleen--vrai    { color: #1a7f37; }
.od-booleen--faux    { color: #b42318; }
.od-booleen--inconnu { color: #0b5ed7; }


/* --- Les entrées du menu latéral ------------------------------------------
 *
 * Chaque entrée portait un `<i>` pour l'icône et un `<p>` pour le libellé :
 * deux éléments par lien, vingt-six sur la barre, sur chaque page. Le lien
 * porte maintenant lui-même la classe `fa-…` et le dessin vient de son
 * `::before`.
 *
 * Deux choses à défaire de Font Awesome, qui règle l'élément et non son
 * pseudo-élément : la police, qui rendrait le libellé en glyphes, et
 * `display: inline-block`, qui casserait la mise en page du lien. On les
 * remet donc sur `::before`, avec les mesures qu'AdminLTE donnait à
 * `.nav-icon` — `width: 1.6rem`, les marges et la taille.
 */
.nav-sidebar .nav-link.od-nav {
    font-family: inherit;
    font-weight: inherit;
    font-style: inherit;
    display: block;
    line-height: inherit;
}

.nav-sidebar > .nav-item > .nav-link.od-nav::before {
    display: inline-block;
    width: 1.6rem;
    margin-left: 0.05rem;
    margin-right: 0.2rem;
    text-align: center;
    font-size: 1.1rem;
    font-family: "Font Awesome 5 Free";
    font-weight: 900;
    /* Celle que `.fa` donnait au `<i>`. Sans elle, le glyphe étire la ligne
       de cinq pixels et les treize entrées décalent le bas du menu de
       soixante-cinq. */
    line-height: 1;
    vertical-align: -0.05em;
}


/* --- L'intitulé d'attente des listes en autocomplétion ---------------------
 *
 * select2 pose `#999999` sur blanc, soit un contraste de 2,84:1 — axe-core le
 * signale en « serious », et c'est le critère RGAA 3.2 (4,5:1 pour un texte
 * de cette taille). `#6c757d` donne 4,68:1, et c'est déjà le gris discret de
 * Bootstrap employé ailleurs dans le projet.
 *
 * Le sélecteur reprend celui de select2 : le sien compte trois classes, et
 * une seule ne l'emporterait pas, quelle que soit la position dans le paquet.
 */
.select2-container--default .select2-selection--single .select2-selection__placeholder,
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
    color: #6c757d;
}


/* --- L'avertissement de changement d'onglet --------------------------------
 *
 * Voir `backoffice/onglets.py`. La fiche ne rend qu'un onglet à la fois :
 * en changer est une navigation, et ce qui n'est pas enregistré serait perdu.
 *
 * La barre vive n'apparaît qu'au premier changement de valeur, posée par
 * `js/onglets.js`. Celle du `<noscript>` est là en permanence, mais seulement
 * pour qui n'a pas JavaScript — son contenu n'est même pas construit sinon.
 */
.od-avertissement {
    margin-bottom: 1rem;
}

.od-avertissement__texte {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 600;
}

.od-avertissement--vif:focus {
    outline: 2px solid #0b5ed7;
    outline-offset: 2px;
}


/* --- Deux contrastes insuffisants des formulaires --------------------------
 *
 * Relevés par axe-core en « serious », tous deux venus de la feuille de
 * jazzmin et invisibles à l'œil nu — c'est bien le problème.
 *
 * `.help-block` porte les textes d'aide sous les champs : #859099 sur blanc,
 * soit 3,25:1 pour un texte de 11,2 px, là où le critère RGAA 3.2 en demande
 * 4,5. #6c757d donne 4,68:1, et c'est le gris discret déjà employé ailleurs.
 *
 * `.vCheckboxLabel.inline` est l'intitulé « Supprimer » des volets imbriqués,
 * en rouge pur : 3,99:1. #b42318 donne 6,57:1 — c'est déjà la teinte des
 * pastilles d'erreur et des booléens faux de ce projet.
 */
.help-block,
.timezonewarning {
    color: #6c757d;
}

.vCheckboxLabel.inline {
    color: #b42318;
}

/* --- Le bandeau et les boutons de la fiche dossier -------------------------
 *
 * L'identite du dossier et ses trois destinations etaient six champs du
 * premier fieldset, que l'on rendait sur chaque onglet pour les garder sous
 * les yeux. Six lignes de formulaire repetees sept fois, pour trois valeurs
 * que l'on ne modifie pas la et trois adresses qui ne se modifient jamais.
 *
 * Le bandeau tient en trois `<span>` et une grille de trois colonnes : le
 * centre reste centre quelle que soit la longueur des deux cotes, ce qu'un
 * `justify-content: space-between` ne donne pas.
 */
.od-entete-dossier {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 16px;
}

.od-entete-dossier__centre {
    font-size: 1.25rem;
    font-weight: 700;
    text-align: center;
}

.od-entete-dossier__cote {
    color: #495057;
}

.od-entete-dossier__cote--fin {
    text-align: right;
}

/* Les quatre boutons d'action, sur une ligne qui se replie si elle deborde. */
.od-actions-dossier {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

.od-actions-dossier form {
    margin: 0;
}


/* --- Les pictogrammes des boutons -----------------------------------------
 *
 * Meme principe que les pastilles d'etat plus haut : le dessin est pose en
 * `mask` sur une balise vide, et prend sa couleur de `currentColor`. Les
 * quatre contours sont extraits de `vendor/fontawesome-reduit`, la fonte
 * reduite que le projet versionne — le trace de `fa-phone` deja converti dans
 * `webfront.css` a servi de controle : l'extraction le reproduit a l'octet.
 *
 * Pourquoi ne pas garder les balises `<i class="fas fa-...">` : elles
 * marchent, mais ces quatre dessins sont alors les seuls de la fiche a
 * dependre du chargement d'une fonte. En masque, ils s'affichent avec la
 * feuille, sans attendre, et sans la seconde ou le bouton reste sans icone.
 */
.od-picto {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    background-color: currentColor;
    -webkit-mask: var(--od-picto) center / contain no-repeat;
            mask: var(--od-picto) center / contain no-repeat;
}

.od-picto--fichier {
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%20-459%20384%20534%22%3E%3Cpath%20d=%22M0%20-384Q1%20-411%2019%20-429Q37%20-447%2064%20-448H224V-320Q224%20-306%20233%20-297Q242%20-288%20256%20-288H384V0Q383%2027%20365%2045Q347%2063%20320%2064H64Q37%2063%2019%2045Q1%2027%200%200V-384ZM384%20-320H256H384H256V-448L384%20-320Z%22/%3E%3C/svg%3E");
}

.od-picto--conformite {
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%20-459%20448%20534%22%3E%3Cpath%20d=%22M64%20-416Q37%20-415%2019%20-397Q1%20-379%200%20-352V-32Q1%20-5%2019%2013Q37%2031%2064%2032H384Q411%2031%20429%2013Q447%20-5%20448%20-32V-352Q447%20-379%20429%20-397Q411%20-415%20384%20-416H64ZM337%20-239%20209%20-111%20337%20-239%20209%20-111Q192%20-97%20175%20-111L111%20-175Q97%20-192%20111%20-209Q128%20-223%20145%20-209L192%20-162L303%20-273Q320%20-287%20337%20-273Q351%20-256%20337%20-239Z%22/%3E%3C/svg%3E");
}

.od-picto--globe {
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%20-459%20512%20534%22%3E%3Cpath%20d=%22M352%20-192Q352%20-159%20349%20-128H163Q160%20-159%20160%20-192Q160%20-225%20163%20-256H349Q352%20-225%20352%20-192ZM381%20-256H504H381H504Q512%20-225%20512%20-192Q512%20-159%20504%20-128H381Q384%20-159%20384%20-192Q384%20-225%20381%20-256ZM493%20-288H377H493H377Q361%20-386%20321%20-440Q381%20-423%20426%20-384Q470%20-344%20493%20-288ZM344%20-288H168H344H168Q177%20-343%20195%20-383Q211%20-418%20228%20-434Q245%20-449%20256%20-448Q267%20-449%20284%20-434Q301%20-418%20317%20-383Q335%20-343%20344%20-288ZM135%20-288H19H135H19Q42%20-344%2086%20-384Q131%20-423%20191%20-440Q151%20-386%20135%20-288ZM8%20-256H131H8H131Q128%20-225%20128%20-192Q128%20-159%20131%20-128H8Q0%20-159%200%20-192Q0%20-225%208%20-256ZM195%20-1Q177%20-41%20168%20-96H344Q335%20-41%20317%20-1Q301%2034%20284%2050Q267%2065%20256%2064Q245%2065%20228%2050Q211%2034%20195%20-1ZM135%20-96Q151%202%20191%2056Q131%2039%2086%200Q42%20-40%2019%20-96H135ZM493%20-96Q470%20-40%20426%200Q381%2039%20322%2056Q361%202%20377%20-96H493Z%22/%3E%3C/svg%3E");
}

/* Toutes les regles qui suivent visent une ligne ou un champ en particulier.
 * Chacune reprend la garde complete de la regle generale qu'elle corrige, et
 * y ajoute sa classe : a garde identique, c'est la classe en plus qui tranche.
 * Sans cela la regle generale, plus specifique, l'emporte — et la correction
 * ne fait rien du tout, ce qui s'est produit trois fois ici avant mesure.
 */

/* --- Deux lignes qui ne tiennent pas dans la grille ordinaire -----------------
 *
 * Le suffixe d'adresse : un intitulé de huit lettres, une liste de quatre
 * entrées, et un « + » qui se rangeait sous elle faute de place. Le deuxième
 * intitulé n'a pas besoin des douze rem de la grille ordinaire : les cinq
 * qu'on lui reprend suffisent à mettre le « + » à gauche de la liste, là où
 * on le cherche.
 *
 * `order` plutôt qu'un gabarit à part : les liens sont rendus par
 * `related_widget_wrapper.html`, commun à tous les champs de relation du site.
 * Les déplacer pour un seul d'entre eux se fait ici, et nulle part ailleurs.
 */
.form-group.row.field-suffix:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])) {
    grid-template-columns:
        12rem minmax(11rem, 1fr)
        7rem minmax(11rem, 1fr);
}

/* **Il y avait ici un `order: -1`**, qui mettait le « + » a gauche de la liste.
   Il ne deplacait que l'ordre **visuel** : le DOM garde la liste avant le lien,
   donc au clavier on atteignait la liste puis l'on **revenait en arriere** vers
   le « + » affiche avant elle. RGAA 10.3 : l'ordre de tabulation doit suivre
   l'ordre de lecture.

   Le « + » reste donc apres la liste, comme pour tous les autres champs de
   relation du site. Ce qui motivait le deplacement — « il se rangeait sous elle
   faute de place » — est deja regle par les quatre colonnes ci-dessus, qui
   reprennent a l'intitule la largeur dont la liste avait besoin. */

/* Le type de revente : une colonne de plus pour la liste, une de moins pour
 * l'intitule. « Type de revente » tient en deux mots, et la liste affiche des
 * libelles entiers — « Vente du surplus », « Vente de la totalite ». */
.form-group.row.field-reselling_type:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])) {
    grid-template-columns:
        12rem minmax(11rem, 1fr)
        9rem minmax(11rem, 1.4fr);
}

/* L'autre exception : « Puissance de l'ancienne installation de production
 * raccordée » tient sur trois lignes dans les douze rem de la grille
 * ordinaire, pendant qu'un nombre de deux chiffres occupe tout le reste. Dix
 * douzièmes pour l'intitulé, deux pour le champ. */
.form-group.row.field-power_of_former_electric_production:not(
    :has(> * > input[type="checkbox"])) {
    grid-template-columns: minmax(0, 10fr) minmax(0, 2fr);
}

/* --- Les deux seuils que les exceptions franchissaient -----------------------
 *
 * **Le troisieme trou du repli.** Les deux exceptions ci-dessus ajoutent une
 * classe — `.field-suffix`, `.field-reselling_type` — donc une specificite
 * superieure a celle de la grille generale, et elles sont declarees **apres**
 * la requete de conteneur qui empile les paires. Elles gardaient donc quatre
 * colonnes sous cinquante rem. Mesure : leurs minima plus les gouttieres font
 * 716 px et 748 px, contre 648 px de zone de formulaire disponible a 1366 px
 * de fenetre.
 *
 * Le remede est ce bloc, place **ici** et non la-haut : a specificite egale,
 * c'est l'ordre du fichier qui tranche, et il faut donc passer apres les
 * exceptions. Les monter avant la requete aurait marche aussi, mais aurait
 * separe chaque exception du commentaire qui l'explique.
 */
@container (max-width: 50rem) {
    .form-group.row.field-suffix:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])),
    .form-group.row.field-reselling_type:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])) {
        grid-template-columns: 12rem minmax(11rem, 1fr);
    }
}

/* --- Et sous une piste, plus d'intitule en vis-a-vis -------------------------
 *
 * **Le premier trou du repli : il n'y avait qu'un seuil.** En dessous de
 * 24,25 rem — les douze rem de l'intitule, les onze du champ, et la gouttiere
 * de 1,25 —, chaque ligne a un minimum intrinseque plus large que son
 * conteneur. La grille ne peut plus rien resserrer, et le debordement
 * horizontal revient : a 400 % de zoom, qui est le critere WCAG 1.4.4, la
 * zone de formulaire vaut moins de vingt rem.
 *
 * Sous ce seuil, l'intitule passe **au-dessus** de son champ. C'est le seul
 * choix qui tienne : une colonne d'intitule de douze rem ne se reduit pas, et
 * la reduire rendrait « Puissance de l'ancienne installation de production
 * raccordee » sur sept lignes.
 *
 * Les cinq selecteurs sont repris un par un, et c'est deliberé : les deux
 * exceptions et la ligne de puissance ont une specificite superieure a la
 * grille generale, donc une regle qui ne nommerait que celle-ci les laisserait
 * a quatre colonnes — exactement le trou qu'on vient de fermer au-dessus.
 */
@container (max-width: 24.25rem) {
    .form-group.row:not(:has(> * > input[type="checkbox"])),
    .form-group.row:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])),
    .form-group.row.field-suffix:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])),
    .form-group.row.field-reselling_type:not(:has(> * > input[type="checkbox"])):has(> :nth-child(4)):not(:has(> :nth-child(5))):not(:has(input[type="file"])),
    .form-group.row.field-power_of_former_electric_production:not(:has(> * > input[type="checkbox"])) {
        grid-template-columns: 1fr;
    }
}

/* --- Le numero de rue --------------------------------------------------------
 *
 * Un champ texte prend sa largeur naturelle, une vingtaine de caracteres. Dans
 * la ligne du suffixe, dont la deuxieme colonne est plus large que celle des
 * autres lignes, il s'etirait jusqu'a frôler l'intitule « Suffixe ». Un numero
 * de rue tient en quatre caracteres.
 */
.form-group.row:not(:has(> * > input[type="checkbox"])) > div.field-street_number > input {
    max-width: 6rem;
}

/* --- La liste de relation et ses liens ----------------------------------------
 *
 * Django pose la liste déroulante et ses liens côte à côte dans un bloc. La
 * liste y prend toute la largeur disponible, et les liens se rangent après
 * elle : hors de la colonne. Mesuré sur le volet tabulaire des photographies,
 * le « + » et l'œil dépassaient de 42 et 80 pixels sur la colonne suivante.
 *
 * En ligne souple, la liste prend ce qui reste une fois les liens placés.
 * `min-width: 0` est ce qui l'autorise à se réduire : un élément souple ne
 * descend pas sous sa taille intrinsèque sans cela, et une liste déroulante en
 * a une.
 */
.related-widget-wrapper {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.related-widget-wrapper > .select2-container,
.related-widget-wrapper > select,
.related-widget-wrapper > input {
    flex: 1 1 auto;
    min-width: 0;
}

.related-widget-wrapper > .related-widget-wrapper-link {
    flex: 0 0 auto;
}

/* --- Ce qui a changé depuis le dernier passage --------------------------------
 *
 * Le bandeau des notifications, en tête de la fiche dossier. Il n'apparaît
 * qu'une fois — elles passent à « lu » en même temps qu'on les rend — donc il
 * doit se voir sans crier : un filet de couleur à gauche, et rien d'autre.
 *
 * Le gris du texte est celui qui sert déjà ailleurs dans cette feuille, à
 * 4,69:1 sur blanc.
 */
.od-demandes {
    margin: 0 0 1rem;
    padding: 0.75rem 1rem;
    /* L'ambre de la frise, qui dit déjà « en attente » ailleurs dans
       l'application. Une demande non traitée n'est pas une information : c'est
       quelque chose à faire. */
    border-left: 4px solid #faac19;
    background: #fffaf0;
}

.od-demandes form {
    display: inline;
}

.od-notifications {
    margin: 0 0 1rem;
    padding: 0.75rem 1rem;
    border-left: 4px solid #0b5ed7;
    background: #f6f8fc;
}

.od-demandes__titre,
.od-notifications__titre {
    margin: 0 0 0.25rem;
    font-size: 1rem;
    font-weight: 600;
}

.od-demandes__liste,
.od-notifications__liste,
.od-notifications__liste ul {
    margin: 0;
    padding-left: 1.25rem;
}

.od-notifications__liste ul {
    /* Pas le gris de Bootstrap, qui sert ailleurs : il donne 4,69:1 sur
       blanc, mais 4,41 sur ce fond bleute — juste sous le critere. Mesure
       faite au navigateur, et c'est cette regle-ci qui l'avait introduit.
       Celui-ci tient 5,09:1. */
    color: #636b72;
}

/* --- L'horodatage des actions récentes ----------------------------------------
 *
 * Le tableau de bord liste les dernières actions, chacune avec son « Depuis
 * deux heures ». AdminLTE l'écrit en #999999 sur blanc : 2,84:1, quand le
 * critère RGAA 3.2 en demande 4,5 pour un texte courant — et c'est un texte de
 * douze pixels, donc pas du « grand texte » à 3:1.
 *
 * Le gris de Bootstrap, qui sert déjà ailleurs dans cette feuille, donne
 * 4,68:1.
 *
 * Il ne se voyait pas des balayages précédents : la liste est vide tant que
 * personne n'a rien fait, et la règle ne s'applique alors à aucun élément.
 *
 * Le sélecteur recopie celui d'AdminLTE au lieu de se contenter de
 * `.timeline .time` : à spécificité moindre, la règle d'origine l'emportait et
 * la couleur ne changeait pas. À spécificité égale, c'est l'ordre des feuilles
 * qui tranche, et celle-ci est chargée après.
 */
.timeline > div > .timeline-item > .time {
    color: #6c757d;
}

/* --- Le champ de recherche d'une liste à choix multiple -----------------------
 *
 * La commune et ses codes postaux sont le seul choix multiple du site. select2
 * y rend les valeurs choisies en puces, puis un `<textarea>` de recherche
 * auquel il donne une largeur en ligne — « 0.75em », qu'il ajuste au fil de la
 * frappe. Résultat mesuré sur la fiche d'une commune : un carré de seize
 * pixels sur seize, sous la première puce et à l'extrême gauche. Rien ne disait
 * qu'il fallait cliquer là pour ajouter un code postal.
 *
 * On en fait un élément souple de la même ligne que les puces : il occupe ce
 * qui reste, passe à la ligne avec elles, et ne descend jamais sous huit rem.
 * Le `!important` répond à la largeur que select2 écrit sur l'élément.
 */
.select2-container--admin-autocomplete .select2-selection--multiple {
    /* select2 rend le champ de recherche en frère de la liste des puces, et
       non dedans : en bloc, les deux se superposaient en hauteur. C'est donc
       ici, et non sur la liste, que la ligne se compose. */
    display: flex;
    flex-wrap: wrap;
    align-items: center;
}

.select2-container--admin-autocomplete .select2-selection--multiple
.select2-selection__rendered {
    flex: 0 1 auto;
    width: auto;
    align-items: center;
}

.select2-container--admin-autocomplete .select2-search--inline {
    display: flex;
    flex: 1 1 8rem;
}

.select2-container--admin-autocomplete .select2-search--inline .select2-search__field {
    width: 100% !important;
    min-width: 8rem;
    margin: 0;
}

/* --- Le contraste de la liste déroulante de select2 ---------------------------
 *
 * L'option survolée est écrite en #212529 sur le bleu #007bff : 3.87:1, quand
 * le critère 3.2 du RGAA en demande 4.5. C'est la seule ligne lisible de la
 * liste qui ne l'était pas assez, et elle l'est sur toutes les pages — toute
 * liste déroulante du site passe par là.
 *
 * On garde le bleu, assombri d'un cran — c'est celui que Bootstrap emploie
 * déjà au survol d'un bouton primaire — et on écrit en blanc : 7.05:1.
 */
/* **Les deux themes, et non un seul.** Cette regle ne couvrait que
   `--admin-autocomplete`. Or le filtre par installateur (`js/autocompletion.js`)
   et les listes des lignes ajoutees (`js/lignes-ajoutees.js`) initialisent
   select2 **sans theme** : ils tombent sur `default`, et ne recevaient donc
   aucune correction de contraste sur l'option survolee. */
.select2-container--admin-autocomplete .select2-results__option--highlighted,
.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected],
.select2-container--default .select2-results__option--highlighted,
.select2-container--default .select2-results__option--highlighted[aria-selected] {
    background-color: #0056b3;
    color: #fff;
}

/* --- Les quatre liens d'une liste de relation ---------------------------------
 *
 * Django les dessine avec quatre fichiers SVG, servis un par un : quatre
 * requêtes HTTP pour quatre icônes de treize pixels, sur chaque page qui porte
 * une liste déroulante de relation. Ce sont désormais des masques, dans cette
 * feuille, déjà chargée.
 *
 * Les teintes sont celles des fichiers d'origine, reprises telles quelles :
 * c'est à sa couleur qu'on reconnaît ce que fait chacun de ces liens. Le vert
 * donne 3,14:1 sur blanc et le bleu 5,03:1 — au-delà des 3:1 que le critère
 * RGAA 3.3 demande à un élément d'interface.
 *
 * La taille est celle des images remplacées : 24 pixels, alignés sur le
 * milieu de la ligne.
 */
.od-picto--lien {
    width: 24px;
    height: 24px;
    vertical-align: middle;
}

.od-picto--ajouter {
    background-color: #5fa225;
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%3E%3Cpath%20d%3D%22M1600%20796v192q0%2040-28%2068t-68%2028h-416v416q0%2040-28%2068t-68%2028h-192q-40%200-68-28t-28-68v-416h-416q-40%200-68-28t-28-68v-192q0-40%2028-68t68-28h416v-416q0-40%2028-68t68-28h192q40%200%2068%2028t28%2068v416h416q40%200%2068%2028t28%2068z%22%2F%3E%3C%2Fsvg%3E");
}

.od-picto--consulter {
    background-color: #2b70bf;
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%3E%3Cpath%20d%3D%22M1664%20960q-152-236-381-353%2061%20104%2061%20225%200%20185-131.5%20316.5t-316.5%20131.5-316.5-131.5-131.5-316.5q0-121%2061-225-229%20117-381%20353%20133%20205%20333.5%20326.5t434.5%20121.5%20434.5-121.5%20333.5-326.5zm-720-384q0-20-14-34t-34-14q-125%200-214.5%2089.5t-89.5%20214.5q0%2020%2014%2034t34%2014%2034-14%2014-34q0-86%2061-147t147-61q20%200%2034-14t14-34zm848%20384q0%2034-20%2069-140%20230-376.5%20368.5t-499.5%20138.5-499.5-139-376.5-368q-20-35-20-69t20-69q140-229%20376.5-368t499.5-139%20499.5%20139%20376.5%20368q20%2035%2020%2069z%22%2F%3E%3C%2Fsvg%3E");
}

.od-picto--modifier {
    background-color: #b48c08;
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%3E%3Cpath%20d%3D%22M491%201536l91-91-235-235-91%2091v107h128v128h107zm523-928q0-22-22-22-10%200-17%207l-542%20542q-7%207-7%2017%200%2022%2022%2022%2010%200%2017-7l542-542q7-7%207-17zm-54-192l416%20416-832%20832h-416v-416zm683%2096q0%2053-37%2090l-166%20166-416-416%20166-165q36-38%2090-38%2053%200%2091%2038l235%20234q37%2039%2037%2091z%22%2F%3E%3C%2Fsvg%3E");
}

.od-picto--supprimer {
    background-color: #dd4646;
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201792%201792%22%3E%3Cpath%20d%3D%22M1490%201322q0%2040-28%2068l-136%20136q-28%2028-68%2028t-68-28l-294-294-294%20294q-28%2028-68%2028t-68-28l-136-136q-28-28-28-68t28-68l294-294-294-294q-28-28-28-68t28-68l136-136q28-28%2068-28t68%2028l294%20294%20294-294q28-28%2068-28t68%2028l136%20136q28%2028%2028%2068t-28%2068l-294%20294%20294%20294q28%2028%2028%2068z%22%2F%3E%3C%2Fsvg%3E");
}

.od-picto--frise {
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20512%20512%22%3E%3Cpath%20d=%22M32%20240h448v32H32z%22/%3E%3Ccircle%20cx=%2296%22%20cy=%22256%22%20r=%2256%22/%3E%3Ccircle%20cx=%22256%22%20cy=%22256%22%20r=%2256%22/%3E%3Ccircle%20cx=%22416%22%20cy=%22256%22%20r=%2256%22/%3E%3C/svg%3E");
}

/* La main levee de « faire une demande ». Elle ne reprend surtout pas
   l'enveloppe : « Envoyer le lien de suivi » est juste a cote dans la meme
   barre, et les deux boutons portaient le meme dessin pour deux gestes
   differents — on ecrit au client dans un cas, on sollicite l'installateur
   dans l'autre.

   La fenetre est 480 x 816 et non 448 x 768 : un viewport SVG **rogne**, et le
   trace atteint x=463 et y=32. Le bord du pouce et le bas de la main etaient
   coupes dans les deux boutons. Mesure du trace : x de 20 a 463, y de -736 a
   32 — la fenetre l'enclot desormais avec une marge de dessin. */
.od-picto--demande {
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%20-768%20480%20816%22%3E%3Cpath%20d=%22M32%20-416Q33%20-389%2051%20-371Q69%20-353%2096%20-352Q123%20-353%20141%20-371Q159%20-389%20160%20-416V-672Q161%20-699%20179%20-717Q197%20-735%20224%20-736Q251%20-735%20269%20-717Q287%20-699%20288%20-672V-352V-256V-199Q289%20-186%20300%20-181Q312%20-177%20321%20-186L361%20-226Q380%20-243%20404%20-243Q428%20-243%20446%20-226Q463%20-208%20463%20-184Q463%20-160%20446%20-142L321%20-17Q275%2029%20211%2032H176Q110%2030%2066%20-14Q22%20-58%2020%20-124V-416Q21%20-443%2039%20-461Q57%20-479%2084%20-480Q85%20-480%2086%20-480Q32%20-470%2032%20-416Z%22/%3E%3C/svg%3E");
}

/* La cloche de « suivre ce dossier ». Un trace a nous, en segments et
   quadratiques, entierement contenu entre 56 et 440 sur les deux axes : la
   fenetre 512 l'enclot sans calcul, ce qui est tout l'interet apres le
   rognage du picto voisin. */
.od-picto--cloche {
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20512%20512%22%3E%3Cpath%20d=%22M256%2056Q268%2056%20268%2072V88Q376%20104%20376%20208V288L408%20344V360H104V344L136%20288V208Q136%20104%20244%2088V72Q244%2056%20256%2056ZM208%20392H304Q304%20440%20256%20440Q208%20440%20208%20392Z%22/%3E%3C/svg%3E");
}

.od-picto--enveloppe {
    --od-picto: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%20-459%20512%20534%22%3E%3Cpath%20d=%22M48%20-384Q28%20-383%2014%20-370Q1%20-356%200%20-336Q1%20-312%2019%20-298L237%20-134Q256%20-122%20275%20-134L493%20-298Q511%20-312%20512%20-336Q511%20-356%20498%20-370Q484%20-383%20464%20-384H48ZM0%20-272V-64V-272V-64Q1%20-37%2019%20-19Q37%20-1%2064%200H448Q475%20-1%20493%20-19Q511%20-37%20512%20-64V-272L294%20-109Q277%20-96%20256%20-96Q235%20-96%20218%20-109L0%20-272Z%22/%3E%3C/svg%3E");
}

/* --- La largeur d'une liste d'administration -------------------------------
 *
 * Le parent de `#od-liste` est une `.row` de Bootstrap, donc une boîte flexible,
 * et la zone y vaut `flex: 0 1 auto` : elle se réduit à son contenu. Un `col-12`
 * l'enveloppait et lui donnait la pleine largeur ; il est parti avec un lot
 * d'allègement du DOM, et j'avais vérifié la géométrie sur la liste des
 * dossiers — large de dix colonnes, donc insensible au défaut. Les autres s'en
 * trouvaient tassées sur la gauche :
 *
 *     liste des modules        526 px de large pour 1286 disponibles
 *     liste des installateurs  691 px
 *
 * Une déclaration de largeur suffit, là où le `col-12` coûtait un élément de
 * DOM par page de liste.
 */
.row > #od-liste {
    width: 100%;
}


/* --- La largeur des listes déroulantes -------------------------------------
 *
 * `jazzmin/js/change_form.js` initialise select2 avec `width: 'element'` : la
 * bibliothèque recopie alors la largeur intrinsèque du `<select>` dans un
 * `style="width: 320px"` posé en ligne, et une de ses feuilles ajoute
 * `min-width: 200px`. Ni l'une ni l'autre ne connaît la colonne qui accueille
 * le champ. Sur une ligne de deux champs, la liste du code postal débordait
 * donc sur l'intitulé « Ville », qu'elle recouvrait — reproduit dès 1400 px de
 * fenêtre.
 *
 * Trois douzièmes de la grille, comme les autres champs. `!important` parce
 * que la largeur est posée en ligne par le script, et qu'une feuille ne peut
 * pas la contredire autrement ; `min-width: 0` parce que le plancher de
 * select2 rouvrirait le débordement sous 1250 px.
 */
.select2-container {
    width: 100% !important;
    max-width: 100%;
    min-width: 0;
}

/* ------------------------------------------------------- les graphiques ----
 * Le tableau de bord dessine en SVG rendu par le serveur, sans bibliothèque :
 * voir `backoffice/graphiques.py` pour le pourquoi et le chiffrage. Ce bloc
 * porte tout ce que le dessin n'écrit pas — l'axe, la grille, les teintes et
 * les motifs de trait — précisément pour que le SVG n'ait pas à les payer en
 * éléments de DOM, qui pèsent triple dans l'EcoIndex.
 *
 * ## Le contraste, et pourquoi la couleur ne distingue rien ici
 *
 * WCAG 1.4.11 demande 3:1 entre un objet graphique et les couleurs qui lui
 * sont adjacentes. Mesuré sur la palette de cette feuille, sur fond blanc :
 *
 *     #0f7a78  teal maison   5,15:1
 *     #0b5ed7  bleu          5,84:1
 *     #8a5200  ambre         6,39:1
 *     #41525c  ardoise       8,12:1
 *
 * Chacune passe donc largement contre le fond. **Entre elles, aucune paire
 * n'atteint 3:1** — les écarts vont de 1,01:1 à 1,60:1, parce que toutes ont
 * été choisies contre le blanc et ont par construction des luminances
 * voisines. Et ce n'est pas un défaut de choix : trois teintes mutuellement à
 * 3:1 dont chacune serait à 3:1 sur blanc n'existent pas, le blanc ne laisse
 * pas assez de place sur l'échelle de luminance.
 *
 * Deux conséquences, et elles sont dans le dessin :
 *
 * - les barres d'un même groupe ne se touchent pas (`INTERSTICE` dans
 *   `graphiques.py`), de sorte que chaque barre n'est adjacente qu'au fond ;
 * - ce qui distingue les séries n'est **jamais** leur couleur : c'est leur
 *   position dans le groupe pour les barres, leur motif de trait pour les
 *   courbes, et la légende énonce l'une comme l'autre en texte. C'est ce
 *   qu'exige WCAG 1.4.1, et c'est aussi ce qui fait tenir le graphique en
 *   noir et blanc ou pour un œil daltonien.
 *
 * axe-core ne mesure **pas** le contraste d'un `fill` SVG : ces ratios ne sont
 * vérifiés par aucun balayage, seulement par ce commentaire. Les recalculer
 * avant de changer une teinte.
 */

.od-graphe {
    margin: 0;
}

.od-graphe figcaption,
.od-graphe > figcaption {
    font-size: 0.92rem;
    font-weight: 600;
    margin-bottom: 0.35rem;
}

/* La légende et l'échelle vivent dans le titre : du texte, pas des éléments
   de décor. Le `::before` dessine la pastille de la série sans coûter un
   élément de plus. */
.od-graphe figcaption b {
    font-weight: 500;
}

.od-graphe figcaption b::before {
    content: "";
    display: inline-block;
    width: 0.7rem;
    height: 0.7rem;
    margin: 0 0.25rem 0 0.5rem;
    vertical-align: baseline;
    background: currentColor;
}

/* Et chaque série donne sa couleur à sa pastille. Sans ces quatre règles,
   `currentColor` vaut l'encre du titre : les pastilles sortaient **toutes
   noires**, et une légende de deux séries ne distinguait rien. Les couleurs
   n'étaient déclarées que sous `.od-graphe__dessin`, en `fill` et `stroke`,
   qui ne s'appliquent qu'au SVG — la légende, elle, est du HTML dans le
   `<figcaption>`.

   Le défaut s'est vu sur une copie d'écran prise pour les guides : « créés »
   et « clos » portaient le même carré sombre. Aucun test ne le voyait, et
   axe-core non plus : deux carrés de même couleur ne sont pas une faute de
   contraste.

   La couleur ne porte que la pastille, jamais le texte : ces teintes sont
   choisies pour 3:1 contre le fond, ce qui suffit à un aplat et non à du
   texte, qui en demande 4,5. */
.od-graphe figcaption .od-serie--1::before       { background: #2c6faf; }
.od-graphe figcaption .od-serie--2::before       { background: #b07a00; }
.od-graphe figcaption .od-serie--3::before       { background: #6b4fbb; }
.od-graphe figcaption .od-serie--moyenne::before { background: #41525c; }

/* Sur une courbe, ce n'est pas la couleur qui distingue deux séries mais le
   motif du trait — trois teintes mutuellement à 3:1 et chacune à 3:1 sur
   blanc n'existent pas, et c'est mesuré. La légende montre donc le trait
   avec son motif, et non un aplat : le repère du titre et celui du dessin
   sont alors le même signal. Les périodes reprennent les `stroke-dasharray`
   ci-dessous, à l'échelle d'un dixième de rem par unité. */
.od-graphe--courbe figcaption b::before {
    width: 1.6rem;
    height: 0.22rem;
    vertical-align: 0.18em;
}

.od-graphe--courbe figcaption .od-serie--2::before {
    background: repeating-linear-gradient(to right,
        #b07a00 0 0.7rem, transparent 0.7rem 1.1rem);
}

.od-graphe--courbe figcaption .od-serie--3::before {
    background: repeating-linear-gradient(to right,
        #6b4fbb 0 0.2rem, transparent 0.2rem 0.5rem);
}

.od-graphe--courbe figcaption .od-serie--moyenne::before {
    background: repeating-linear-gradient(to right,
        #41525c 0 0.1rem, transparent 0.1rem 0.4rem);
}

.od-graphe figcaption small {
    font-weight: 400;
    color: #595f66;   /* 6,21:1 sur blanc */
}

/* L'axe horizontal et la grille, en CSS : un trait décoratif n'a pas à être
   un élément de DOM. Quatre lignes de grille pour situer les hauteurs, sans
   graduation chiffrée — c'est l'échelle du titre qui la donne. */
.od-graphe__dessin {
    display: block;
    width: 100%;
    height: auto;
    border-bottom: 1px solid var(--od-quiet-border);
    background: repeating-linear-gradient(
        to top,
        transparent 0,
        transparent calc(25% - 1px),
        #eef1f3 calc(25% - 1px),
        #eef1f3 25%
    );
}

/* Les separations de mois, sur l'axe horizontal. Un second gradient, de
   periode `100% / --mois`, qui ne dessine qu'un trait de un pixel en bas
   de chaque mois. Le nombre de mois est pose en propriete personnalisee sur
   le `<svg>` par le gabarit : c'est la seule chose que le CSS ne peut pas
   deviner.

   **Zero element de DOM.** Douze graduations dessinees en SVG en couteraient
   douze, et vingt-quatre pour deux graphiques — c'est exactement le genre de
   depense que ce module s'interdit. La grille horizontale ci-dessus est deja
   faite ainsi.

   Les traits s'arretent a huit pixels du bas : ils situent les mois sans
   couper les barres, qui montent depuis la ligne d'axe. */
.od-graphe__dessin[style*="--mois"] {
    background-image:
        repeating-linear-gradient(
            to top,
            transparent 0,
            transparent calc(25% - 1px),
            #eef1f3 calc(25% - 1px),
            #eef1f3 25%
        ),
        repeating-linear-gradient(
            to right,
            transparent 0,
            transparent calc(100% / var(--mois) - 1px),
            #d7dde2 calc(100% / var(--mois) - 1px),
            #d7dde2 calc(100% / var(--mois))
        );
    background-size: 100% 100%, 100% 9px;
    background-position: 0 0, 0 100%;
    background-repeat: no-repeat, no-repeat;
}

/* Les zones de survol : un rectangle par mois, transparent, qui ne sert qu'à
   porter un `<title>`. Le navigateur en fait une infobulle native, sans une
   ligne de script.

   `fill: transparent` et non `fill: none` : un remplissage absent ne reçoit
   pas d'événement de souris, donc l'infobulle ne s'afficherait jamais. C'est
   le genre de nuance qui fait passer une heure.

   Pas de `pointer-events: none` non plus, évidemment — mais pas de curseur
   particulier : il n'y a rien à cliquer, et un curseur de main promettrait
   une action qui n'existe pas. */
.od-graphe__survol {
    fill: transparent;
}

/* Les deux libellés d'axe, sous le dessin. Ils étaient des `<text>` dans le
   SVG, et grandissaient donc avec lui : passés à 635 pixels de large, ils
   s'affichaient à vingt-neuf pixels. En HTML, le corps suit celui de la page.
   Voir `graphiques._bornes`. */
.od-graphe__bornes {
    display: flex;
    justify-content: space-between;
    margin: 0.25rem 0 0;
    font-size: 0.78rem;
    color: #595f66;   /* 6,21:1 sur blanc */
}

/* Un seul point ne donne qu'une borne : elle se centre plutôt que de se
   coller à gauche, sans quoi elle aurait l'air d'un début de période. */
.od-graphe__bornes > span:only-child {
    margin: 0 auto;
}

.od-graphe__vide {
    margin: 0;
    padding: 1.25rem 0;
    color: #595f66;
    font-style: italic;
}

/* Les séries, dérivées du logo Python et adoucies pour tenir le contraste.
   La couleur ne porte aucune information (voir plus haut) : le
   `stroke-dasharray` est ce qui distingue deux courbes, et l'ordre dans le
   groupe ce qui distingue deux barres.

   Le jaune du logo — `#FFD43B` — ne vaut que **1,43:1 sur blanc**, loin des
   3:1 qu'un aplat demande. On le descend jusqu'à l'ocre, qui garde sa
   franchise et tient 3,73:1. Le bleu, lui, passe presque tel quel.

       série 1  #2c6faf  5,25:1    bleu du logo
       série 2  #b07a00  3,73:1    jaune du logo, descendu
       série 3  #6b4fbb  6,07:1    violet, pour une troisième franche
       moyenne  #41525c  8,12:1    ardoise, c'est un repère et non une série

   Les trois séries ne se distinguent **pas** entre elles par la luminance —
   1,16:1 entre le bleu et le violet — et c'est assumé : trois teintes
   mutuellement à 3:1 et chacune à 3:1 sur blanc n'existent pas. C'est le
   motif du trait qui les sépare, et la légende le reprend. */
.od-graphe__dessin .od-serie--1 { fill: #2c6faf; stroke: #2c6faf; }
.od-graphe__dessin .od-serie--2 { fill: #b07a00; stroke: #b07a00; }
.od-graphe__dessin .od-serie--3 { fill: #6b4fbb; stroke: #6b4fbb; }

/* La référence — la moyenne du périmètre, sur la page de statistiques. En
   ardoise et en pointillé serré : c'est un repère, pas une série de plus. */
.od-graphe__dessin .od-serie--moyenne { fill: #41525c; stroke: #41525c; }

/* Une courbe n'a pas de remplissage, et son trait porte le motif. Le
   `stroke-linecap: round` n'est pas cosmétique : c'est lui qui rend visible
   un sous-chemin de longueur nulle, c'est-à-dire un mois isolé entre deux
   mois non renseignés. */
.od-graphe--courbe .od-serie--1,
.od-graphe--courbe .od-serie--2,
.od-graphe--courbe .od-serie--3,
.od-graphe--courbe .od-serie--moyenne {
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.od-graphe--courbe .od-serie--2       { stroke-dasharray: 7 4; }
.od-graphe--courbe .od-serie--3       { stroke-dasharray: 2 3; }
.od-graphe--courbe .od-serie--moyenne { stroke-width: 1.5; stroke-dasharray: 1 3; }

/* --- Les barres à libellés, en HTML -----------------------------------------
 * Pour les séries dont **chaque** point a besoin de son libellé — les étapes
 * du parcours, l'entonnoir, les communes. Pas de SVG ici, et c'est un choix
 * mesuré : le texte d'un `<svg>` se met à l'échelle avec son `viewBox`, donc
 * dix libellés dans une carte de trois cents pixels s'afficheraient autour de
 * sept pixels et demi — illisible, et RGAA 10.4 devient discutable.
 *
 * Une `<dl>` : un `<dt>` par étape, un `<dd>` par valeur. La barre est le
 * `::before` du `<dd>`, et sa longueur vient de `--part`, posé en style
 * d'attribut par le gabarit. Trois éléments par ligne, et le texte reste du
 * texte : lu nativement, zoomable, sélectionnable, sans question
 * d'alternative.
 */

.od-barres {
    display: grid;
    grid-template-columns: minmax(8rem, auto) 1fr;
    gap: 0.2rem 0.75rem;
    margin: 0;
    font-size: 0.92rem;
}

.od-barres dt {
    font-weight: 400;
    min-width: 0;
}

/* **La barre sous son chiffre**, et non à côté : c'est ce qui règle à la fois
   le débordement du texte et la comparabilité d'une ligne à l'autre.

   Première version, avec `display: flex` : la barre était un élément de
   largeur `calc(--part * 100%)` que rien ne laissait rétrécir, et cette
   largeur entrait dans la largeur intrinsèque du `<dd>`. Sur une colonne
   étroite, le total — barre plus « 26 jours » en `nowrap` — dépassait la
   piste, et le texte courait sous la colonne voisine : on lisait
   « 18 jourssur 577 ». Mesuré sur le tableau de bord : cinq lignes sur dix
   débordaient de 28 à 59 pixels. Le défaut ne se voyait pas sur l'ancien jeu
   de démonstration, dont les valeurs tenaient en deux caractères.

   Deuxième version, deux colonnes en grille — la barre dans sa piste, le
   texte dans la sienne : plus de débordement, mais la piste de la barre
   changeait de largeur d'une ligne à l'autre, puisque le texte y prenait sa
   `max-content` et que « 6 jours » est plus court que « 17 jours ». La
   longueur d'une barre ne se comparait donc plus d'une ligne à l'autre :
   mesuré, une part de 0,231 rendait une barre plus longue qu'une part de
   0,269. Un diagramme dont les longueurs mentent est pire qu'un tableau.

   Troisième version, celle-ci : la barre est sur **sa propre ligne**, sous le
   chiffre. Sa largeur en pourcentage se résout sur la largeur du `<dd>`, qui
   est celle de la piste de la grille extérieure — la même pour toutes les
   lignes. Le texte ne lui dispute plus rien, et deux barres se comparent.
   Coût : un demi-interligne par ligne. */
.od-barres dd {
    margin: 0;
    display: grid;
    grid-template-rows: auto auto;
    align-content: center;
    gap: 0.18rem;
    white-space: nowrap;
}

.od-barres dd::before {
    content: "";
    grid-row: 2;
    height: 0.4rem;
    width: calc(var(--part, 0) * 100%);
    background: #2c6faf;   /* 5,25:1 sur blanc */
}

/* Une valeur nulle donne une barre de largeur nulle, donc rien — et sans
   `min-width`, ce qui est voulu : un filet d'un pixel ferait croire à une
   valeur très petite, qui n'est pas la même chose que rien. Pas besoin d'une
   règle qui inspecte l'attribut `style` : `calc(0 * 100%)` suffit, et aucun
   sélecteur n'a à connaître le format de nombre du gabarit. */

/* Deux colonnes de valeurs : l'effectif et le délai de la même étape. */
.od-barres--duo {
    grid-template-columns: minmax(8rem, auto) 1fr minmax(4rem, auto);
}

.od-barres__appoint {
    color: #595f66;   /* 6,21:1 sur blanc */
    text-align: right;
}

/* --- Les trois crans d'urgence ----------------------------------------------
 * Un dégradé qui se lit sans qu'on lise : rouge vif, rouge, orange. La ligne
 * entière est teintée — l'intitulé et le nombre — parce qu'une couleur posée
 * sur le seul chiffre oblige à chercher de quoi il parle.
 *
 * La couleur n'est **jamais seule** : les trois intitulés se classent par
 * eux-mêmes — « Critique », « Urgent », « À surveiller » — et la ligne reste
 * lisible en noir et blanc comme pour qui distingue mal les couleurs
 * (WCAG 1.4.1).
 *
 * Les trois teintes tiennent le 4,5:1 sur blanc, puisqu'elles portent du
 * texte et non un aplat :
 *
 *     critique      #c2272d   5,80:1
 *     urgent        #9b2226   7,92:1
 *     à surveiller  #b35c00   4,72:1
 *
 * Le fond est une teinte très claire de la même couleur, qui situe la ligne
 * sans la rendre criarde — le texte y garde 4,58:1 au pire, mesure sur les
 * trois paires reellement rendues.
 */

/* --- Les lignes allumees du premier bloc ------------------------------------
 *
 * **La classe etait `od-urgence`, posee sans condition.** Les trois crans
 * etaient donc colores meme a zero : la couleur ne disait pas « il y a
 * urgence », elle disait « cette ligne parle d'urgence ». Un tableau de bord
 * tout propre avait l'air d'un tableau de bord en feu, et le jour ou quelque
 * chose brulait vraiment, rien ne changeait a l'ecran.
 *
 * La classe s'appelle maintenant `od-vif`, le gabarit ne la pose que si le
 * nombre est non nul, et la grammaire tient en une phrase : **en couleur, il
 * faut regarder ; en noir, tout va bien.**
 *
 * Trois familles de teinte, parce que ce ne sont pas trois fois le meme
 * probleme :
 *
 * - les **urgences** regardent une echeance qui approche — rouge, le retard ;
 * - l'**oubli** regarde un dossier qui dort depuis trente jours — ardoise,
 *   l'assoupissement, et surtout pas une quatrieme nuance de rouge qui
 *   entrerait en concurrence avec les trois crans ;
 * - la **piste** regarde une occasion a saisir — le teal de la marque. Une
 *   demande entrante n'est pas un retard : la ranger dans la famille du
 *   rouge ferait lire une bonne nouvelle comme une alerte.
 */

.od-chiffres .od-vif {
    font-weight: 600;
    padding: 0.08rem 0.3rem;
}

/* La gouttiere de la grille coupait la teinte en deux : l'intitule et le
   nombre formaient deux pastilles separees au lieu d'une ligne. Une ombre
   portee de chaque cote, large d'une demi-gouttiere, la comble — sans
   toucher a la mise en page, la ou un `gap: 0` aurait resserre toutes les
   autres lignes du bloc.

   `currentColor` vaudrait la couleur du texte : chaque teinte redefinit donc
   l'ombre avec son propre fond, en meme temps que ce fond. */
.od-chiffres .od-vif {
    box-shadow: 0.375rem 0 0 currentColor, -0.375rem 0 0 currentColor;
}

.od-chiffres .od-vif--urgent_1 {
    color: #c2272d;
    background: #fbeaea;
    box-shadow: 0.375rem 0 0 #fbeaea, -0.375rem 0 0 #fbeaea;
}

.od-chiffres .od-vif--urgent_2 {
    color: #9b2226;
    background: #fbefef;
    box-shadow: 0.375rem 0 0 #fbefef, -0.375rem 0 0 #fbefef;
}

/* `#b35c00` valait **4,25:1** sur son fond, sous le seuil de 4,5:1 qu'un texte
   normal demande — `.od-chiffres` est a 0,92 rem, et `font-weight: 600`
   n'ouvre pas l'exception du grand texte. `#AB5800` monte a 4,58:1, et l'ecart
   ne se voit pas. */
.od-chiffres .od-vif--urgent_3 {
    color: #AB5800;
    background: #fdf1e5;
    box-shadow: 0.375rem 0 0 #fdf1e5, -0.375rem 0 0 #fdf1e5;
}

/* Le dossier oublie : ardoise sur gris tres clair, **6,59:1** mesure. Au-dela
   du seuil, et volontairement : cette ligne ne doit pas crier plus fort que
   les trois crans d'urgence qui la precedent, et une teinte froide se lit
   comme « en attente » plutot que comme « en retard ». */
.od-chiffres .od-vif--oubli {
    color: #4A5568;
    background: #eef0f3;
    box-shadow: 0.375rem 0 0 #eef0f3, -0.375rem 0 0 #eef0f3;
}

/* La piste commerciale : le teal de la marque, assombri pour le contraste.
   `#007A7A` tombait a **4,58:1** sur ce fond — juste au-dessus du seuil, donc
   sans marge ; `#006B6B` donne **5,61:1** et la difference ne se voit pas. */
.od-chiffres .od-vif--piste {
    color: #006B6B;
    background: #e6f4f4;
    box-shadow: 0.375rem 0 0 #e6f4f4, -0.375rem 0 0 #e6f4f4;
}

/* Le lien du nombre prend la couleur de sa ligne plutôt que le bleu des
   liens : sur une ligne teintée, un nombre bleu se lirait comme un intrus. */
.od-chiffres .od-vif a {
    color: inherit;
    text-decoration: underline;
}

/* --- Les blocs du tableau de bord -------------------------------------------
 * Une `<section>` à bordure, et non la pile `div.card` + `div.card-header` +
 * `h2` + `div.card-body` d'AdminLTE : quatre éléments pour un encadré que la
 * bordure dessine. Sur dix blocs, cela fait trente éléments de DOM pour de la
 * décoration.
 */

.od-bloc {
    border: 1px solid var(--od-quiet-border);
    border-radius: 0.3rem;
    padding: 0.85rem 1rem;
    background: #fff;
}

.od-bloc__titre {
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 0.6rem;
}

/* --- La grille du tableau de bord -------------------------------------------
 * Une grille CSS sur un conteneur unique, et non `row`/`col`.
 *
 * C'est ce qui règle le « sans perte d'espace » : `auto-fill` répartit les
 * blocs selon la largeur disponible, et `align-items: start` les empêche de
 * s'étirer à la hauteur du plus haut de leur rangée — un bloc de trois lignes
 * à côté d'un bloc de dix laissait sinon sept lignes de vide. Un bloc absent —
 * les pistes pour un installateur, les courriels quand la file d'envoi va
 * bien — ne laisse plus de colonne vide non plus.
 *
 * Coût : **un** élément d'habillage pour toute la page, contre six `div.col-*`
 * et une `div.row` avant.
 */

/* La largeur, d'abord — et c'est une correction. Le parent de `.od-tableau`
   est une `.row` de Bootstrap, donc une boîte flexible, et la grille y vaut
   `flex: 0 1 auto` : elle se réduisait à son contenu. Mesuré au navigateur :

       tableau de bord          664 px de large pour 1286 disponibles
       page de statistiques    1080 px

   C'est le même défaut que `#od-liste` plus haut, né de la même suppression
   des `col-12`, sur un troisième écran. Il ne s'était pas vu parce qu'une
   grille `auto-fill` remplit sans se plaindre ce qu'on lui donne : on voyait
   deux colonnes bien rangées, et la moitié droite de la page vide. */
.row > .od-tableau {
    width: 100%;
}

/* Deux colonnes, et non plus `auto-fill`. Sur 1286 pixels, `auto-fill` en
   fabriquait quatre de 320, soit des blocs trop étroits pour un tableau de
   délais ; et surtout l'appariement des blocs était subi — il dépendait de la
   largeur de la fenêtre. Deux colonnes déclarées, c'est « les dossiers » en
   face de « combien de temps prend chaque étape », et « dossiers par mois »
   en face de « puissance par mois », quelle que soit la fenêtre.

   `minmax(0, 1fr)` et non `1fr` : le minimum automatique d'une piste de
   grille est le contenu minimal de son élément, et un tableau de sept
   colonnes le ferait déborder. */
.od-tableau {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    align-items: start;
}

@media (min-width: 62em) {
    .od-tableau {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* La période court sur toute la largeur : elle gouverne tout ce qui suit. */
.od-tableau > .od-periode {
    grid-column: 1 / -1;
}

/* Les graphiques sont des éléments de grille comme les autres, et prennent le
   même encadré que les blocs — sans l'élément d'habillage qui l'aurait porté. */
.od-tableau > .od-graphe {
    border: 1px solid var(--od-quiet-border);
    border-radius: 0.3rem;
    padding: 0.85rem 1rem;
    background: #fff;
}

.od-periode {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.5rem 0.75rem;
    border: 1px solid var(--od-quiet-border);
    border-radius: 0.3rem;
    padding: 0.75rem 1rem;
    background: #fff;
}

.od-periode label {
    margin: 0 0 0.15rem;
    font-size: 0.86rem;
    color: #595f66;   /* 6,21:1 sur blanc */
}

.od-periode input.vDateNatif {
    width: auto;
}

/* Le choix d'installateur prend la place qui reste. */
.od-periode .form-group {
    flex: 1 1 14rem;
    margin: 0;
    min-width: 0;
}

/* Deux colonnes : l'intitulé, puis le nombre aligné à droite. Le nombre est
   ce qu'on vient lire, et c'est pour cela qu'il est en graisse et non
   l'intitulé. */
.od-chiffres {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0.2rem 0.75rem;
    margin: 0;
    font-size: 0.92rem;
}

.od-chiffres dt {
    font-weight: 400;
}

.od-chiffres dd {
    margin: 0;
    text-align: right;
    font-weight: 600;
}

.od-chiffres dd small {
    font-weight: 400;
    color: #595f66;
}

.od-bloc__note {
    margin: 0.6rem 0 0;
    font-size: 0.86rem;
    color: #595f66;
}

/* Un bloc qui ne s'affiche qu'en panne. La couleur n'est pas seule à le dire :
   le texte annonce la panne en toutes lettres. */
.od-bloc--alerte {
    border-color: var(--od-danger);
}

.od-bloc--alerte p {
    margin: 0 0 0.4rem;
    color: var(--od-danger);
}

.od-bloc--alerte p:last-child {
    margin-bottom: 0;
}

/* Le journal, ramené de onze éléments par entrée à deux. */
/* --- Mes dernieres actions --------------------------------------------------
 *
 * C'etait une `<ul>` d'une ligne par entree : trois lignes « DEMO-412 »
 * disaient trois fois la meme chose. C'est desormais un tableau de trois
 * colonnes — l'objet, ce qu'on lui a fait, quand — avec un `rowspan` sur la
 * premiere cellule quand un objet porte plusieurs actions.
 *
 * `border-collapse` et non `separate` : sans lui, le `rowspan` laisse
 * apparaitre les bordures internes de la cellule fusionnee, et le groupe se
 * lit comme trois objets au lieu d'un.
 */

.od-journal {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
}

.od-journal th,
.od-journal td {
    padding: 0.2rem 0.5rem 0.2rem 0;
    text-align: left;
    font-weight: 400;
    vertical-align: top;
}

/* L'en-tete de colonne, discret : ce sont trois mots qui nomment des colonnes
   evidentes, ils ne doivent pas peser autant que le contenu. */
.od-journal thead th {
    font-size: 0.82rem;
    color: #595f66;
    border-bottom: 1px solid #d8dce1;
}

/* La cellule de l'objet porte le `rowspan`. Un filet en haut separe les
   groupes, et la bordure du groupe precedent ne coupe donc jamais une suite
   d'actions en deux. */
.od-journal tbody th {
    font-weight: 600;
    border-top: 1px solid #eceef1;
}

/* Un `<tbody>` par objet — voir le gabarit, c'est `scope="rowgroup"` qui
   l'exige. Donc `tbody tr:first-child` designe **chaque** objet, et non le
   premier : le filet doit se retirer du premier groupe, pas de tous. */
.od-journal tbody:first-of-type th {
    border-top: 0;
}

.od-journal__quand {
    color: #595f66;
    white-space: nowrap;
}

/* --- La page de statistiques ------------------------------------------------
 * Elle réutilise la grille du tableau de bord, et n'ajoute que deux choses :
 * un bloc qui prend toute la largeur, pour les communes, et un tableau de
 * données.
 *
 * C'est le seul endroit du chantier où l'on paie un `<table>`, et c'est
 * assumé : un tableau de dix communes sur cinq colonnes, ce sont cinquante
 * cellules, mais ce sont des **données**, pas de la décoration. La règle du
 * projet n'est pas « jamais de tableau », c'est « jamais un tableau pour
 * mettre en page ».
 */

.od-bloc--large {
    grid-column: 1 / -1;
}

.od-donnees {
    width: 100%;
    margin-top: 0.75rem;
    border-collapse: collapse;
    font-size: 0.92rem;
}

.od-donnees th,
.od-donnees td {
    padding: 0.3rem 0.5rem;
    border-bottom: 1px solid var(--od-quiet-border);
    text-align: right;
}

.od-donnees thead th,
.od-donnees tbody th {
    text-align: left;
    font-weight: 600;
}

.od-donnees thead th:not(:first-child) {
    text-align: right;
}

/* --- Le tableau des durées d'étape ------------------------------------------
 * La cellule de la médiane porte sa barre en `::before` : la forme se voit
 * d'un coup d'oeil, et le dessin ne coûte aucun élément de DOM. C'est la même
 * mécanique que `.od-barres`, dans une cellule plutôt que dans un `<dd>`.
 *
 * La barre est **décorative** — elle redit la valeur écrite dans la cellule —
 * donc elle n'a ni rôle ni nom accessible. Un lecteur d'écran lit le tableau,
 * qui porte l'information complète, en-têtes de ligne et de colonne compris.
 */

.od-etapes__mediane {
    position: relative;
    font-weight: 600;
}

.od-etapes__mediane::before {
    content: "";
    position: absolute;
    left: 0.5rem;
    bottom: 0.15rem;
    height: 0.22rem;
    /* La piste va du bord gauche de la cellule à son bord droit moins les
       deux rembourrages : la longueur se compare donc d'une ligne à
       l'autre, toutes les cellules de la colonne ayant la même largeur. */
    width: calc(var(--part, 0) * (100% - 1rem));
    background: #2c6faf;   /* 5,25:1 sur blanc */
}

/* Sept colonnes dans une demi-largeur : les chiffres se resserrent, et les
   en-têtes de rang sont des fractions. Pas de `display: block` ici — il
   transformerait le tableau en boîte de bloc, dont le contenu se réduit à sa
   taille naturelle au lieu de remplir la colonne. Mesuré : 760 pixels de
   contenu pour 635 de piste, et un tableau collé à gauche. */
.od-etapes th,
.od-etapes td {
    padding: 0.3rem 0.35rem;
}

.od-etapes thead abbr {
    text-decoration: none;
    border-bottom: 1px dotted currentColor;
}

/* Une commune portée par le graphique. La couleur n'est pas seule à le dire :
   le lien porte `aria-current`, et la graisse se voit en noir et blanc. */
.od-donnees__choisie th a {
    font-weight: 700;
}

.od-donnees__choisie {
    background: var(--od-quiet-hover);
}

/* Un lien au milieu d'une phrase doit se distinguer autrement que par sa
 * couleur : axe-core le signale en `link-in-text-block`, sérieux, et c'est
 * WCAG 1.4.1. Mesuré sur « Plus de statistiques » dans la note du bloc des
 * dossiers — le gris de la note et le bleu du lien ne suffisaient pas.
 *
 * Le soulignement est la réponse la moins coûteuse et la plus universelle :
 * elle tient en noir et blanc, pour un œil daltonien, et sans survol. */
.od-bloc__note a,
.od-journal a {
    text-decoration: underline;
}

/* La grille, dans un onglet de fiche : elle vit à l'intérieur du `<form>` de
   l'administration, qui a déjà ses marges, d'où la respiration en moins. */
.od-tableau--onglet {
    margin-bottom: 1rem;
}

/* --- L'aide de l'écran ------------------------------------------------------
 * Un `<details>` replié, posé sous le titre de la page.
 *
 * Le `<summary>` porte le résumé : la phrase qui dit à quoi l'écran sert est
 * donc lisible **sans ouvrir**, et c'est ce qui fait que l'aide rend service à
 * qui ne la déplie jamais.
 *
 * Le marqueur par défaut des navigateurs est un triangle minuscule, difficile
 * à viser. On le remplace par un bouton d'icône de la fonte déjà chargée —
 * `fa-circle-question` — et l'on garde `list-style: none` pour que Safari
 * n'en ajoute pas un second.
 */

/* --- La bascule de l'aide ---------------------------------------------------
 * L'aide ne s'affiche pas a l'arrivee sur un ecran : on vient y travailler,
 * pas la lire. Une icone dans la barre du haut la montre, et le bloc reste a
 * l'endroit ou il parle — sous le titre, au-dessus du contenu.
 *
 * Aucun script. La case a cocher est dans la barre, le bloc d'aide est a
 * l'autre bout du document : un selecteur de freres ne peut pas aller de
 * l'une a l'autre, et `:has()` sur l'ancetre commun le fait. C'est la seule
 * facon d'y arriver en CSS seul, et elle est tenue par tous les navigateurs
 * depuis la fin 2023.
 *
 * La case est masquee a l'oeil mais **pas au clavier** : `clip` plutot que
 * `display: none`, sinon elle sortirait de l'ordre de tabulation et de
 * l'arbre d'accessibilite, et l'aide deviendrait inaccessible autrement qu'a
 * la souris.
 */

.od-bascule-aide__case {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

.od-bascule-aide label {
    cursor: pointer;
    margin: 0;
}

/* L'etat se voit : coche, l'icone prend la couleur d'accent et le fond du
   bouton s'enfonce. Sans cela, rien ne dirait que c'est cette icone-la qui a
   fait apparaitre le bloc. */
.od-bascule-aide__case:checked + label {
    background: rgba(0, 0, 0, 0.08);
    border-radius: 0.25rem;
}

.od-bascule-aide__case:checked + label .fa-circle-question {
    color: var(--od-primary);
}

.od-bascule-aide__case:focus-visible + label {
    outline: 2px solid var(--od-primary);
    outline-offset: 2px;
}

.od-aide {
    display: none;
}

.wrapper:has(.od-bascule-aide__case:checked) .od-aide {
    display: block;
}

.od-aide {
    margin: 0 0 1rem;
    border: 1px solid var(--od-quiet-border);
    border-left: 3px solid var(--od-primary);
    border-radius: 0.3rem;
    padding: 0.6rem 0.9rem;
    background: #fff;
    font-size: 0.92rem;
}

.od-aide > summary {
    cursor: pointer;
    list-style: none;
    color: var(--od-quiet-text);
}

.od-aide > summary::-webkit-details-marker {
    display: none;
}

/* L'icône est un `<i class="fas fa-circle-question">` du gabarit, et non un
 * `content:` posé ici. Le projet n'embarque qu'une fonte **réduite**, et
 * `reduire_les_icones` décide des glyphes a garder en cherchant les classes
 * `fa-…` : un point de code écrit à la main ferait disparaître le dessin au
 * prochain passage, sans un mot. Voir `booleens.py`, qui raconte la même
 * histoire pour les cases à cocher. */
.od-aide > summary .fa-circle-question {
    margin-right: 0.35rem;
    color: var(--od-primary);
}

.od-aide > summary:focus-visible {
    outline: 2px solid var(--od-primary);
    outline-offset: 2px;
}

.od-aide ul {
    margin: 0.6rem 0 0;
    padding-left: 1.2rem;
}

.od-aide li {
    margin-bottom: 0.35rem;
}

.od-aide li:last-child {
    margin-bottom: 0;
}

/* `**gras**` n'est pas du Markdown ici : les textes d'aide sont des chaînes
   traduisibles, et y mettre du HTML les rendrait impossibles à relire. Le
   gras se fait donc à la lecture, par convention typographique dans le
   texte — ou pas du tout. */

/* --- La visite guidée -------------------------------------------------------
 * Un bandeau en tête de l'écran réel, et rien d'autre.
 *
 * Pas de calque sombre, pas de trou découpé autour d'un bouton, pas de bulle
 * positionnée en JavaScript. Les bibliothèques de visite guidée font cela, et
 * c'est précisément ce qu'on évite : elles pèsent de trente à cent
 * kilo-octets, leurs positions se décalent dès qu'une police charge en retard,
 * et surtout elles apprennent à suivre une bulle plutôt qu'à se servir du
 * logiciel.
 *
 * Le bandeau est teinté de la couleur maison et nettement séparé du contenu :
 * on doit voir d'un coup d'œil que ce texte n'est pas une partie de l'écran.
 */

.od-visite {
    margin: 0 0 1.25rem;
    border: 2px solid var(--od-primary);
    border-radius: 0.3rem;
    padding: 0.9rem 1.1rem;
    background: #f4fbfb;
}

.od-visite__rang {
    margin: 0 0 0.2rem;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #0b625f;   /* 6,38:1 sur #f4fbfb */
}

.od-visite__titre {
    margin: 0 0 0.4rem;
    font-size: 1.1rem;
    font-weight: 600;
}

.od-visite p {
    margin: 0 0 0.5rem;
}

.od-visite__essayez {
    font-style: italic;
    color: #41525c;   /* 7,54:1 sur #f4fbfb */
}

.od-visite__liens {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    align-items: baseline;
    margin: 0.75rem 0 0;
}

/* Le lien qui fait avancer est le seul en plein : les autres sont des
   recours. Et il ne se distingue pas que par la couleur — il est en gras, et
   son libellé le dit. */
.od-visite__suivant {
    font-weight: 600;
}

/* « Quitter » est poussé à droite : c'est une sortie, pas une alternative au
   parcours. */
.od-visite__quitter {
    margin-left: auto;
}

/* Les liens d'un bandeau de texte doivent se distinguer autrement que par la
   couleur — axe-core le signale en `link-in-text-block`, et c'est WCAG 1.4.1.
   La leçon a déjà coûté une passe sur « Plus de statistiques ». */
.od-visite a {
    text-decoration: underline;
}


/* --- Les pages d'erreur -----------------------------------------------------
 * Le numéro est affiché — il sert à en parler au support — mais il ne porte
 * pas le sens : c'est le titre qui le dit. Il est donc discret, au-dessus de
 * l'explication, et non en gros chiffres au milieu de la page.
 */

.od-erreur__code {
    margin: 0 0 0.5rem;
    font-size: 0.86rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #595f66;   /* 6,21:1 sur blanc */
}

.od-erreur p:last-child {
    margin-bottom: 0;
}


/* --- Deux manquements que le balayage axe-core a trouvés le 10 octobre 2026
 * -----------------------------------------------------------------------------
 *
 * Les deux viennent d'un gabarit que nous ne tenons pas — Django pour le
 * premier, jazzmin pour le second — et les deux se corrigent une fois pour
 * tous les écrans concernés, pas page par page.
 */

/* « Date : » et « Heure : » d'un champ composé sont désormais des `<label for>`
   — voir `admin/widgets/split_datetime.html`. Un intitulé reçoit de
   l'habillage une marge basse d'une demi-ligne et une graisse de titre : les
   deux déplaceraient la saisie et changeraient le dessin d'un écran qu'on ne
   corrige que pour son accessibilité. Ici l'intitulé reste le mot qu'il était.

   **Le sélecteur est long pour une raison mesurée.** La règle de l'habillage
   est `label:not(.form-check-label):not(.custom-file-label)`, dont la
   spécificité est (0,2,1) : un `:not` compte celle de son argument. Écrit
   `.datetime .od-sous-etiquette`, soit (0,2,0), le `font-weight` ne passait
   pas, et les deux mots se retrouvaient en gras — relevé à 700 là où le
   paragraphe est à 400, c'est-à-dire exactement le changement de dessin que
   l'on refusait. */
p.datetime label.od-sous-etiquette {
    display: inline;
    margin: 0;
    font-weight: inherit;
}

/* Sur les pages de confirmation de suppression, le lien vers l'objet à
   détruire se distingue du texte qui l'entoure par la seule couleur —
   `link-in-text-block`, sérieux, et c'est WCAG 1.4.1. Même règle que pour la
   visite guidée, quelques lignes plus haut.

   **Et le défaut est dans toutes ces pages, pas dans les trois que le
   balayage signale** : axe ne lève la règle que là où l'étiquette devant le
   lien est assez longue pour qu'il traite la ligne comme un bloc de texte.
   Mesuré : `<li>Boîtier : <a>…` passe, `<li>Type de photographie : <a>…` non,
   pour un balisage identique. D'où un sélecteur qui les prend toutes, y
   compris la liste imbriquée des objets liés et la page de suppression
   groupée, qui porte la même classe de `<body>`. */
.delete-confirmation #content-main ol a {
    text-decoration: underline;
}


/* --- Les listes déroulantes de filtre, sans select2 ------------------------
 *
 * `jazzmin/js/change_list.js` n'habille plus les filtres de liste ni la liste
 * d'actions : voir la surcharge dans `webfront/static/jazzmin/js/`. Ce sont
 * donc des `<select>` natifs, et c'est ici qu'ils prennent la forme des
 * autres contrôles de la barre — même hauteur, même bordure, même rayon,
 * puisque `.form-control` les porte déjà.
 *
 * **Il ne reste que la flèche.** `appearance: none` retire celle du système,
 * et le chevron est une image de fond en `data:` — comme les douze masques
 * d'icône du projet : zéro requête, zéro élément de DOM. C'est tout l'intérêt
 * de l'opération, qui a rendu de sept à quarante-deux éléments par page.
 *
 * **Ce que cette règle ne peut pas faire, et qu'il faut savoir.** Elle habille
 * le contrôle *fermé*. La liste *ouverte* est dessinée par le système
 * d'exploitation et n'est pas stylable — c'est le prix du contrôle natif, et
 * c'est aussi ce qui le rend bon au clavier, sur mobile, et nommé sans qu'un
 * script ait à le rattraper.
 */
select.search-filter,
.actions select {
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%2016%2016%22%3E%3Cpath%20fill=%22%236c757d%22%20d=%22M1.646%204.646a.5.5%200%200%201%20.708%200L8%2010.293l5.646-5.647a.5.5%200%200%201%20.708.708l-6%206a.5.5%200%200%201-.708%200l-6-6a.5.5%200%200%201%200-.708z%22/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.6rem center;
    background-size: 0.7rem auto;
    padding-right: 2rem;
}

/* La largeur. select2 recopiait la largeur intrinsèque du `<select>` dans un
   style en ligne ; sans lui, un `width: 100%` dans une `.form-inline` se
   résout sur un conteneur qui n'a pas de largeur propre et le contrôle se
   réduit à sa flèche. Un plancher, et il grandit avec son contenu. */
select.search-filter {
    min-width: 12rem;
    width: auto;
}

.actions select {
    min-width: 16rem;
}

/* --- Le filtre d'autocomplétion, à la même hauteur que ses voisins ---------
 *
 * Il est le seul de la barre à garder select2 — il cherche parmi une
 * soixantaine d'installateurs, et une saisie lui est utile là où un `<select>`
 * de six options n'en a pas besoin. Mais select2 dessine sa boîte à 28 px,
 * quand `.form-control` en fait 38 : à côté des `<select>` natifs redevenus
 * ordinaires, il paraissait rabougri et d'une autre famille.
 *
 * On lui donne donc les métriques de `.form-control`, et rien d'autre : même
 * hauteur, même bordure, même rayon, même alignement du texte. Le sélecteur
 * reprend celui de select2, qui compte trois classes — il en faut autant pour
 * passer devant.
 */
.od-filtres .select2-container--default .select2-selection--single,
#changelist-search .select2-container--default .select2-selection--single,
.od-periode .select2-container--default .select2-selection--single {
    height: calc(2.25rem + 2px);
    border: 1px solid #ced4da;
    border-radius: 0.25rem;
}

.od-filtres .select2-container--default .select2-selection--single
.select2-selection__rendered,
#changelist-search .select2-container--default .select2-selection--single
.select2-selection__rendered,
.od-periode .select2-container--default .select2-selection--single
.select2-selection__rendered {
    line-height: calc(2.25rem);
    padding-left: 0.75rem;
    /* select2 rend son texte à 14 px quand `.form-control` est à 16 : côte à
       côte dans la même barre, les deux ne se lisaient pas pareil. */
    font-size: 1rem;
}

.od-filtres .select2-container--default .select2-selection--single
.select2-selection__arrow,
#changelist-search .select2-container--default .select2-selection--single
.select2-selection__arrow,
.od-periode .select2-container--default .select2-selection--single
.select2-selection__arrow {
    height: calc(2.25rem);
}

/* --- La pastille d'état portée par la cellule ------------------------------
 *
 * Sur la liste des dossiers, les trois colonnes d'état rendaient un `<span>`
 * dans leur `<td>`, uniquement pour y accrocher des classes. Trois éléments
 * par ligne, **trente par page**, sur l'écran que le mandataire ouvre dix
 * fois par jour. Le `<span>` est parti, les classes sont sur la cellule :
 * voir `backoffice/templatetags/od_listes.py`.
 *
 * **Le dessin change, et c'est le seul point à regarder.** Un `<td>` ne peut
 * pas porter une pastille : son fond remplit la cellule entière, et trois
 * bandes de couleur pleine par ligne noieraient le tableau. L'état devient
 * donc un **libellé en couleur avec son pictogramme**, au lieu d'une étiquette
 * blanche sur fond de couleur.
 *
 * Les quatre teintes sont inchangées, et elles tiennent le critère dans leur
 * nouveau rôle : elles avaient été choisies pour leur contraste **sur blanc**
 * — c'est exactement ce qu'il faut à du texte. Recalculé sur les deux fonds
 * alternés du tableau, le plus serré étant « obtenu » sur les lignes grises :
 *
 *     teinte          sur #ffffff   sur #f2f2f2
 *     obtenu             5,08:1        4,54:1
 *     reçu / envoyé      5,84:1        5,22:1
 *     demandé            6,39:1        5,71:1
 *     absent             6,57:1        5,87:1
 *
 * `test_accessibilite.py` les recalcule depuis la feuille : retoucher une
 * teinte ou le gris des lignes fera tomber le test, pas passer inaperçu.
 *
 * Et la couleur n'est toujours pas seule à porter l'information : le
 * pictogramme reste — il hérite de `currentColor` — et le libellé est écrit.
 */
td.od-etat {
    display: table-cell;
    background: none;
    border-radius: 0;
    font-weight: 600;
    white-space: nowrap;
}

td.od-etat--obtenu  { color: #1a7f37; }
td.od-etat--recu,
td.od-etat--envoye  { color: #0b5ed7; }
td.od-etat--demande { color: #8a5200; }
td.od-etat--absent  { color: #b42318; }

/* « Sans objet » reste une absence de démarche, donc sans graisse. */
td.od-etat--sans-objet {
    color: #595f66;
    font-weight: 400;
}
