/*
=========================
WB 2.0 — Sidebar de migration + coquille de page (?page=slug)
=========================
Sidebar verticale neuve, en flux, à gauche du contenu. Coexiste volontairement
avec le menu horizontal legacy (position:fixed) le temps de la migration
(« présentation bâtarde »). Palette alignée sur le vert #4CAF50 du site.
*/

/* Pages WB 2.0 : reset du fond dark legacy webbike.css */
body.wb-modern {
    background-color: var(--bs-body-bg) !important;
    color: var(--bs-body-color) !important;
    margin: 0 !important;
}

/* ⛔ LES RÈGLES DE `#menu` SONT PARTIES LE 12.09.2026, AVEC LE MENU LEGACY.
   Elles étaient six, et chacune payait un défaut de la barre flottante : le
   calage à droite, la descente sous les trois barres du chrome, le masquage par
   défaut sur les écrans WB 2.0, sa bascule, et la reprise à 992 px. Un sélecteur
   sans porteur se relit comme un composant encore là — c'est la leçon de
   `.wb-sidebar`, retirée d'ici le 01.09.2026 avec un jour de retard. */

/* ⛔ `.wb-shell` ET `.wb-main` SONT PASSÉS DANS `css/registre.css` LE
   01.09.2026, avec le chrome horizontal : la coquille n'empile plus une colonne
   et un contenu côte à côte, elle empile trois barres puis le contenu.
   ⚠️ ET L'OFFSET DE 32 PX A DISPARU AVEC SA CAUSE : il compensait une barre
   fixe qui recouvrait le haut du contenu. Les trois barres sont dans le flux —
   elles prennent leur place au lieu de la voler. */

/* ===== Barre de page : fil d'Ariane, titre, onglets de sous-section =====
   L'en-tête de page était masqué globalement, au motif que la sidebar indique
   déjà la page active. Elle dit OÙ l'on est ; un titre dit CE QU'ON PEUT Y
   FAIRE — et il porte les actions de la page, que trente pages sur quarante et
   une déclaraient déjà avant d'être cachées. */
.wb-pagebar {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: 0.9rem;
}

/* Le fil d'Ariane et le « ? » de la page partagent une ligne : .wb-pagebar
   empile ses enfants, et deux rangées auraient poussé le titre d'un cran vers
   le bas sur chaque écran. */
.wb-pagebar-haut {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Le « ? » de l'écran — rendu par App\PageBar depuis le catalogue d'aide, jamais
   écrit dans l'écran. Discret par défaut : c'est un recours, pas une action. */
.wb-pagebar-aide {
    margin-left: auto;
    color: var(--bs-secondary-color, #6c757d);
    line-height: 1;
    text-decoration: none;
}
/* Dans la ligne du titre, il suit les actions : `me-auto` du titre les range déjà à droite. */
.wb-page-header > .wb-pagebar-aide { margin-left: .25rem; }
.wb-pagebar-aide:hover,
.wb-pagebar-aide:focus-visible { color: var(--bs-body-color); }

/* Fil d'Ariane. Le groupe n'est pas cliquable : un groupe est un rangement,
   pas une destination — le rendre cliquable promettrait une page inexistante. */
.wb-fil {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 12px;
    letter-spacing: 0.02em;
    color: var(--bs-secondary-color, #6c757d);
    min-height: 1.1rem;
}
.wb-fil .bi {
    font-size: 0.6rem;
    opacity: 0.55;
}
.wb-fil-groupe { font-weight: 600; }
.wb-fil-ici { color: var(--bs-body-color); }

/* L'en-tête déclaré par les pages : `d-flex align-items-center mb-3`, avec
   `me-auto` sur le h1 — les actions se rangent donc à droite d'elles-mêmes.
   `margin-bottom` neutralisé : l'espacement est porté par .wb-pagebar. */
.wb-page-header { margin-bottom: 0 !important; }

/* Onglets de sous-section — remplacent la 2e sidebar de 210 px. */
.wb-onglets {
    display: flex;
    gap: 0.15rem;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--bs-border-color, #dee2e6);
    margin-top: 0.25rem;
}
.wb-onglet {
    padding: 0.4rem 0.75rem 0.5rem;
    font-size: 0.87rem;
    color: var(--bs-secondary-color, #6c757d);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;   /* le filet actif recouvre celui du conteneur */
    white-space: nowrap;
}
.wb-onglet:hover { color: var(--bs-body-color); }
/* ⚠️ LA COULEUR DU FILET ACTIF N'EST PLUS ÉCRITE ICI (14.09.2026, décision du
   mandant) : la charte la pose en ROUGE (`css/registre.css`, § des onglets),
   comme la sous-navigation. Ce fichier garde la GÉOMÉTRIE — le filet de 2 px et
   son recouvrement —, la charte dit l'encre. Et le focus n'a plus de règle du
   tout : celui de la charte (`:focus-visible { outline: 1px solid var(--ink) }`)
   est celui de tous les autres contrôles du produit, sans coin arrondi. */
.wb-onglet.actif {
    color: var(--bs-body-color);
    font-weight: 600;
}
/* --- Première visite : la bulle qui présente la recherche, UNE fois ---
   Un champ, même bien dessiné, ne dit pas TOUT ce qu'il accepte. Cette bulle le
   dit une fois, puis ne revient jamais (localStorage). */
.wb-search-coach {
    position: absolute;
    z-index: 1080;
    max-width: 17rem;
    padding: 0.6rem 0.75rem;
    border-radius: 0.5rem;
    background: var(--bs-emphasis-color);
    color: var(--bs-body-bg);
    font-size: 0.8125rem;
    line-height: 1.35;
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.25);
}

.wb-search-coach::before {
    content: "";
    position: absolute;
    top: 0.9rem;
    left: -0.35rem;
    width: 0.7rem;
    height: 0.7rem;
    background: inherit;
    transform: rotate(45deg);
}

.wb-search-coach button {
    margin-top: 0.4rem;
    border: 0;
    background: transparent;
    color: inherit;
    font-weight: 600;
    font-size: 0.8125rem;
    padding: 0;
    text-decoration: underline;
    cursor: pointer;
}

/* --- Exemples affichés dans la palette tant que rien n'est tapé --- */
.wb-palette-exemples {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--bs-border-color);
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.wb-palette-exemples code {
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    padding: 0.05rem 0.3rem;
}

/* ===== Touches de clavier — une seule apparence pour toute l'application =====
   ⚠️ POURQUOI CETTE CLASSE EXISTE. Bootstrap habille `<kbd>` en INVERSE du
   corps : `background-color: var(--bs-body-color)` (donc presque noir en thème
   clair) et `color: var(--bs-body-bg)`. C'est lisible tel quel — mais y ajouter
   une classe utilitaire de couleur (`text-body-secondary`, par exemple) ne
   remplace QUE le texte : on obtient du gris sur du noir, et la touche devient
   un rectangle illisible. C'est ce qu'on voyait sur la touche « Échap » de la
   palette.
   `.wb-kbd` pose les deux couleurs ensemble, dans le sens du corps de page :
   elles ne peuvent plus se contredire. */
.wb-kbd {
    display: inline-block;
    font-size: 12px;
    line-height: 1.2;
    padding: 0.15rem 0.35rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.25rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
}

/* ===== Badges d'aide clavier (js/hints.js) =====
   Discret par construction : c'est un indice, pas une décoration. Il doit se
   lire quand on le cherche et s'oublier quand on ne le cherche pas — d'où
   l'opacité réduite, qui remonte au survol de l'élément porteur. */
.wb-hint {
    /* Même apparence que `.wb-kbd`, en plus discret : c'est un indice, pas une
       décoration. Il doit se lire quand on le cherche et s'oublier sinon. */
    flex-shrink: 0;
    display: inline-block;
    font-size: 12px;
    line-height: 1.1;
    padding: 0.1rem 0.28rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.2rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-secondary-color);
    opacity: 0.72;
    transition: opacity 0.12s ease;
}

*:hover > .wb-hint,
*:focus-visible > .wb-hint { opacity: 1; }/* Dans le volet, les libellés reviennent : ils sont masqués globalement en rail
   par la règle `.wb-label { display: none !important }/* La 2e sidebar contextuelle (.wb-subnav, 210 px) a été retirée : les
   sous-sections d'une parente subNav sont désormais une rangée d'onglets sous
   le titre de page (.wb-onglets plus bas, cf. app/PageBar.php). Avec elle
   disparaît le repli automatique en rail de la bande 768–1199 px, qui n'existait
   que pour lui rendre de la largeur. */

/* --- Page moderne (layout.php) --- */

.wb-card {
    display: flex;
    flex-direction: column;
    /* ⚠️ La carte REMPLIT sa cellule, elle ne se dimensionne plus elle-même :
       c'est ce qui aligne les bas de cartes d'une même rangée. */
    height: 100%;
    min-height: 0;
    /* ⚠️ Variables Bootstrap et non couleurs en dur : les cartes étaient
       #ffffff sur #e0e0e0 avec du texte #2c3e50 — donc BLANCHES en thème
       sombre, avec du texte foncé sur fond clair au milieu d'une page sombre.
       Le thème sombre existe depuis longtemps ; ces quatre valeurs étaient les
       seules à ne pas le suivre. */
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
    padding: 18px;
}

.wb-card-title {
    font-size: 1.05rem;
    color: var(--bs-emphasis-color);
    margin: 0 0 8px;
}

.wb-card-text {
    font-size: 0.9rem;
    color: var(--bs-secondary-color);
    line-height: 1.45;
    margin: 0;
}

.wb-card-text code {
    background: var(--bs-tertiary-bg);
    padding: 1px 5px;
    color: var(--bs-body-color);
    font-size: 0.85em;
}

/* ⛔ CE BLOC A RETOURNÉ LA COQUILLE SUR TÉLÉPHONE, ET C'ÉTAIT L'ERREUR.
   Il posait `flex-direction: column` sur `.wb-shell` et rendait la sidebar
   pleine largeur (`width: 100%`) et NON POSITIONNÉE (`position: static`). Trois
   conséquences, toutes visibles :

     1. le menu passait AVANT le contenu, sur toute la largeur : deux à trois
        écrans de navigation à faire défiler avant la première ligne utile ;
     2. `position: static` annule le `z-index` — un élément non positionné n'en
        a pas. Le `z-index: 1035` de la sidebar (cf. son bloc plus haut, et
        SidebarEmpilementTest) tombait donc avec lui, et avec le contexte
        d'empilement qu'il créait : volets de groupe et menu du profil
        repassaient sous les cartes de la page, à moitié recouverts ;
     3. la sidebar perdait sa hauteur (`min-height: 0`), donc son fond : là où
        elle ne portait plus rien, on lisait la page au travers.

   La sidebar reste donc, sur téléphone, la colonne de gauche qu'elle est
   partout ailleurs — en version ÉTROITE, forcée à l'ouverture de `.wb-shell`
   (cf. `index.php`). Les règles de largeur sont plus bas, après les profils
   d'écran par poste : elles doivent gagner contre eux. */
@media (max-width: 768px) {

    .wb-card { height: auto; }
}

/* ===== Tabulator WB 2.0 — densité et scroll ===== */
.tabulator {
    font-size: 0.8rem;
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
    padding: 4px 6px;
}
.tabulator .tabulator-tableholder .tabulator-table .tabulator-row .tabulator-cell {
    padding: 3px 6px;
}
.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input {
    font-size: 0.75rem;
    padding: 1px 4px;
    height: auto;
}

/* ===== Tabulator WB 2.0 — habillage visuel (tokens + composants réutilisables) =====
   Ce bloc s'applique à TOUS les tableaux du socle Datatable (véhicules, articles,
   commandes, location...), pas seulement à un dataset en particulier. Les sélecteurs
   restent chaînés/spécifiques pour continuer à gagner sur tabulator_bootstrap5.min.css
   et Bootstrap sans recourir à !important (cf. bloc densité ci-dessus). */
:root {
    --wb-dt-border: #dee1e4;
    --wb-dt-border-strong: #c7cbcf;
    --wb-dt-surface: #ffffff;
    --wb-dt-surface-alt: #f4f6f7;
    --wb-dt-text: #262a2d;
    --wb-dt-text-muted: #6b7176;
    --wb-dt-accent: #2a5f8f;
    --wb-dt-accent-soft: #e7f0f7;
    /* ⚠️ LE SEUL JETON SÉMANTIQUE QUI RESTE (09.09.2026). Ses sept voisins
       (--wb-dt-ok/-soft, --wb-dt-warn-soft, --wb-dt-info/-soft, --wb-dt-alt/-soft)
       n'alimentaient que les pastilles des grilles, devenues des mots réglés
       dans un filet (`.et`, css/registre.css) : un jeton que plus personne ne lit
       est une couleur qui attend de revenir. Celui-ci est lu par la relance GED
       (`.wb-ged-relance`), où le trait de couleur EST l'information. */
    --wb-dt-warn: #b6690a;
}

.tabulator.tabulator {
    border: 1px solid var(--wb-dt-border);
    border-radius: 8px;
    background: var(--wb-dt-surface);
    color: var(--wb-dt-text);
}
.tabulator .tabulator-header {
    background: var(--wb-dt-surface-alt);
    border-bottom: 1px solid var(--wb-dt-border);
}
.tabulator .tabulator-header .tabulator-col {
    background: transparent;
    /* box-shadow plutôt que border : un vrai border-right modifierait la largeur
       de la boîte si box-sizing n'est pas garanti border-box à cet endroit précis
       (Tabulator calcule et synchronise les largeurs header/corps en px inline) —
       box-shadow est purement visuel, ne participe jamais au layout. */
    box-shadow: inset -1px 0 0 var(--wb-dt-border);
}
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--wb-dt-text-muted);
}
.tabulator .tabulator-tableholder .tabulator-table .tabulator-row {
    border-bottom: 1px solid var(--wb-dt-border);
    background: var(--wb-dt-surface);
}
.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-row-even {
    background: var(--wb-dt-surface);
}
.tabulator .tabulator-tableholder .tabulator-table .tabulator-row:hover {
    background: var(--wb-dt-surface-alt);
}

/* ⭐ LIGNE OUVRABLE (`rowOpen`, 04.09.2026) — la ligne entière mène à sa fiche.
   Le curseur le dit avant le clic ; le liseré de focus le dit au clavier, qui
   atteint la ligne par Tab et l'ouvre par Entrée. Ni fond coloré ni pastille :
   la charte « Le Registre » se tient au trait. */
.tabulator .tabulator-row.wb-dt-ligne-ouvrable {
    cursor: pointer;
}

/* ⭐ … SAUF SUR LA CELLULE QUI SE MODIFIE (16.09.2026, lot EH). Depuis que TOUTE
   grille à fiche s'ouvre au clic — éditables comprises —, la ligne porte la main
   d'un bout à l'autre ; mais dans une cellule `.tabulator-editable`, le clic ne
   mène pas à la fiche, il ouvre l'éditeur. Le doigt ne promet que ce que le clic
   fait : le curseur y redevient celui d'une saisie.
   ⚠️ TABULATOR NE POSE CETTE CLASSE QUE LÀ OÙ LA COLONNE A UN `editor` — donc
   jamais pour qui n'a pas le droit d'écrire, dont la ligne s'ouvre partout.
   Aucune couleur : la charte se tient au trait. */
.tabulator .tabulator-row.wb-dt-ligne-ouvrable .tabulator-cell.tabulator-editable {
    cursor: text;
}

/* La ligne dont le volet parle (charte A2 : fond d'accent, filet à gauche).
   Ce n'est pas le curseur, qui se dit par le liseré de focus ci-dessous. */
.tabulator .tabulator-row.wb-dt-ligne-active,
.tabulator .tabulator-row.wb-dt-ligne-active .tabulator-cell {
    background: var(--acc-w);
}
.tabulator .tabulator-row.wb-dt-ligne-active .tabulator-cell:first-child {
    box-shadow: inset 3px 0 0 var(--acc);
}

/* ⚠️ LE LISERÉ DE FOCUS VAUT POUR TOUTE LIGNE ATTEINTE AU CLAVIER, ouvrable ou
   non (16.09.2026, lot EA) : depuis que les flèches descendent TOUTES les
   grilles — y compris celles qui n'ouvrent rien, comme le rapport occasions —,
   une règle réservée à `.wb-dt-ligne-ouvrable` laissait le clavier sans repère
   visible sur les autres. Une seule règle, un sélecteur plus large. */
.tabulator .tabulator-row:focus-visible {
    /* ⚠️ LE REPLI EST `currentColor`, PAS UN HEXA : la charte veut ses jetons
       et jamais une couleur en dur — mais un `var()` sans repli qui ne résout
       pas laisse la ligne SANS liseré de focus, c'est-à-dire un clavier qui ne
       sait plus où il est. */
    outline: none;
}
/* Le liseré est un calque posé sur la ligne : en `outline`, les cellules figées
   (collantes, opaques) le recouvraient et il s'interrompait sous elles. */
.tabulator .tabulator-row:focus-visible::after {
    content: '';
    position: absolute;
    inset: 0;
    border: 2px solid var(--actif, currentColor);
    pointer-events: none;
    z-index: 12;
}

/* Lien de cellule vers une VRAIE page (`pageLink`) : il se distingue de
   l'aperçu (`.wb-entity-link`) par le seul fait qu'il porte une adresse — rien
   ne le souligne différemment, deux liens de même nature ont la même apparence
   (règle ⭐ 6). */
.tabulator .tabulator-row .wb-dt-lien-page {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Boutons d'action de ligne (__actions) : discrets, apparaissent au survol */
.tabulator .tabulator-row .wb-dt-actions-cell {
    /* inline-flex, pas flex : cette cellule reste un .tabulator-cell positionné
       dans le flux de la ligne (inline-block) — display:flex la rendrait "block"
       et casserait l'alignement de toutes les colonnes suivantes. */
    display: inline-flex;
    gap: 4px;
    opacity: 0.45;
    transition: opacity 0.1s ease;
}
.tabulator .tabulator-row:hover .wb-dt-actions-cell {
    opacity: 1;
}
.tabulator .tabulator-row .wb-dt-actions-cell .btn {
    width: 26px;
    height: 26px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
}

/* ── Barre de critères ──────────────────────────────────────────────────────
   Les critères actifs, énoncés en toutes lettres au-dessus de la grille. Elle
   existe parce qu'un critère posé sur une colonne MASQUÉE était invisible : la
   grille se restreignait sans que rien ne dise pourquoi. */
.wb-dt-criteres {
    border: 1px solid var(--wb-dt-border);
    border-radius: 8px;
    background: var(--wb-dt-surface-alt);
    padding: 8px 10px;
    margin-bottom: 8px;
}
.wb-dt-criteres-puces {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 8px;
}
.wb-dt-criteres-ajout {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding-top: 8px;
    border-top: 1px solid var(--wb-dt-border);
}
.wb-dt-critere {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--wb-dt-surface);
    border: 1px solid var(--wb-dt-border);
    border-radius: 14px;
    padding: 3px 6px 3px 10px;
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--wb-dt-text);
}
.wb-dt-critere strong { font-weight: 600; }
.wb-dt-critere-x {
    appearance: none;
    border: none;
    background: transparent;
    color: var(--wb-dt-text-muted);
    font-size: 0.85rem;
    line-height: 1;
    padding: 2px 4px;
    border-radius: 50%;
    cursor: pointer;
}
.wb-dt-critere-x:hover { background: var(--wb-dt-danger-soft, #f8d7da); color: #58151c; }

/* Bandeau d'onglets de portée (scopeTabs), au-dessus de la grille */
.wb-dt-scope-tabs {
    display: inline-flex;
    background: var(--wb-dt-surface-alt);
    border: 1px solid var(--wb-dt-border);
    border-radius: 8px;
    padding: 3px;
    gap: 2px;
    margin-bottom: 8px;
}
.wb-dt-scope-tabs button {
    appearance: none;
    border: none;
    background: transparent;
    color: var(--wb-dt-text-muted);
    font-size: 0.78rem;
    font-weight: 600;
    padding: 5px 11px;
    border-radius: 6px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.wb-dt-scope-tabs button.wb-dt-scope-active {
    background: var(--wb-dt-surface);
    color: var(--wb-dt-text);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

/* Compteur inscrit dans chaque onglet (« Parc location (350) »). Rempli par
   datatable.js depuis l'API des facettes : un onglet vide s'explique alors
   de lui-même, au lieu de laisser croire que l'écran est cassé. */
.wb-dt-scope-tabs .wb-dt-scope-count {
    font-weight: 500;
    opacity: 0.7;
    font-variant-numeric: tabular-nums;
}
/* Un onglet à zéro se voit AVANT le clic — on ne fait pas partir quelqu'un en
   exploration pour lui montrer une grille vide. Estompé, jamais masqué : la
   portée existe, elle est simplement sans contenu aujourd'hui. */
.wb-dt-scope-tabs button.wb-dt-scope-vide {
    opacity: 0.5;
}
.wb-dt-scope-tabs button.wb-dt-scope-vide.wb-dt-scope-active {
    opacity: 1;
}

/* ===== Dialogues : socle commun aux modales et aux tiroirs =====
   Le comportement (focus, Entrée, empilement) est dans js/dialog.js ; ici,
   ce qui se voit. */

/* Pied de tiroir. `.offcanvas-footer` N'EXISTE PAS dans Bootstrap : c'est une
   classe maison que trois gabarits utilisaient sans qu'aucune règle ne la
   définisse. Les boutons d'action suivaient donc le contenu et partaient sous la
   ligne de flottaison dès que la fiche était longue — il fallait dérouler tout
   le tiroir pour trouver « Enregistrer ». */
.offcanvas-footer {
    flex: 0 0 auto;
    margin-top: auto;
    background: var(--bs-body-bg);
    position: sticky;
    bottom: 0;
    z-index: 2;
}

/* Le corps prend la place restante et défile seul, pour que l'en-tête et le pied
   restent en place. */
.offcanvas-body { flex: 1 1 auto; min-height: 0; }

/* ══ LARGEUR DES TIROIRS ═════════════════════════════════════════════════════
   28rem, celle des aperçus à une colonne. En dessous de 576 px de viewport, le
   tiroir prend tout l'écran : en laisser une bande de fond inutilisable sur un
   téléphone n'aide personne.

   ⛔ ON RÈGLE `--bs-offcanvas-width`, ET SURTOUT PAS `width`. C'est LA leçon de
   ce coin du fichier, et elle a été payée trois fois.

   Bootstrap 5.3.3 écrit `.offcanvas.offcanvas-end { width: var(--bs-offcanvas-width) }`
   — DEUX classes, donc la spécificité EXACTE de nos sélecteurs — et
   `index.php` le charge (l. 315) APRÈS `css/app.css` (l. 303). À spécificité
   égale, le dernier arrivé gagne : **toute déclaration `width` écrite ici est
   morte**, silencieusement. La variable, elle, est posée par Bootstrap sur
   `.offcanvas` SEUL (une classe) : la surcharger depuis deux classes gagne par
   spécificité, quel que soit l'ordre de chargement.

   ⛔ ET C'EST EXACTEMENT CE QUI S'EST PASSÉ. `webbike.css:697` portait
   `.wb-drawer-wide { width: 720px }` ; cette feuille étant chargée (l. 404)
   APRÈS Bootstrap, c'était la SEULE qui pouvait gagner. En la retirant le
   15.08.2026 « au profit de la définition unique d'app.css », on a fait retomber
   tous les tiroirs à la valeur par défaut de Bootstrap — **400 px** — pendant
   que le commentaire d'ici annonçait 45rem. Trois valeurs successives ont ainsi
   été écrites, lues et commentées sans jamais s'appliquer : 38rem, 45rem, 90rem.
   Signalé par le mandant le 18.08.2026, capture à l'appui : « le drawer est
   toujours trop étroit, le fix ne fonctionne pas ». Mesuré au navigateur avant
   correction : 400 px à 1366, 1512 ET 1920 px de viewport.

   ⚠️ LE TIROIR LARGE (`.wb-drawer-wide`) EST PARTI LE 01.10.2026 : plus aucune
   fiche ne s'ouvre en tiroir (CLAUDE.md, règle 5), aucune page ne la posait. */
.offcanvas.offcanvas-end,
.offcanvas.offcanvas-start { --bs-offcanvas-width: min(28rem, 100vw); }
@media (max-width: 575.98px) {
    .offcanvas.offcanvas-end,
    .offcanvas.offcanvas-start { --bs-offcanvas-width: 100vw; }
}

/* Modale haute : le corps défile, l'en-tête et le pied restent visibles. Sans
   ça, les boutons d'un long formulaire sortent de l'écran. */
.modal-dialog { max-height: calc(100vh - 3.5rem); }
.modal-content { max-height: inherit; }
.modal-body    { overflow-y: auto; }

/* Le focus doit se VOIR dans un dialogue : on y arrive au clavier, souvent sans
   avoir touché la souris.
   ⚠️ IL N'EST PLUS REDESSINÉ ICI (14.09.2026, décision du mandant) : la règle
   posait l'anneau bleu de Bootstrap, seule couleur non chartée d'un dialogue,
   et l'en-tête coloré qui la justifiait n'existe plus depuis la charte. Le trait
   d'encre de `css/registre.css` s'applique dans un dialogue comme ailleurs. */

@media (prefers-reduced-motion: reduce) {
    .modal.fade .modal-dialog,
    .offcanvas { transition: none !important; }
}

/* ----- Présentation des champs, commune à tous les dialogues -----
   Les 14 dialogues à formulaire habillaient leurs champs chacun à sa façon :
   étiquettes tantôt `fw-medium`, tantôt nues, espacements de 2 à 4 crans. */
.modal .form-label,
.offcanvas .form-label {
    font-size: 0.8rem;
    font-weight: 600;
    margin-bottom: 0.2rem;
    color: var(--bs-secondary-color, #6c757d);
}

/* Champ obligatoire : marqué une fois, au même endroit, partout. Le titre porte
   le mot en clair — un astérisque seul n'est compris que de qui connaît déjà la
   convention. */
.modal .form-label.wb-requis::after,
.offcanvas .form-label.wb-requis::after {
    content: "*";
    color: var(--bs-danger, #dc3545);
    margin-left: 0.2rem;
    font-weight: 700;
}

/* Sections d'un formulaire long : le tiroir location en compte cinq. */
.modal fieldset,
.offcanvas fieldset { margin-bottom: 1.1rem; border: 0; }
.wb-legend {
    font-size: 0.82rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--bs-primary, #0d6efd);
    border-bottom: 1px solid var(--bs-border-color, #dee2e6);
    padding-bottom: 0.25rem;
    margin-bottom: 0.7rem;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
    float: none;   /* <legend> flotte par défaut dans certains UA */
}

/* Aide sous un champ : ton et taille identiques partout. */
.modal .form-text,
.offcanvas .form-text { font-size: 0.75rem; }

/* Pied de dialogue : le DESTRUCTIF est repoussé à gauche par `me-auto`, loin du
   bouton principal, pour qu'un clic qui rate ne détruise rien. L'ordre de
   lecture — et donc de tabulation — devient : destructif · annuler · principal.
   Il variait d'un dialogue à l'autre, y compris l'inverse. */
.modal-footer .wb-destructif,
.offcanvas-footer .wb-destructif { margin-right: auto; }

/* Sur écran étroit, les boutons passent en colonne pleine largeur plutôt que de
   se tasser à trois par ligne. */
@media (max-width: 400px) {
    .modal-footer, .offcanvas-footer { flex-direction: column-reverse; align-items: stretch; }
    .modal-footer .wb-destructif,
    .offcanvas-footer .wb-destructif { margin-right: 0; margin-top: 0.25rem; }
}

/* ----- Titre de dialogue : une icône, toujours au même endroit -----
   Le tiroir livraisons ouvre sur « 🚚 Modifier la livraison » ; six autres
   ouvrent sur un titre nu (« Détail », « Aperçu », « Actions », « Revue de la
   paire »). Sur un poste où trois tiroirs s'enchaînent, l'icône est ce qui dit
   de quoi on parle AVANT d'avoir lu. */
.modal-title > i.bi,
.offcanvas-title > i.bi {
    margin-right: 0.5rem;
    color: var(--bs-primary, #0d6efd);
}

/* ===== Calendriers : le repère temporel, commun aux trois vues =====
   Comportement dans js/calendrier-passe.js ; ici, ce qui se voit.

   ⛔ CE QUI A ÉTÉ DEMANDÉ, ET POURQUOI CE N'EST PAS CE QUI EST FAIT.
   La demande (15.08.2026) était de GRISER les jours passés. Mesuré sur la vue
   Mois des livraisons au 15.08.2026 : 19 cellules sur 42 sont passées (45 %), et
   les six livraisons affichées — 28.07, 3, 4, 5, 6.08 — sont TOUTES dans le
   passé. La règle telle que formulée aurait donc grisé la totalité de ce qui
   porte du contenu : un signal qui couvre la moitié de la surface n'est plus un
   signal, et une livraison passée n'est pas une donnée morte — c'est la trace
   qu'on vient consulter.

   ⚠️ LE VRAI DÉFAUT ÉTAIT AILLEURS : « aujourd'hui » valait
   `rgba(76,175,80,0.06)`, un vert à 6 % d'opacité — invisible. Sur les
   calendriers atelier et collaborateurs, il n'y avait rien du tout, ils
   héritaient du défaut du bundle.

   ⭐ LES NIVEAUX SONT CEUX DU MOIS D'ATELIER (`.wb-mo`, 23.09.2026, lot
   LIVCAL) : hors-mois (lavis, numéro en `--ink-3`, `css/registre.css`) · passé
   (numéro en `--ink-3`) · aujourd'hui (le lavis de repère seul). Le passé est
   atténué SUR LE NUMÉRO, pas sous les livraisons : ça ne coûte rien à leur
   contraste. Les sélecteurs portent `.ec` : la forme du numéro est posée par
   `css/registre.css`, chargé après, et une égalité de poids la ferait gagner.
   ⚠️ VAUT POUR LES TROIS CALENDRIERS DU MOTEUR (livraisons, absences des
   collaborateurs, locations), comme le script qui pose les classes. */

.ec .wb-cal-passe .ec-day-head time { color: var(--ink-3); }

/* Le dimanche, l'atelier est fermé : une hachure. Posée en `background-image`, elle
   laisse sa couleur à la case (lavis du mois voisin compris). La case reste
   cliquable : la hachure signale, elle n'interdit pas. */
.ec .ec-day.wb-cal-ferme {
    background-image: repeating-linear-gradient(135deg, transparent 0 6px, var(--wash) 6px 7px);
}

/* Aujourd'hui : le lavis de repère de la charte, seul — le filet d'encre
   au-dessus de la case est parti avec la grille du mois d'atelier.

   ⛔ IL ÉTAIT BLEU, ET C'ÉTAIT UNE PASTILLE (14.09.2026, sixième revue) :
   `--bs-primary-bg-subtle` en fond, une ombre INTERNE de deux pixels en
   `--bs-primary`, et le numéro du jour peint en blanc dans un `border-radius:
   999px` — la seule pastille qui restait sur un écran WB 2.0, dans la seule
   couleur que la charte ne connaisse pas. Le planning des absences, lui, posait
   déjà `--repere-aujourdhui-w` : deux définitions d'un même repère, sur deux
   calendriers voisins (règle 6). C'est le jeton qui gagne, et il vaut pour les
   trois vues du bundle. */
.ec-day.ec-today { background-color: var(--repere-aujourdhui-w); }

/* ⚠️ AUJOURD'HUI GAGNE, sur le passé comme sur la hachure. La classe du passé
   est posée en JS sur les cellules antérieures ; si les deux se rencontraient
   (bascule de minuit, fuseau), c'est « aujourd'hui » qui doit se lire. Et un
   dimanche d'aujourd'hui reste le repère du jour, pas une case fermée. */
.ec .ec-day.ec-today.wb-cal-passe .ec-day-head time { color: var(--ink); }
.ec .ec-day.ec-today.wb-cal-ferme { background-image: none; }

html.wb-screen-grande .wb-main {
    font-size: 0.95rem;
}html.wb-screen-petite .wb-main {
    padding: 0.5rem;
    font-size: 0.875rem;
}

/* Moyenne (MacBook Pro 14/16", 22-24") : comportement par défaut, aucun override */

/* ⛔ LE BLOC « TÉLÉPHONE : LA COLONNE ÉTROITE » EST PARTI LE 01.09.2026, avec
   la sidebar. Il réglait une question de LARGEUR : 250 px de menu sur un écran
   de 390, un repli décidé avant peinture, un dépliage qui recouvre plutôt que
   de pousser, et un cas « le script n'a pas tourné ». Trois barres horizontales
   n'ont aucune de ces questions — leur hauteur ne dépend d'aucune préférence.
   Ce qui les protège sur un écran étroit vit dans `css/registre.css` (les deux
   paliers de réduction du bandeau) et se vérifie par `BandeauTelephoneTest`. */

/* Logo du garage en tête du tableau de bord — borné en hauteur pour qu'un
   fichier mal exporté ne pousse pas la page. */
.wb-dash-logo,
.wb-dash-mark {
    height: 40px;
    width: auto;
    object-fit: contain;
    flex-shrink: 0;
}
.wb-dash-logo { max-width: 260px; }
.wb-dash-mark { max-width: 120px; display: none; }

/* ⚠️ Sous 900 px, le logotype prendrait toute la largeur de l'en-tête et
   pousserait le nom et le bouton hors de vue. La marque compacte le remplace :
   même signe, place tenue. */
@media (max-width: 900px) {
    .wb-dash-logo { display: none; }
    .wb-dash-mark { display: block; }
}

/* ── Statistiques : la palette des années ─────────────────────────────────────
   ⚠️ UNE TEINTE PAR ANNÉE, PAS QUATRE NUANCES DE BLEU. La première version
   dégradait un bleu du foncé au clair : élégant sur maquette, illisible en
   usage — trois traits pâles qu'on ne distingue qu'en pointant la légende.
   Signalé par le mandant le 09.08.2026.

   Les quatre teintes sont celles d'OKABE-ITO, la palette qualitative de
   référence pour rester distinguable sous les trois formes courantes de
   daltonisme, dont la deutéranopie (≈ un homme sur douze).

   ⚠️ DÉCLARÉES SUR `:root` ET NON SUR LA PAGE : la vignette du tableau de bord
   les emploie aussi, et elle vit dans une autre page. Une palette définie deux
   fois finit par diverger.                                                   */
:root {
  --wb-stats-c1: #0072B2;  /* bleu   — année en cours */
  --wb-stats-c2: #E69F00;  /* orange — N-1 */
  --wb-stats-c3: #009E73;  /* vert   — N-2 */
  --wb-stats-c4: #CC79A7;  /* mauve  — N-3 */
}
/* Sur fond sombre, les mêmes valeurs tombent sous le seuil de contraste. */
[data-bs-theme="dark"] {
  --wb-stats-c1: #56B4E9;
  --wb-stats-c2: #F0B840;
  --wb-stats-c3: #2FBF95;
  --wb-stats-c4: #E39BC3;
}

/* Vignette du widget d'accueil : rendue côté serveur, sans JavaScript. */

/* ── Panneau « Documents » : ce qui s'accroche à une facture ────────────────
   ⛔ L'INDENTATION EST UNE AFFIRMATION, PAS UNE DÉCORATION : elle dit « ceci
   se rattache à la ligne du dessus ». Le JS ne la pose que lorsque la facture
   (ou un maillon déjà rattaché) est réellement au-dessus — sur un document
   isolé, elle désignerait le dossier d'un autre numéro.

   ⚠️ DEUX NIVEAUX, ET LA COULEUR EST LA DIFFÉRENCE. `.wb-ged-attache` est le
   rattachement nu : un bulletin de versement accompagne sa facture, il ne la
   réclame pas. `.wb-ged-relance` reprend cette base et n'ajoute QUE la couleur
   d'alerte — une relance est une créance impayée, elle doit se repérer en
   survolant la colonne, sans lire. Peindre les deux pareil ferait lire un
   impayé là où il n'y en a pas.                                              */
.wb-ged-attache,
.wb-ged-relance {
    margin-left: 1.75rem;
    position: relative;
    border-left: 3px solid var(--wb-dt-border-strong) !important;
    /* ⚠️ RESSERRER L'ÉCART, sinon le bloc ne se lit pas comme un bloc : la liste
       espace toutes ses lignes de la même façon (`gap-2`), et une relance se
       retrouvait aussi loin de sa facture que d'un dossier étranger. */
    margin-top: -0.25rem;
}
/* Le crochet qui rattache visuellement le bloc à la facture au-dessus.
   `aria-hidden` implicite : c'est un pseudo-élément, aucun lecteur d'écran ne
   le rencontre — le libellé « Rappel (2e sommation) » porte déjà le sens. */
.wb-ged-relance { border-left-color: var(--wb-dt-warn) !important; }
.wb-ged-relance::before { background: var(--wb-dt-warn); }

.wb-ged-attache::before,
.wb-ged-relance::before {
    content: "";
    position: absolute;
    left: -1rem;
    top: 1.1rem;
    width: 1rem;
    height: 3px;
    background: var(--wb-dt-border-strong);
    opacity: .55;
}

/* La couleur du retard, partagée par les cartes de l'accueil et le stockage. */
.wb-jr-rd { color: var(--red); }

@media print {
    .wb-journal .wb-page-header .btn { display: none !important; }
}

