/*
 * Feuille de style du CRM Mytek.
 *
 * AdminLTE 3 fournit la charpente (Bootstrap 4, grille, sidebar). Ce fichier apporte
 * ce qui manque à un outil qu'on utilise huit heures par jour :
 *
 *  1. un jeu de jetons de design (couleurs, rayons, ombres) qui rend l'ensemble
 *     cohérent et modifiable en un seul endroit ;
 *  2. un habillage plus lisible des composants Bootstrap (formulaires, cartes,
 *     tableaux, badges, boutons) dont les réglages par défaut sont trop serrés ;
 *  3. les composants propres au CRM : avatars, Kanban, timeline, éditeur de pipeline.
 *
 * Règle de lecture : aucune couleur n'est écrite en dur dans les composants, tout passe
 * par les jetons du bloc :root ci-dessous.
 */

/* ================================================================== Jetons de design */

:root {
    /*
     * Les trois couleurs de la charte Mytek (MYTEK-Charte.pdf, page 2), telles quelles.
     * Elles ne se dérivent de rien : c'est le reste de la palette qui se dérive d'elles.
     */
    --crm-navy:  #082d3f;  /* C100 M73 J49 N53 : le bleu nuit du logo et de la barre latérale */
    --crm-coral: #e64c54;  /* C2 M82 J58 N0    : l'accent, le triangle du logo */
    --crm-mist:  #9aa3ad;  /* C43 M29 J25 N6   : le gris bleuté */

    /*
     * Gris légèrement bleutés : plus doux à l'œil qu'un gris pur sur une journée entière.
     *
     * La rampe est calée sur la charte à ses deux extrémités : le 400 **est** le gris
     * `--crm-mist` et le 900 **est** le bleu nuit `--crm-navy`. Entre les deux, la teinte
     * glisse de 211 à 200 et la saturation descend jusqu'au 500 (10 %, celle du gris de la
     * charte) puis remonte (78 %, celle du bleu nuit) : les tons sombres tirent donc vers le
     * logo, les tons moyens restent neutres. Aucune valeur n'est choisie à l'œil, elles
     * sortent d'un calcul HSL, et leur clarté est strictement décroissante.
     */
    --crm-slate-50:  #f7f9fa;
    --crm-slate-100: #eef1f4;
    --crm-slate-200: #e0e6eb;
    --crm-slate-300: #c9d1d9;
    --crm-slate-400: var(--crm-mist);
    --crm-slate-500: #66747f;
    --crm-slate-600: #475864;
    --crm-slate-700: #2f4450;
    --crm-slate-800: #1a3644;
    --crm-slate-900: var(--crm-navy);

    /*
     * Couleurs fonctionnelles, chacune avec sa version « aplat clair » pour les pastilles.
     *
     * Le bleu d'interaction **est** le bleu nuit de la charte, éclairci : même teinte (200),
     * même saturation (78 %), seule la clarté passe de 14 % à 32 %. Le bleu nuit lui-même ne
     * peut pas jouer ce rôle, il rend 14,4:1 sur blanc, donc un lien qui ne se distingue plus
     * du texte ; à 32 % il rend 6,2:1, aussi bien en encre sur blanc qu'en fond sous du blanc.
     *
     * Le corail n'est **pas** promu couleur d'action, et c'est délibéré : il est à deux degrés
     * de teinte de `--crm-danger`, si bien qu'« enregistrer » et « supprimer » seraient du même
     * rouge. Il reste ce qu'il est dans le logo, un accent, et ne sert qu'au repère de position
     * de la barre latérale. Pour la même raison `--crm-danger` n'est pas repeint en corail.
     */
    --crm-primary:      #126791;
    --crm-primary-dark: #0d5173;
    --crm-primary-soft: #ecf6fb;
    --crm-success:      #12855f;
    --crm-success-soft: #e3f5ee;
    --crm-warning:      #96601a;
    /* L'ambre moyen des liserés et des barres : il était écrit en dur à quatre endroits, et
       `--crm-warning` est l'encre, trop sombre pour un aplat de 3 px. */
    --crm-amber:        #d9a13b;
    --crm-warning-soft: #fdf3e2;
    --crm-danger:       #cf3040;
    --crm-danger-soft:  #fdecee;
    --crm-info:         #1f7f9c;
    --crm-info-soft:    #e6f4f8;

    /* Surfaces et bordures. */
    --crm-bg:          #f3f6f9;
    --crm-surface:     #ffffff;
    --crm-border:      var(--crm-slate-200);
    --crm-border-soft: var(--crm-slate-100);

    /* Texte. */
    --crm-text:       var(--crm-slate-800);
    --crm-text-muted: var(--crm-slate-500);
    --crm-text-faint: var(--crm-slate-400);

    /*
     * Rayons, ombres, transitions.
     *
     * Trois rayons, et une règle pour choisir : sans elle, chaque écran prenait le sien :
     *   - `-lg` : un **encart**. Carte, tuile de chiffre, widget de tableau de bord, carte de
     *     Kanban, boîte de conversations, encart de configuration. C'est le rayon que l'œil
     *     associe au CRM, et il doit être le même partout, y compris entre deux encarts posés
     *     côte à côte : un 8 px à côté d'un 12 px se voit immédiatement.
     *   - (défaut) : un **contrôle** ou un flottant. Champ, bouton, menu déroulant, panneau de
     *     filtre rapide, boîte imbriquée dans un encart : un rayon plus serré que son parent.
     *   - `-sm` : une **pastille**, un jeton, un coin de bulle de message.
     *
     * Deux feuilles (`crm-chat.css`, `crm-settings.css`) portaient leurs rayons en dur et
     * étaient donc restées à 8 px : la boîte de conversations et les encarts de configuration
     * avaient des coins plus secs que le reste. Ne jamais écrire un rayon en dur.
     */
    --crm-radius-sm: .35rem;
    --crm-radius:    .5rem;
    --crm-radius-lg: .75rem;
    /* L'encre des ombres est le bleu nuit de la charte, pas un gris neutre : une ombre grise
       sur un fond bleuté vire au brun là où elle est la plus dense. */
    --crm-shadow-sm: 0 1px 3px rgba(8, 45, 63, .10), 0 1px 2px rgba(8, 45, 63, .05);
    --crm-shadow:    0 4px 12px rgba(8, 45, 63, .10), 0 1px 3px rgba(8, 45, 63, .06);
    --crm-shadow-lg: 0 12px 32px rgba(8, 45, 63, .16);
    --crm-ring:      0 0 0 .2rem rgba(18, 103, 145, .25);
    --crm-ease:      160ms cubic-bezier(.4, 0, .2, 1);

    --crm-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
                Arial, "Noto Sans", sans-serif;
    --crm-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* ================================================================== Base */

body,
.wrapper {
    font-family: var(--crm-font);
    color: var(--crm-text);
}

body {
    background-color: var(--crm-bg);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.content-wrapper { background-color: var(--crm-bg); }

/* AdminLTE impose son propre gris à l'écran de connexion : on le ramène au fond du CRM. */
body.login-page,
body.register-page { background-color: var(--crm-bg); }
.login-box .card { box-shadow: var(--crm-shadow); }
/*
 * Le logo remplace le titre en toutes lettres, et c'est ici qu'on sert le verrouillage complet,
 * « PORTAGE » compris : c'est le seul écran du CRM qui ait la place de le rendre lisible. La
 * taille est donnée en **largeur**, celle de la boîte de connexion étant la contrainte réelle
 * (360 px) ; à 13,75 rem le mot rend une hauteur de capitale de 6 px, contre 2 px dans le
 * bandeau du menu.
 */
.login-logo .crm-login-logo { width: 13.75rem; max-width: 100%; height: auto; }

a { color: var(--crm-primary); }
a:hover { color: var(--crm-primary-dark); }

.text-muted { color: var(--crm-text-muted) !important; }

/* Un seul anneau de focus pour toute l'application : visible sans être agressif. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--crm-primary);
    outline-offset: 2px;
    box-shadow: none;
}

/* ================================================================== En-tête de page */

.content-header { padding: 1.35rem .5rem .85rem; }

.content-header h1 {
    font-size: 1.5rem;
    font-weight: 600;
    letter-spacing: -.015em;
    color: var(--crm-slate-900);
    display: flex;
    align-items: center;
    gap: .6rem;
}

/* L'icône du titre devient une vignette : elle identifie le module sans crier. */
.content-header h1 > .fas,
.content-header h1 > .far,
.content-header h1 > .fab {
    font-size: 1rem;
    color: var(--crm-primary);
    background: var(--crm-primary-soft);
    width: 2.1rem;
    height: 2.1rem;
    border-radius: var(--crm-radius);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    margin: 0 !important;
}

/* Sous-titre d'écran : à quoi sert cette page, en une phrase. */
.crm-page-subtitle {
    margin: .35rem 0 0;
    color: var(--crm-text-muted);
    font-size: .875rem;
    max-width: 78ch;
}

/*
 * Actions principales de l'écran, alignées sur le titre.
 *
 * `clear` est indispensable : le fil d'Ariane est flottant, et un conteneur flex se
 * rétrécit pour l'éviter au lieu de passer dessous, les boutons se retrouvaient
 * empilés sur deux lignes dans un espace de 150 px.
 */
.crm-page-actions {
    clear: both;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    justify-content: flex-end;
    align-items: center;
}

.breadcrumb {
    background: transparent;
    padding: .35rem 0;
    margin-bottom: 0;
    font-size: .8125rem;
}
.breadcrumb-item + .breadcrumb-item::before { color: var(--crm-slate-300); }
.breadcrumb-item.active { color: var(--crm-text-muted); }

/* ================================================================== Barre supérieure */

.main-header.navbar {
    background: var(--crm-surface);
    border-bottom: 1px solid var(--crm-border);
    box-shadow: none;
    min-height: 3.5rem;
}

.main-header .nav-link { color: var(--crm-slate-600); }
.main-header .nav-link:hover { color: var(--crm-slate-900); }

/*
 * Le groupe d'actions de droite : des cibles carrées et une pastille au survol.
 *
 * Elles étaient des liens nus de largeurs inégales (46, 50, 43, 48 px mesurés), et rien ne
 * disait qu'on pouvait cliquer avant d'avoir la souris dessus. Une trame carrée de 2,25 rem
 * donne une rangée régulière et une cible confortable ; la pastille au survol dit « bouton »
 * là où le seul changement de couleur du glyphe ne le disait pas.
 *
 * La largeur fixe sert aussi le badge : c'est elle qui garantit la place à sa droite du
 * glyphe, sans quoi il n'y a pas de « coin » où se percher (voir plus bas).
 */
.main-header .navbar-nav.ml-auto > .nav-item > .nav-link,
.main-header .navbar-nav.ml-auto > .nav-item > .btn {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    margin: 0 .1rem;
    padding: 0;
    border-radius: var(--crm-radius);
    transition: background-color .12s ease, color .12s ease;
}

.main-header .navbar-nav.ml-auto > .nav-item > .nav-link:hover,
.main-header .navbar-nav.ml-auto > .nav-item > .btn:hover {
    background: var(--crm-slate-100);
}

/* L'écran courant se signale, comme dans le menu latéral : la roue dentée allumée dit qu'on
   est dans la configuration, ce qui évite de chercher où l'on se trouve. */
.main-header .navbar-nav.ml-auto > .nav-item > .nav-link.active {
    background: var(--crm-primary-soft);
    color: var(--crm-primary-dark);
}

.main-header .navbar-nav.ml-auto > .nav-item > .nav-link > .fas,
.main-header .navbar-nav.ml-auto > .nav-item > .nav-link > .far,
.main-header .navbar-nav.ml-auto > .nav-item > .btn > .fas {
    font-size: 1rem;
    line-height: 1;
}

/* Le point de disponibilité du chat est un voyant, pas une icône : plus petit que ses
   voisines, il se lit comme un état et non comme une action de plus. */
.main-header [data-crm-chat-toggle] > .fas.fa-circle { font-size: .6rem; }

/*
 * Le compteur se perche au coin haut-droit du glyphe.
 *
 * Il était **centré dessus** : mesuré sur le tableau de bord, le badge des tâches en retard
 * allait de x=241 à x=274 pour une icône allant de 246 à 260. Deux chiffres recouvraient donc
 * le glyphe entier, et la barre affichait une pastille rouge sans qu'on sache de quoi : « 46 »
 * ne veut rien dire sans le presse-papiers qui le porte. La cause était un aplomb sur le bord
 * du lien (`right: 1px`) alors que le badge grandit vers la gauche à chaque chiffre.
 *
 * Il est maintenant aligné à droite **et** déporté vers l'extérieur : il ne mord que le coin,
 * comme un compteur de notifications doit le faire, et sa liseré de la couleur du fond le
 * détache du glyphe sans avoir besoin d'espace supplémentaire.
 */
/*
 * `.main-header` en tête du sélecteur, et ce n'est pas décoratif.
 *
 * `.navbar-badge` seul a la même spécificité que `.badge`, plus bas dans cette feuille
 * (« Badges et pastilles ») : c'est donc `.badge` qui gagnait, par simple ordre de lecture.
 * Mesuré : le compteur recevait `font-size: .72rem` et `padding: .3rem .5rem` au lieu des
 * valeurs écrites ici, d'où 33 px de large pour deux chiffres, soit plus du double du glyphe
 * qu'il devait décorer. Rien dans le bloc de la barre supérieure ne le disait, et c'est le
 * même piège que la classe `.crm-composer-tool` partagée entre la boîte de chat et la fenêtre
 * d'e-mail : un réglage voyage d'une fonction à l'autre sans laisser de trace là où on le lit.
 */
.main-header .navbar-badge {
    position: absolute;
    top: 0;
    right: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.05rem;
    height: 1.05rem;
    padding: 0 .22rem;
    border: 2px solid var(--crm-surface);
    /* Une pastille, donc le rayon des pastilles, poussé au cercle : un compteur de deux
       chiffres reste une gélule, jamais un rectangle aux coins arrondis. */
    border-radius: 999px;
    font-size: .625rem;
    font-weight: 700;
    letter-spacing: 0;
    line-height: 1;
    transform: translate(30%, -22%);
}

/*
 * Un compteur perché se lit en plein, jamais en fond clair.
 *
 * `.badge-warning` est un fond ambre très pâle avec un texte ambre : parfait pour une pastille
 * de statut dans un tableau, illisible à dix pixels sur un glyphe. Les compteurs de la barre
 * sont donc pleins, avec leur liseré de la couleur du fond pour se détacher.
 */
.main-header .navbar-badge.badge-warning {
    background: var(--crm-warning);
    color: #fff;
    border-color: var(--crm-surface);
}

/* Le bloc du compte, détaché du groupe d'actions par un filet : ce sont deux choses
   différentes, l'une agit sur le CRM, l'autre sur soi. */
.main-header .navbar-nav.ml-auto > .nav-item.dropdown:last-child {
    margin-left: .45rem;
    padding-left: .55rem;
    border-left: 1px solid var(--crm-border);
}

.main-header .navbar-nav.ml-auto > .nav-item.dropdown:last-child > .nav-link {
    width: auto;
    padding: 0 .45rem 0 .35rem;
    gap: .45rem;
}

.form-control-navbar {
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border);
    border-right: 0;
    border-radius: var(--crm-radius) 0 0 var(--crm-radius);
    height: 2.3rem;
}
.form-control-navbar:focus {
    background: var(--crm-surface);
    border-color: var(--crm-primary);
    box-shadow: none;
}
.form-control-navbar + .input-group-append .btn-navbar {
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border);
    border-left: 0;
    border-radius: 0 var(--crm-radius) var(--crm-radius) 0;
    color: var(--crm-text-muted);
}
.crm-global-search .input-group:focus-within .btn-navbar {
    background: var(--crm-surface);
    border-color: var(--crm-primary);
    color: var(--crm-primary);
}

/* Logement du raccourci, entre le champ et le bouton de recherche. */
.crm-kbd-slot {
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border);
    border-left: 0;
    border-right: 0;
    padding: 0 .35rem;
    align-items: center;
}
.crm-global-search .input-group:focus-within .crm-kbd-slot { border-color: var(--crm-primary); }

/* Raccourci clavier annoncé dans le champ de recherche. */
.crm-kbd {
    display: inline-block;
    padding: .05rem .32rem;
    font-family: var(--crm-font);
    font-size: .68rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--crm-text-muted);
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-bottom-width: 2px;
    border-radius: .25rem;
}

/* ================================================================== Menu latéral */

.main-sidebar { background: var(--crm-slate-900); box-shadow: none; }

/*
 * Le bandeau de marque porte le logo Mytek, pas une icône générique.
 *
 * Sa hauteur n'est pas un choix de mise en page : AdminLTE écrit
 * `.sidebar { height: calc(100% - (3.5rem + 1px)) }`, donc tout bandeau plus haut pousse le
 * bas du menu hors de l'écran, et tout bandeau plus bas laisse une bande morte. 3,5 rem est
 * aussi la hauteur de la barre supérieure : les deux filets du haut se rejoignent.
 *
 * Le logo servi est la déclinaison **blanche** de la charte (le fichier nommé « FondBleu »
 * chez le graphiste : c'est la version *pour* un fond bleu, pas une version *à* fond bleu).
 * La déclinaison bleu nuit est conservée à côté pour les fonds clairs.
 *
 * C'est la marque MYTEK **seule** qui est servie ici, et non le verrouillage complet avec son
 * « PORTAGE ». Ce n'est pas un choix de goût : à 36 px de haut, la hauteur de capitale de
 * PORTAGE tombe à 2 px, donc une bavure corail sous le mot. Il faudrait un logo de 146 px de
 * haut pour la ramener à 8 px, et le bandeau ne peut pas grandir. L'écran de connexion, lui,
 * a la place et porte le verrouillage entier.
 */
.brand-link {
    display: flex;
    align-items: center;
    gap: .7rem;
    height: 3.5rem;
    padding: 0 1rem;
    overflow: hidden;
}

/*
 * Le fond et le filet sont repris à AdminLTE, qui les peint en gris ardoise par deux règles
 * plus spécifiques que `.brand-link` : `[class*="sidebar-dark"] .brand-link` pour le filet, et
 * `.layout-navbar-fixed .wrapper .sidebar-dark-primary .brand-link:not([class*="navbar"])`
 * pour le fond. Sans cette spécificité rendue coup pour coup, le bandeau reste gris au-dessus
 * d'une barre bleu nuit, et rien dans le bloc qu'on écrit ne dit d'où vient ce gris. Le fond
 * est peint et non rendu transparent : le bandeau est en `position: fixed`, il passe donc
 * au-dessus du contenu de la page.
 */
[class*="sidebar-dark"] .brand-link,
.layout-navbar-fixed .wrapper .sidebar-dark-primary .brand-link:not([class*="navbar"]) {
    background-color: var(--crm-navy);
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.brand-link .crm-brand-logo { height: 2.25rem; width: auto; flex: 0 0 auto; }
.brand-link .crm-brand-picto { display: none; height: 1.85rem; width: auto; }

/* « CRM » nomme l'outil, que le logo seul ne nomme pas : le même logo sert au site et aux
   contrats. Séparé par un filet plutôt que collé, sinon il se lit comme un morceau du logo. */
.brand-link .crm-brand-app {
    padding-left: .7rem;
    border-left: 1px solid rgba(255, 255, 255, .18);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--crm-mist);
    line-height: 1;
}

/* Menu replié : le picto seul, centré. Le survol rouvre la barre, donc rend le logo entier. */
.sidebar-collapse .brand-link { justify-content: center; padding: 0 .5rem; }
.sidebar-collapse .brand-link .crm-brand-logo,
.sidebar-collapse .brand-link .crm-brand-app { display: none; }
.sidebar-collapse .brand-link .crm-brand-picto { display: block; }
.sidebar-collapse .main-sidebar:hover .brand-link { justify-content: flex-start; padding: 0 1rem; }
.sidebar-collapse .main-sidebar:hover .brand-link .crm-brand-logo { display: block; }
.sidebar-collapse .main-sidebar:hover .brand-link .crm-brand-app { display: block; }
.sidebar-collapse .main-sidebar:hover .brand-link .crm-brand-picto { display: none; }

.nav-sidebar .nav-header {
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--crm-slate-400);
    padding: 1.15rem 1.1rem .35rem;
    background: transparent;
}

.nav-sidebar .nav-link {
    border-radius: var(--crm-radius);
    margin: .1rem .55rem;
    padding: .5rem .7rem;
    font-size: .89rem;
    color: var(--crm-slate-300);
    transition: background var(--crm-ease), color var(--crm-ease);
}
.nav-sidebar .nav-link:hover { background: rgba(255, 255, 255, .07); color: #fff; }
.nav-sidebar .nav-link .nav-icon {
    font-size: .95rem;
    width: 1.35rem;
    color: var(--crm-slate-400);
}
.nav-sidebar .nav-link:hover .nav-icon { color: #fff; }

/*
 * L'élément actif : un liseré corail, et non plus un aplat franc. On doit savoir où l'on est
 * d'un coup d'oeil, et c'est justement ce que l'aplat ne pouvait plus faire une fois la barre
 * passée au bleu nuit de la charte. L'arithmétique tranche, elle ne laisse pas le choix :
 *
 *  - le fond de la barre est à 0,023 de luminance relative ;
 *  - un aplat sous du texte blanc doit rester sous 0,183, sans quoi le libellé tombe sous les
 *    4,5:1 exigés à cette taille (0,89 rem, donc pas du « grand texte ») ;
 *  - un aplat sous 0,183 sur un fond à 0,023 plafonne à **3,2:1** : jamais franc.
 *
 * Mesuré sur les deux candidats : le bleu d'interaction rend 2,3:1 contre la barre (invisible),
 * le corail plein 3,8:1 mais son texte blanc tombe à 3,8:1 aussi (illisible aux normes). Le
 * repère quitte donc le fond pour le bord, où aucune de ces deux bornes ne s'applique : le
 * liseré rend 3,8:1 contre la barre, et le libellé blanc 10,1:1 sur son fond surélevé. C'est
 * au passage l'emploi que la charte fait du corail, un accent de forme et non un aplat.
 */
.sidebar-dark-primary .nav-sidebar > .nav-item > .nav-link.active,
.sidebar-dark-primary .nav-sidebar .nav-treeview > .nav-item > .nav-link.active {
    position: relative;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    font-weight: 600;
    box-shadow: none;
}
/* Le liseré est posé au bord de la barre, hors de la pastille : à l'intérieur, l'arrondi de
   8 px le rognerait par les deux bouts, et il ne resterait qu'un tiret au milieu. */
.nav-sidebar .nav-link.active::before {
    content: "";
    position: absolute;
    left: -.55rem;
    top: .3rem;
    bottom: .3rem;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--crm-coral);
}
.nav-sidebar .nav-link.active .nav-icon { color: var(--crm-coral); }

.nav-treeview .nav-link { font-size: .85rem; padding-left: 1.6rem; }
.nav-treeview .nav-icon { font-size: .5rem !important; }

/* ================================================================== Cartes */

.card {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    box-shadow: var(--crm-shadow-sm);
    margin-bottom: 1.25rem;
}

.card-header {
    background: transparent;
    border-bottom: 1px solid var(--crm-border-soft);
    padding: .9rem 1.15rem;
    border-radius: var(--crm-radius-lg) var(--crm-radius-lg) 0 0 !important;
    min-height: 0;
}

.card-title {
    font-size: .95rem;
    font-weight: 600;
    color: var(--crm-slate-800);
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: .45rem;
}

.card-body { padding: 1.15rem; }

.card-footer {
    background: var(--crm-slate-50);
    border-top: 1px solid var(--crm-border-soft);
    padding: .8rem 1.15rem;
    border-radius: 0 0 var(--crm-radius-lg) var(--crm-radius-lg) !important;
}

.card-outline.card-primary { border-top: 3px solid var(--crm-primary); }

/* Précision sous un titre de carte : la règle métier à connaître avant d'agir. */
.crm-card-hint {
    font-size: .8rem;
    color: var(--crm-text-muted);
    margin: .25rem 0 0;
    flex-basis: 100%;
}

/* ================================================================== Boutons */

/*
 * Un bouton doit se voir, dire ce qu'il fait et donner envie d'être cliqué. Trois moyens :
 * la mise en page interne (flex + gap, l'icône ne dépend plus des marges du gabarit), le
 * relief (dégradé très court, liseré interne clair, ombre colorée) et la réaction au
 * survol (un pixel de soulèvement, l'ombre qui s'étale).
 */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    border-radius: var(--crm-radius);
    font-weight: 600;
    font-size: .875rem;
    line-height: 1.35;
    padding: .45rem .95rem;
    white-space: nowrap;
    transition: background var(--crm-ease), border-color var(--crm-ease),
                box-shadow var(--crm-ease), color var(--crm-ease),
                transform var(--crm-ease);
}

/*
 * Les gabarits espacent l'icône avec « mr-1 ». Le `gap` s'en charge désormais pour tous
 * les boutons de l'application : on neutralise la marge pour que l'écart soit le même
 * partout, quel que soit ce que le gabarit a écrit.
 */
.btn > i[class*="fa-"] { margin: 0 !important; font-size: .92em; }

/* `display: inline-flex` prendrait le pas sur .btn-block : on le rétablit. */
.btn-block { display: flex; width: 100%; }

.btn-sm { padding: .32rem .7rem; font-size: .8125rem; gap: .35rem; border-radius: var(--crm-radius-sm); }
.btn-xs { padding: .2rem .45rem; font-size: .75rem; gap: .3rem; border-radius: var(--crm-radius-sm); }
.btn-lg { padding: .62rem 1.35rem; font-size: 1rem; gap: .55rem; }

.btn:disabled,
.btn.disabled { box-shadow: none; transform: none; opacity: .55; }

/* Action principale : la seule à porter une couleur pleine et une ombre teintée. */
.btn-primary {
    background-color: var(--crm-primary);
    background-image: linear-gradient(180deg, #4a71ef, var(--crm-primary));
    border-color: var(--crm-primary-dark);
    box-shadow: 0 1px 2px rgba(20, 40, 110, .22), inset 0 1px 0 rgba(255, 255, 255, .18);
}
.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--crm-primary-dark);
    background-image: linear-gradient(180deg, #3d64ec, var(--crm-primary-dark));
    border-color: var(--crm-primary-dark);
    box-shadow: 0 5px 14px rgba(47, 91, 234, .34), inset 0 1px 0 rgba(255, 255, 255, .2);
    transform: translateY(-1px);
}
.btn-primary:not(:disabled):not(.disabled):active {
    background-image: none;
    background-color: var(--crm-primary-dark);
    box-shadow: inset 0 2px 4px rgba(20, 40, 110, .3);
    transform: translateY(0);
}

/* Action secondaire : blanche et bordée, elle recule sans disparaître. */
.btn-secondary {
    background: var(--crm-surface);
    background-image: linear-gradient(180deg, #ffffff, #fbfcfd);
    border-color: var(--crm-slate-300);
    color: var(--crm-slate-700);
    box-shadow: 0 1px 2px rgba(22, 28, 38, .05);
}
.btn-secondary:hover,
.btn-secondary:focus {
    background-image: none;
    background-color: var(--crm-slate-50);
    border-color: var(--crm-slate-400);
    color: var(--crm-slate-900);
    box-shadow: 0 3px 8px rgba(22, 28, 38, .08);
    transform: translateY(-1px);
}
.btn-secondary:not(:disabled):not(.disabled):active {
    background-color: var(--crm-slate-100);
    box-shadow: inset 0 2px 4px rgba(22, 28, 38, .08);
    transform: translateY(0);
}

.btn-outline-primary {
    background: var(--crm-surface);
    border-color: rgba(47, 91, 234, .4);
    color: var(--crm-primary);
}
.btn-outline-primary:hover {
    background: var(--crm-primary);
    border-color: var(--crm-primary);
    box-shadow: 0 3px 10px rgba(47, 91, 234, .25);
}

.btn-outline-secondary {
    background: var(--crm-surface);
    border-color: var(--crm-slate-300);
    color: var(--crm-slate-600);
}
.btn-outline-secondary:hover {
    background: var(--crm-slate-50);
    border-color: var(--crm-slate-400);
    color: var(--crm-slate-900);
}

.btn-outline-danger { background: var(--crm-surface); border-color: rgba(207, 48, 64, .4); color: var(--crm-danger); }
.btn-outline-danger:hover {
    background: var(--crm-danger);
    border-color: var(--crm-danger);
    box-shadow: 0 3px 10px rgba(207, 48, 64, .25);
}

.btn-success {
    background-color: var(--crm-success);
    background-image: linear-gradient(180deg, #17a074, var(--crm-success));
    border-color: #0d6b4c;
    box-shadow: 0 1px 2px rgba(6, 60, 42, .2), inset 0 1px 0 rgba(255, 255, 255, .18);
}
.btn-success:hover { box-shadow: 0 5px 14px rgba(18, 133, 95, .3); transform: translateY(-1px); }

.btn-danger {
    background-color: var(--crm-danger);
    background-image: linear-gradient(180deg, #e0424f, var(--crm-danger));
    border-color: #a8262f;
    box-shadow: 0 1px 2px rgba(110, 20, 28, .2), inset 0 1px 0 rgba(255, 255, 255, .18);
}
.btn-danger:hover { box-shadow: 0 5px 14px rgba(207, 48, 64, .3); transform: translateY(-1px); }

.btn-link { font-weight: 500; box-shadow: none; }
.btn-link:hover { transform: none; box-shadow: none; }

/*
 * Groupe de boutons présenté en sélecteur segmenté : un seul bloc, des séparateurs fins,
 * et pas de soulèvement au survol, les segments doivent rester alignés.
 */
.btn-group {
    border-radius: var(--crm-radius);
    box-shadow: 0 1px 2px rgba(22, 28, 38, .06);
}
.btn-group > .btn {
    box-shadow: none;
    background-image: none;
    font-weight: 500;
}
.btn-group > .btn:hover,
.btn-group > .btn:focus {
    transform: none;
    box-shadow: none;
    z-index: 2;
}
.btn-group > .btn + .btn { border-left-color: var(--crm-border); }

/* Action discrète d'une ligne de tableau : neutre au repos, colorée au survol. */
.crm-btn-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.95rem;
    height: 1.95rem;
    border: 1px solid transparent;
    border-radius: var(--crm-radius-sm);
    background: transparent;
    color: var(--crm-text-muted);
    font-size: .8rem;
    padding: 0;
    transition: all var(--crm-ease);
}
.crm-btn-ghost:hover {
    background: var(--crm-primary-soft);
    border-color: var(--crm-primary);
    color: var(--crm-primary);
    text-decoration: none;
}
.crm-btn-ghost-danger:hover {
    background: var(--crm-danger-soft);
    border-color: var(--crm-danger);
    color: var(--crm-danger);
}
/* Action indisponible : elle reste visible et explique pourquoi par son title. */
.crm-btn-ghost:disabled,
.crm-btn-ghost[disabled] {
    opacity: .4;
    cursor: not-allowed;
    background: transparent;
    border-color: transparent;
    color: var(--crm-text-faint);
}

/* ================================================================== Formulaires */

.form-group { margin-bottom: 1.1rem; }

label,
.col-form-label {
    font-size: .8125rem;
    font-weight: 600;
    color: var(--crm-slate-700);
    margin-bottom: .35rem;
}

/* Champ obligatoire : l'astérisque est posée par le thème de formulaire, pas à la main. */
label.required::after,
.crm-required::after {
    content: "*";
    color: var(--crm-danger);
    margin-left: .2rem;
    font-weight: 700;
}

/* Les cases à cocher gardent un libellé de poids normal : ce n'est pas un titre de champ. */
.custom-control-label.crm-label,
.form-check-label.crm-label { font-weight: 500; }

.form-control,
.custom-select {
    border: 1px solid var(--crm-slate-300);
    border-radius: var(--crm-radius);
    height: calc(2.4rem + 2px);
    padding: .45rem .7rem;
    font-size: .875rem;
    color: var(--crm-text);
    background-color: var(--crm-surface);
    box-shadow: none;
    transition: border-color var(--crm-ease), box-shadow var(--crm-ease);
}
textarea.form-control { height: auto; line-height: 1.55; }

.form-control::placeholder { color: var(--crm-text-faint); }

.form-control:hover:not(:focus):not(:disabled) { border-color: var(--crm-slate-400); }

.form-control:focus,
.custom-select:focus {
    border-color: var(--crm-primary);
    box-shadow: var(--crm-ring);
    outline: none;
}

.form-control:disabled,
.form-control[readonly] {
    background-color: var(--crm-slate-50);
    color: var(--crm-text-muted);
}

.form-control-sm { height: calc(1.9rem + 2px); padding: .25rem .55rem; font-size: .8125rem; }

/* Texte d'aide : gris, petit, mais jamais sous le seuil de lisibilité. */
.form-text,
small.form-text,
.crm-help {
    font-size: .78rem;
    color: var(--crm-text-muted);
    margin-top: .35rem;
    line-height: 1.45;
}

.invalid-feedback,
.crm-field-error {
    display: block;
    font-size: .78rem;
    font-weight: 500;
    color: var(--crm-danger);
    margin-top: .3rem;
}
.form-control.is-invalid { border-color: var(--crm-danger); background-image: none; }
.form-control.is-invalid:focus { box-shadow: 0 0 0 .2rem rgba(207, 48, 64, .18); }

/* Case à cocher présentée en interrupteur : l'état est lisible sans lire le libellé. */
.custom-control-label { font-weight: 500; font-size: .875rem; padding-top: .1rem; }
.custom-switch .custom-control-label::before { border-color: var(--crm-slate-300); }
.custom-control-input:checked ~ .custom-control-label::before {
    background-color: var(--crm-primary);
    border-color: var(--crm-primary);
}
.custom-control-input:focus ~ .custom-control-label::before { box-shadow: var(--crm-ring); }

/* Liste de choix développée : autant de colonnes que la largeur en autorise. */
.crm-choice-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: .3rem 1.25rem;
    padding: .55rem .75rem;
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border-soft);
    border-radius: var(--crm-radius);
}
.crm-choice-grid .custom-control { margin-bottom: 0; }

/* Bloc « interrupteur + explication », utilisé pour les options de configuration. */
.crm-toggle-field {
    display: flex;
    gap: .85rem;
    align-items: flex-start;
    padding: .8rem .95rem;
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border-soft);
    border-radius: var(--crm-radius);
}
.crm-toggle-field .crm-help { margin-top: .2rem; }

/* Regroupement thématique de champs à l'intérieur d'un formulaire long. */
.crm-fieldset { border: 0; padding: 0; margin: 0 0 1.6rem; }
.crm-fieldset:last-of-type { margin-bottom: 0; }
.crm-fieldset-legend {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--crm-text-muted);
    padding-bottom: .5rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--crm-border-soft);
    width: 100%;
}
.crm-fieldset-legend .fas,
.crm-fieldset-legend .far { color: var(--crm-slate-400); }

/* Barre d'enregistrement collante : le bouton reste atteignable sur un formulaire long. */
/*
 * La `gap` tient la barre d'actions ensemble.
 *
 * Les quatre barres du CRM sont des `d-flex` sans gouttière : leurs éléments se touchaient dès
 * que l'un d'eux n'avait pas de marge de son côté. Le cas visible était la fenêtre d'e-mail, où
 * la case « Créer une tâche de suivi » démarrait au pixel où finissait « Envoyer » : la case se
 * lisait comme une partie du bouton, alors que c'est un choix distinct qu'on fait avant de
 * cliquer.
 */
.crm-sticky-actions {
    position: sticky;
    bottom: 0;
    z-index: 5;
    gap: .85rem;
    background: var(--crm-surface);
    border-top: 1px solid var(--crm-border);
    box-shadow: 0 -4px 12px rgba(22, 28, 38, .06);
}

/* Indicateur de modification non enregistrée. */
.crm-dirty-flag {
    display: none;
    align-items: center;
    gap: .35rem;
    font-size: .78rem;
    font-weight: 500;
    color: var(--crm-warning);
}
.crm-dirty .crm-dirty-flag { display: inline-flex; }

/* Select2 aligné sur la hauteur et le rayon des champs natifs. */
.select2-container--bootstrap4 .select2-selection {
    border: 1px solid var(--crm-slate-300) !important;
    border-radius: var(--crm-radius) !important;
    min-height: calc(2.4rem + 2px);
    font-size: .875rem;
}
.select2-container--bootstrap4 .select2-selection--single { height: calc(2.4rem + 2px); }
.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered {
    line-height: calc(2.4rem);
    padding-left: .7rem;
}
.select2-container--bootstrap4.select2-container--focus .select2-selection,
.select2-container--bootstrap4.select2-container--open .select2-selection {
    border-color: var(--crm-primary) !important;
    box-shadow: var(--crm-ring);
}
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice {
    background: var(--crm-primary-soft);
    border: 1px solid rgba(47, 91, 234, .25);
    border-radius: var(--crm-radius-sm);
    color: var(--crm-primary-dark);
    font-size: .8rem;
    padding: .08rem .45rem;
}
.select2-container--bootstrap4 .select2-results__option--highlighted { background: var(--crm-primary) !important; }
.select2-dropdown { border-color: var(--crm-slate-300); border-radius: var(--crm-radius); box-shadow: var(--crm-shadow); }

/* ================================================================== Volet latéral (§5.7) */

/*
 * Les formulaires de création s'ouvrent dans un panneau glissant à droite, sans quitter
 * l'écran de travail : on ne perd ni sa liste, ni ses filtres, ni sa place dans la page.
 *
 * Le panneau est en trois parties fixes : en-tête, corps défilant, pied d'actions collant.
 */
.crm-drawer-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1045;
    background: rgba(22, 28, 38, .45);
    opacity: 0;
    transition: opacity 200ms ease;
}
.crm-drawer-backdrop.is-open { opacity: 1; }

.crm-drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 1046;
    width: min(38rem, 100vw);
    display: flex;
    flex-direction: column;
    background: var(--crm-surface);
    box-shadow: -12px 0 32px rgba(22, 28, 38, .18);
    transform: translateX(100%);
    transition: transform 220ms cubic-bezier(.32, .72, 0, 1);
}
.crm-drawer.is-open { transform: translateX(0); }

/* Certains formulaires (positionnement, mission) ont trop de champs pour 38 rem. */
.crm-drawer.is-wide { width: min(52rem, 100vw); }

.crm-drawer-form { display: flex; flex-direction: column; height: 100%; min-height: 0; }

/*
 * Le gabarit de formulaire garde un niveau d'imbrication entre le fragment et l'en-tête
 * (c'est la colonne de la grille en page pleine). Il doit relayer la contrainte de
 * hauteur, sans quoi le corps ne défile pas et le pied d'actions sort de l'écran.
 */
.crm-drawer-pane {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.crm-drawer-head {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--crm-border);
}
.crm-drawer-title {
    flex: 1 1 auto;
    margin: 0;
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -.01em;
    color: var(--crm-slate-900);
}
.crm-drawer-close {
    flex: 0 0 auto;
    width: 2.1rem;
    height: 2.1rem;
    border: 1px solid transparent;
    border-radius: var(--crm-radius);
    background: transparent;
    color: var(--crm-text-muted);
    transition: all var(--crm-ease);
}
.crm-drawer-close:hover {
    background: var(--crm-slate-100);
    border-color: var(--crm-border);
    color: var(--crm-slate-900);
}

.crm-drawer-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/*
 * Une fenêtre centrée met son contenu en retrait des bords, et ce retrait vient d'ici.
 *
 * `.crm-drawer-body` n'avait aucun retrait horizontal : les écrans qui en ont un le tenaient de
 * leur propre `.card-body`. Ceux qui rendent un formulaire nu, comme le réglage des colonnes
 * d'un encart ou les champs d'un bloc, collaient donc au bord de la fenêtre : mesuré, les
 * lignes commençaient à **2 px** de l'arête. C'est ce que l'utilisateur voyait, et régler des
 * dixièmes de rem sur la zone de défilement ne pouvait pas y changer quoi que ce soit.
 *
 * 1,25 rem, comme le retrait de la barre de titre juste au-dessus : le contenu s'aligne alors
 * sur le titre, ce qui est la seule valeur qui ne se remarque pas.
 *
 * Portée à la fenêtre centrée : le volet de bord et la fenêtre ancrée en bas rendent une carte
 * qui porte déjà son propre rembourrage, et l'additionner aurait doublé la marge là où elle
 * était juste.
 */
.crm-drawer.is-modal > .crm-drawer-form > .crm-drawer-pane > .crm-drawer-body,
.crm-drawer.is-modal .crm-drawer-body {
    padding: .5rem 1.5rem 1.25rem;
}

/*
 * La barre de titre suit le même retrait, sinon le titre ne s'aligne plus sur le contenu.
 *
 * Elle est à 1,25 rem partout ailleurs, et c'est juste pour un volet de bord ou une fenêtre
 * ancrée, plus étroits. Une fenêtre centrée fait le double de large : le même retrait y paraît
 * deux fois plus serré, et c'est ce que l'utilisateur a signalé deux fois.
 */
.crm-drawer.is-modal .crm-drawer-head { padding-left: 1.5rem; padding-right: 1.5rem; }

/* Une carte à l'intérieur reprendrait le retrait par-dessus le nôtre. */
.crm-drawer.is-modal .crm-drawer-body > .card,
.crm-drawer.is-modal .crm-drawer-body > form > .card { margin: 0; }

/* Dans le volet, la carte n'a plus de raison d'être : le panneau EST la carte. */
/* Portée limitée à la fenêtre : le même gabarit sert la page pleine, où la carte doit
   garder sa bordure et son ombre. */
.crm-drawer .crm-drawer-card { border: 0; border-radius: 0; box-shadow: none; margin: 0; }
.crm-drawer .crm-drawer-card > .card-footer { border-radius: 0 !important; }

/*
 * Hauteur répartie : en-têtes fixes en haut, corps de message extensible, pied collé en
 * bas. Sans cette chaîne de conteneurs flex, la zone de saisie d'un e-mail garderait la
 * hauteur de son contenu et laisserait un vide sous elle.
 */
.crm-drawer-body.crm-drawer-body-fill { display: flex; flex-direction: column; }
.crm-drawer-body-fill > form,
.crm-drawer-body-fill > form > .card { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }

/*
 * Un panneau étroit se lit en une seule colonne. On neutralise donc les colonnes de la
 * grille à l'intérieur : sans toucher aux grilles CSS (listes de cases à cocher), qui
 * s'adaptent déjà à la place disponible.
 */
.crm-drawer .row > [class*="col-"],
.crm-drawer .form-row > [class*="col-"] {
    flex: 0 0 100%;
    max-width: 100%;
}

/* Le corps de la page ne défile pas derrière un volet ouvert. */
body.crm-drawer-open { overflow: hidden; }

/* Chargement du contenu : le panneau s'ouvre tout de suite, le formulaire suit. */
.crm-drawer-loading {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .75rem;
    color: var(--crm-text-muted);
    font-size: .875rem;
}

@media (max-width: 575.98px) {
    .crm-drawer, .crm-drawer.is-wide { width: 100vw; }
}

/* ------------------------------------------------------------------ Ancrage en bas */

/*
 * Même fenêtre, second ancrage : en bas à droite plutôt que sur le bord droit.
 *
 * Le partage est délibéré. Créer un contact ou un besoin remplace ce qu'on regardait : le
 * panneau latéral occupe alors le bord de l'écran. Consigner une activité (une note, un
 * appel, un e-mail, une tâche) se fait au contraire *en regardant* la fiche : le dernier
 * échange, le besoin en cours, le TJM. La fenêtre se pose donc en bas, laisse la fiche
 * lisible, se réduit sans rien perdre et s'agrandit pour relire.
 *
 * Rien n'est dupliqué : le chargement, la soumission en arrière-plan, le repli en page
 * pleine et la garde du brouillon sont ceux du panneau latéral. Seul l'ancrage change.
 */
.crm-drawer.is-dock {
    top: auto;
    right: 1.25rem;
    bottom: 0;
    width: min(40rem, calc(100vw - 2.5rem));
    /*
     * La hauteur se déclare par écran, et 34 rem n'est que le défaut.
     *
     * Les cinq écrans d'activité partagent cette fenêtre, et ils n'ont pas le même besoin : une
     * note de trois lignes tient, un e-mail non, à 34 rem, une fois retirés la barre de titre,
     * l'avertissement Google, la rangée d'outils, les trois en-têtes, la barre de mise en forme
     * et la barre d'envoi, il restait 155 px de zone d'écriture, soit six lignes. On
     * agrandissait donc la fenêtre à chaque e-mail un peu long, ce qui est précisément le geste
     * que la hauteur par défaut devrait épargner.
     *
     * `--crm-dock-height` est posée par `initDrawer` depuis `window_dock_height`. Une variable
     * et non un style en ligne : celui-ci l'aurait emporté sur `.is-minimized` et
     * `.is-expanded`, et les deux boutons de la barre de titre n'auraient plus rien changé.
     *
     * Le plafond reste relatif à la fenêtre du navigateur : sur un écran court c'est
     * `100vh - 5rem` qui décide, et le corps du message défile derrière sa barre d'envoi
     * collante plutôt que d'être écrasé.
     */
    height: min(var(--crm-dock-height, 34rem), calc(100vh - 5rem));
    border-bottom: 0;
    border-radius: var(--crm-radius-lg) var(--crm-radius-lg) 0 0;
    box-shadow: 0 -4px 40px rgba(22, 28, 38, .22);
    transform: translateY(100%);
    transition: transform 220ms cubic-bezier(.32, .72, 0, 1), height 200ms cubic-bezier(.32, .72, 0, 1);
}
.crm-drawer.is-dock.is-open { transform: translateY(0); }

/*
 * Réduite : la barre de titre **reste**, seul le corps est masqué.
 *
 * Elle masquait `.crm-drawer-pane`, qui contient la barre de titre elle-même : il ne restait
 * qu'un rectangle blanc de 3 rem, sans titre, sans bouton d'agrandissement et sans croix. La
 * fenêtre était donc **irrécupérable** au clic, et la seule sortie était Échap, qui ferme au
 * lieu de rouvrir : on perdait la saisie pour avoir voulu la mettre de côté.
 *
 * La hauteur suit la barre de titre au lieu d'être fixée à 3 rem : celle-ci fait 1 rem de
 * retrait plus sa ligne, et un nombre écrit à la main aurait rogné son contenu au premier
 * changement de retrait.
 */
.crm-drawer.is-dock.is-minimized { height: auto; }
.crm-drawer.is-dock.is-minimized .crm-drawer-body { display: none; }

/*
 * Réduite, la barre de titre annonce qu'elle se rouvre.
 *
 * Le corps masqué, elle est le seul élément cliquable de la fenêtre : elle doit donc se
 * comporter comme un bouton, et non comme la poignée de déplacement qu'elle est le reste du
 * temps. Le curseur le dit, et les coins restent arrondis en bas puisqu'il n'y a plus rien
 * en dessous.
 */
.crm-drawer.is-dock.is-minimized .crm-drawer-head {
    cursor: pointer;
    /*
     * Le retrait se serre : la barre de titre d'une fenêtre ouverte peut respirer, une barre
     * réduite est une languette. À 1 rem de retrait elle faisait 66 px de haut pour une ligne
     * de texte, soit plus que la barre supérieure du CRM, et une fenêtre « réduite » aussi
     * haute qu'un bandeau ne se lit pas comme quelque chose qu'on a mis de côté.
     */
    padding: .55rem .75rem .55rem 1rem;
    /* Les coins du bas sont contre le bord de l'écran : les arrondir ne se voit pas. */
    border-radius: var(--crm-radius-lg) var(--crm-radius-lg) 0 0;
}
.crm-drawer.is-dock.is-minimized .crm-drawer-head:hover { background: var(--crm-slate-700); }

/*
 * Agrandie : centrée et presque plein écran, pour un long message. On joue sur `left` et
 * `right` plutôt que sur une translation, qui entrerait en conflit avec celle de
 * l'ouverture.
 */
.crm-drawer.is-dock.is-expanded {
    left: 1.5rem;
    right: 1.5rem;
    bottom: 2rem;
    width: auto;
    max-width: 62rem;
    height: calc(100vh - 4rem);
    margin: 0 auto;
    border-bottom: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
}

/*
 * En bas, la barre de titre est sombre : elle se lit comme la poignée d'une fenêtre posée
 * sur l'écran. Sur le bord droit, elle reste claire : le panneau y prolonge la page.
 */
.crm-drawer.is-dock > .crm-drawer-form > .crm-drawer-pane > .crm-drawer-head,
.crm-drawer.is-dock .crm-drawer-head {
    background: var(--crm-slate-800);
    border-bottom-color: transparent;
    border-radius: var(--crm-radius-lg) var(--crm-radius-lg) 0 0;
}
.crm-drawer.is-dock.is-expanded .crm-drawer-head { border-radius: var(--crm-radius-lg) var(--crm-radius-lg) 0 0; }
.crm-drawer.is-dock .crm-drawer-title { color: #fff; }
.crm-drawer.is-dock .crm-drawer-title .fas,
.crm-drawer.is-dock .crm-drawer-title .far { color: var(--crm-slate-400); }
.crm-drawer.is-dock .crm-drawer-close { color: var(--crm-slate-300); }
.crm-drawer.is-dock .crm-drawer-close:hover { background: rgba(255, 255, 255, .14); border-color: transparent; color: #fff; }

/*
 * La barre de titre d'une fenêtre posée en bas sert de poignée : elle se saisit et se
 * déplace. Le curseur l'annonce, et les pointillés à gauche donnent l'affordance : une
 * zone déplaçable sans marque visible ne se découvre jamais.
 */
.crm-drawer.is-dock .crm-drawer-head { cursor: grab; user-select: none; }
.crm-drawer.is-dock.is-moving .crm-drawer-head { cursor: grabbing; }

/* Pendant le déplacement, aucune transition : la fenêtre doit coller au curseur. */
.crm-drawer.is-moving { transition: none; }

.crm-drawer-grip {
    display: none;
    flex: 0 0 auto;
    margin-right: .1rem;
    color: var(--crm-slate-500);
    font-size: .8rem;
}
.crm-drawer.is-dock .crm-drawer-grip { display: inline-block; }
.crm-drawer.is-dock .crm-drawer-head:hover .crm-drawer-grip { color: var(--crm-slate-300); }

/* Réduire et agrandir n'ont de sens que pour une fenêtre posée en bas. */
.crm-drawer-dockbtn { display: none; }
.crm-drawer.is-dock .crm-drawer-dockbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 2.1rem;
    height: 2.1rem;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--crm-radius);
    background: transparent;
    color: var(--crm-slate-300);
    font-size: .78rem;
    transition: all var(--crm-ease);
}
.crm-drawer.is-dock .crm-drawer-dockbtn:hover { background: rgba(255, 255, 255, .14); color: #fff; }

@media (max-width: 575.98px) {
    .crm-drawer.is-dock,
    .crm-drawer.is-dock.is-expanded {
        left: 0;
        right: 0;
        bottom: 0;
        width: 100vw;
        max-width: none;
        height: 100vh;
        margin: 0;
        border-radius: 0;
    }
}

/* ------------------------------------------------------------------ Champs d'e-mail */

/*
 * Rangée d'outils de la fenêtre d'e-mail, sous la barre de titre. Le sélecteur de modèles
 * s'y trouve parce que c'est avant d'écrire qu'on choisit un modèle : le mettre en pied de
 * fenêtre le proposait une fois le message rédigé, donc trop tard.
 */
/*
 * Rangée d'outils : de vrais boutons, sur le fond de la fenêtre.
 *
 * Elle a été deux fois trop discrète. Bandeau gris et icônes d'abord : le fond en faisait un
 * en-tête de section, donc un titre pour les champs qui suivent, ce qu'elle n'est pas. Puis du
 * texte nu, relevé sur le portail : « Modèles » et « Gérer » ne se distinguaient plus d'une
 * légende, et rien ne disait qu'on pouvait cliquer.
 *
 * Ce sont des boutons discrets : contour, fond de surface, hauteur de contrôle. Le portail s'en
 * passe parce que sa rangée en porte cinq et qu'elles se lisent alors comme une barre ; deux
 * mots isolés, eux, ont besoin de leur contour pour exister.
 */
.crm-composer-tools {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .6rem 1.1rem;
    background: transparent;
    border-bottom: 1px solid var(--crm-border-soft);
}

.crm-composer-tool {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .35rem .75rem;
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    background: var(--crm-surface);
    color: var(--crm-text);
    font-size: .8rem;
    font-weight: 500;
    line-height: 1.35;
    text-decoration: none;
    transition: border-color var(--crm-ease), background var(--crm-ease), color var(--crm-ease);
}

.crm-composer-tool:hover {
    border-color: var(--crm-primary);
    background: var(--crm-primary-soft);
    color: var(--crm-primary);
    text-decoration: none;
}
.crm-composer-tool .fas,
.crm-composer-tool .far { font-size: .75rem; color: var(--crm-text-faint); }
.crm-composer-tool:hover .fas,
.crm-composer-tool:hover .far { color: var(--crm-primary); }

/* Le compte de modèles, en pastille : c'est une indication, mais on veut la lire. */
.crm-composer-tool-count {
    padding: 0 .35rem;
    font-size: .7rem;
    font-weight: 600;
    color: var(--crm-text-muted);
    background: var(--crm-border-soft);
    border-radius: var(--crm-radius-sm);
}

/*
 * En-têtes du message : une ligne par champ, et **chaque champ se voit**.
 *
 * Ils étaient des lignes de texte séparées par des filets, sur le modèle d'une messagerie : rien
 * ne distinguait une valeur saisie d'une valeur affichée, et l'on ne savait pas où cliquer pour
 * corriger le destinataire. Le seul champ encadré était l'objet, ce qui laissait croire que
 * c'était le seul modifiable.
 *
 * Chaque valeur modifiable porte donc son contour, sa hauteur de contrôle et sa bague de mise au
 * point. Le « De », qui n'est pas modifiable, reste du texte : c'est ainsi qu'on voit d'un coup
 * d'œil ce qui se change et ce qui ne se change pas.
 */
.crm-composer-headers {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: .4rem;
    padding: .7rem 1.1rem;
    border-bottom: 1px solid var(--crm-border);
}

.crm-composer-field {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: 0;
}

.crm-composer-label {
    flex: 0 0 3rem;
    margin: 0;
    font-size: .78rem;
    font-weight: 600;
    color: var(--crm-text-muted);
    text-align: right;
}

.crm-composer-input {
    flex: 1 1 auto;
    min-width: 0;
    height: 2.4rem;
    padding: .45rem .7rem;
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    background: var(--crm-surface);
    font-size: .875rem;
    color: var(--crm-text);
    transition: border-color var(--crm-ease), box-shadow var(--crm-ease);
}

/*
 * La bague de mise au point est celle des autres champs du CRM.
 *
 * L'objet reçoit le curseur à l'ouverture (`initDrawer`) : c'est **elle** qui le désigne
 * désormais, et non un contour que ses voisins n'auraient pas. Un champ encadré au milieu de
 * champs nus disait « celui-ci se remplit », et donc, à tort, « les autres non ».
 */
.crm-composer-input:focus {
    outline: none;
    border-color: var(--crm-primary);
    box-shadow: 0 0 0 3px var(--crm-primary-soft);
}
.crm-composer-input::placeholder { color: var(--crm-text-faint); }

/*
 * Le « De » ne se change pas : pas de contour, et l'adresse en gris derrière son nom.
 *
 * Il prend en revanche la **hauteur** et le **retrait** d'un champ. Sans la hauteur, sa ligne
 * était trois pixels plus courte que ses voisines et cassait la trame ; sans le retrait, son
 * texte commençait douze pixels à gauche des valeurs saisies : la bordure et le rembourrage des
 * champs encadrés décalent les leurs, et c'est le texte qui doit s'aligner, pas la boîte.
 */
.crm-composer-from {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: .35rem;
    height: 2.4rem;
    padding: 0 0 0 calc(.7rem + 1px);
    font-size: .875rem;
    color: var(--crm-slate-700, var(--crm-text));
}

/* Le portail écrit « Nom (adresse) », l'adresse en gris : c'est le nom qu'on relit. */
.crm-composer-from-mail { color: var(--crm-text-faint); font-size: .8rem; }

/*
 * « Cc » est au **bout** de la ligne De, comme sur le portail : pas accolé à l'adresse.
 *
 * Accolé, sa position dépendait de la longueur du nom de l'expéditeur : il se déplaçait d'un
 * utilisateur à l'autre, et se lisait comme une parenthèse de l'adresse plutôt que comme un
 * bouton. Au bout de la ligne, il ne bouge plus et ne pousse jamais le destinataire vers la
 * gauche : la raison pour laquelle il est sur cette ligne-là et non sur celle du « À ».
 */
.crm-composer-cc-toggle {
    flex: 0 0 auto;
    margin-left: auto;
    padding: .3rem .6rem;
    border: 1px solid transparent;
    border-radius: var(--crm-radius);
    background: transparent;
    color: var(--crm-primary);
    font-size: .78rem;
    font-weight: 600;
}
.crm-composer-cc-toggle:hover {
    background: var(--crm-primary-soft);
    border-color: var(--crm-primary);
}

/* Le corps du message prend toute la hauteur restante : c'est lui qu'on écrit. */
.crm-composer-editor {
    flex: 1 1 auto;
    min-height: 6rem;
    width: 100%;
    border: 0;
    resize: none;
    padding: .85rem .9rem;
    font-size: .875rem;
    line-height: 1.6;
    color: var(--crm-text);
}
.crm-composer-editor:focus { outline: none; box-shadow: none; }

/*
 * … mais c'est l'éditeur riche qu'il faut étirer, pas le champ.
 *
 * Summernote masque le `<textarea>` (`display: none`) et affiche son propre bloc à côté :
 * le `flex` ci-dessus ne s'appliquait donc à rien de visible, et le message gardait la
 * hauteur passée à l'appel : 220 px. En fenêtre agrandie cela laissait 158 px de blanc sous
 * la barre d'envoi : on agrandit la fenêtre, et la zone d'écriture ne bouge pas.
 *
 * Portée limitée à `crm-drawer-body-fill`, c'est-à-dire aux écrans qui réclament une hauteur
 * répartie. L'éditeur de modèles d'e-mail, lui, vit dans une fenêtre à deux colonnes dont
 * l'aperçu décide de la hauteur : l'y étirer ferait défiler deux zones au lieu d'une.
 */
.crm-drawer-body-fill .note-editor {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.crm-drawer-body-fill .note-editor .note-editing-area {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* La hauteur est écrite **en ligne** par Summernote : seule une règle appuyée la reprend. */
.crm-drawer-body-fill .note-editor .note-editable {
    flex: 1 1 auto;
    height: auto !important;
    /* Plancher : sur une fenêtre courte, mieux vaut faire défiler le corps que réduire la
       zone d'écriture à une ligne et demie. */
    min-height: 8rem;
    overflow-y: auto;
}

/*
 * La poignée de redimensionnement de Summernote n'a plus d'objet quand la hauteur suit la
 * fenêtre, et tirer dessus reprenait la main sur le calcul, ramenant le blanc mort.
 */
.crm-drawer-body-fill .note-editor .note-statusbar { display: none; }

/*
 * La mise en forme passe **sous** le corps du message.
 *
 * C'est l'écart le plus visible avec le portail, et il a une raison : une barre d'outils en tête
 * de zone de saisie fait lire l'e-mail comme un formulaire à remplir ; la même barre en pied le
 * fait lire comme un message qu'on écrit. Summernote rend `[barre, zone, statut]` :
 * `column-reverse` suffit, la zone de statut étant déjà masquée plus haut.
 *
 * ## Pourquoi ces règles-ci portent sur `[data-crm-composer]` et non sur la classe du volet
 *
 * `crm-drawer-body-fill` n'est posée que par la **fenêtre** : la page pleine, qui est le recours
 * et rend pourtant le même gabarit, n'en hérite pas. Toute la présentation reprise du portail (* barre en bas, outils dépouillés) s'y perdait donc, et l'on retombait sur le Summernote nu,
 * barre en tête et boutons Bootstrap. Ce que le CRM déclarait le contraire : « les deux ne
 * peuvent pas diverger ».
 *
 * La répartition de hauteur, elle, reste sur la classe du volet : elle dépend d'une chaîne de
 * conteneurs en colonne que la page pleine n'a pas.
 */
[data-crm-composer] .note-editor {
    display: flex;
    flex-direction: column-reverse;
    /* Summernote laisse 20 px sous son cadre. Entre la barre de mise en forme et la barre
       d'envoi, cela faisait une bande vide que rien ne justifiait, et qui séparait deux
       rangées qui se lisent ensemble. */
    margin-bottom: 0;
}
/*
 * La barre est une **rangée**, pas un bloc.
 *
 * Summernote la rend en `display: block` : les compléments qu'on y dépose, le menu « Insérer »
 * et l'état de rattachement, s'y posaient donc à la suite des outils, et le `margin-left: auto`
 * qui devait renvoyer le rattachement au bout de la rangée ne s'appliquait à rien. Il finissait
 * au milieu, collé aux outils, alors que le portail le met à droite, là où l'œil vérifie sur
 * quelle fiche l'e-mail sera consigné avant d'appuyer sur Envoyer.
 */
[data-crm-composer] .note-editor .note-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .3rem 0;
    border-bottom: 0;
    border-top: 1px solid var(--crm-border);
    background: transparent;
    padding: .55rem 1.1rem;
}

/*
 * La zone d'écriture s'aligne sur les en-têtes : le message ne doit pas commencer plus à gauche
 * que l'objet qu'il porte.
 *
 * Et son **plancher** est plus haut que celui des autres écrans à hauteur répartie (8 rem) :
 * une note se relit en trois lignes, un e-mail s'écrit. En dessous de onze lignes on ne voit
 * plus son paragraphe précédent en tapant le suivant. Sur une fenêtre trop courte pour le
 * tenir, c'est le corps de la fenêtre qui défile : la barre d'envoi étant collante, elle reste
 * visible.
 */
[data-crm-composer] .note-editor .note-editable {
    padding: .9rem 1.1rem;
    min-height: 11rem;
}

/*
 * Les deux règles de partage de hauteur du sélecteur de modèles ont été retirées.
 *
 * Elles réduisaient le plancher de la zone d'écriture et donnaient un plancher à l'éditeur
 * quand la classe `is-picking` était posée, parce que le sélecteur était un panneau **sous** le
 * message et que les deux se disputaient la hauteur de la fenêtre. Le sélecteur est passé en
 * surcouche : il recouvre le message au lieu de le comprimer, il n'y a plus rien à partager, et
 * garder ces règles aurait laissé deux réglages sans cause à comprendre plus tard.
 */

/*
 * La barre de mise en forme ne s'écrase jamais.
 *
 * Rien ne la protégeait : à l'ouverture du panneau, elle passait de 50 px à 18, ses boutons
 * rognés par le haut et par le bas, à cheval sur la ligne au-dessous. Une barre d'outils à
 * moitié coupée se lit comme un défaut d'affichage, et c'en était un.
 */
[data-crm-composer] .note-editor .note-toolbar { flex: 0 0 auto; }
[data-crm-composer] .note-editor .note-editing-area { min-height: 0; }

/*
 * La barre d'envoi : le geste principal se voit comme tel.
 *
 * « Envoyer » avait la taille d'un bouton de formulaire ordinaire, au milieu d'une rangée où
 * tout est de la même hauteur : la case de suivi, le menu d'échéance. C'est pourtant le seul
 * élément de l'écran qui soit irréversible, et le seul qu'on cherche des yeux en ayant fini
 * d'écrire.
 */
[data-crm-composer] .crm-sticky-actions { padding: .9rem 1.1rem; }
[data-crm-composer] .crm-sticky-actions .btn-primary {
    padding: .5rem 1.3rem;
    font-weight: 600;
}

/* Le menu d'échéance est un contrôle, pas une légende : il garde sa hauteur et son contour. */
[data-crm-composer] .crm-followup-delay select { height: 2.4rem; }

/*
 * Les outils : des boutons carrés, détachés les uns des autres.
 *
 * Deux excès à éviter, et le réglage est entre les deux. Summernote les rend en `.btn` groupés
 * en **segments accolés** aux angles arrondis : quinze outils ainsi habillés faisaient 347 px de
 * barre d'application, et les segments donnaient à lire des blocs plutôt que des outils. Les
 * dépouiller entièrement (glyphes nus, sans fond ni contour) les rendait à l'inverse
 * indistinguables du texte : on ne voyait plus qu'il y avait des boutons.
 *
 * Chacun garde donc son contour et son fond, mais sur une cible carrée de 2 rem, détachée de sa
 * voisine. C'est aussi ce qui rend l'état actif lisible (gras, italique) qu'un fond gris seul
 * ne distinguait pas du survol.
 *
 * Réservé au composeur : l'éditeur de modèles d'e-mail et les notes gardent la barre habituelle.
 */
[data-crm-composer] .note-toolbar .note-btn {
    min-width: 2rem;
    height: 2rem;
    padding: 0 .45rem;
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    background: var(--crm-surface);
    box-shadow: none;
    color: var(--crm-text-muted);
    transition: border-color var(--crm-ease), background var(--crm-ease), color var(--crm-ease);
}
[data-crm-composer] .note-toolbar .note-btn:hover,
[data-crm-composer] .note-toolbar .note-btn:focus {
    border-color: var(--crm-primary);
    background: var(--crm-primary-soft);
    color: var(--crm-primary);
    box-shadow: none;
}

/* L'outil en cours porte la couleur pleine : on doit savoir qu'on écrit en gras. */
[data-crm-composer] .note-toolbar .note-btn.active {
    border-color: var(--crm-primary);
    background: var(--crm-primary);
    color: #fff;
    box-shadow: none;
}

/* Les segments sont défaits : chaque outil est une cible, pas un morceau de bloc. */
[data-crm-composer] .note-toolbar .note-btn-group {
    display: inline-flex;
    gap: .25rem;
    margin: 0 .55rem 0 0;
    box-shadow: none;
}

/*
 * Compléments de cette barre : le menu « Insérer » et l'état de rattachement.
 *
 * `initComposerFields()` déplace ce bloc dans la barre de Summernote pour n'avoir qu'une rangée.
 * Les styles tiennent dans les deux cas : dans la barre, ou resté à sa place si le déplacement
 * échoue : deux rangées serrées valent mieux qu'un bouton disparu.
 */
.crm-composer-extras {
    display: inline-flex;
    align-items: center;
    gap: .75rem;
    flex: 1 1 auto;
    min-width: 0;
    padding: 0 .25rem;
}

/* Poussé à droite : le portail met l'état de rattachement au bout de la rangée. */
.crm-composer-assoc {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: .76rem;
    color: var(--crm-text-muted);
}
.crm-composer-assoc .fas { font-size: .7rem; color: var(--crm-text-faint); }

.crm-composer-insert { position: relative; flex: 0 0 auto; }

/*
 * Le menu s'ouvre **vers le haut** : la barre est en pied de fenêtre, un menu descendant
 * sortirait sous le bord bas et ne serait pas atteignable.
 */
.crm-composer-insert-menu {
    position: absolute;
    bottom: calc(100% + .4rem);
    left: 0;
    z-index: 20;
    min-width: 13rem;
    padding: .3rem;
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    background: var(--crm-surface);
    box-shadow: var(--crm-shadow-lg);
}
.crm-composer-insert-item {
    display: flex;
    align-items: center;
    gap: .5rem;
    width: 100%;
    padding: .4rem .55rem;
    border: 0;
    border-radius: var(--crm-radius-sm);
    background: transparent;
    color: var(--crm-text);
    font-size: .82rem;
    text-align: left;
}
.crm-composer-insert-item:hover { background: var(--crm-primary-soft); color: var(--crm-primary); }
.crm-composer-insert-item .fas,
.crm-composer-insert-item .far { width: 1rem; color: var(--crm-text-faint); }
.crm-composer-insert-item:hover .fas,
.crm-composer-insert-item:hover .far { color: var(--crm-primary); }

/* Bouton de fermeture du sélecteur de modèles. */
.crm-template-close {
    flex: 0 0 auto;
    width: 1.85rem;
    height: 1.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--crm-radius-sm);
    background: transparent;
    color: var(--crm-text-muted);
    font-size: .78rem;
    transition: all var(--crm-ease);
}
.crm-template-close:hover { background: var(--crm-slate-100); color: var(--crm-slate-900); }

.crm-composer-foot {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .65rem .9rem;
    background: var(--crm-slate-50);
    border-top: 1px solid var(--crm-border);
}
.crm-composer-hint {
    font-size: .72rem;
    color: var(--crm-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ------------------------------------------------------------------ Tâche de suivi */

/*
 * Case de suivi en pied de fenêtre. L'échéance reste en retrait tant que la case n'est pas
 * cochée : proposer un délai pour une tâche qu'on ne crée pas ajoute du bruit à un pied de
 * fenêtre déjà chargé.
 */
.crm-followup {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    font-size: .8rem;
    color: var(--crm-slate-600);
}
.crm-followup .custom-control-label { font-size: .8rem; }

.crm-followup-delay {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    margin: 0;
    opacity: .45;
    transition: opacity var(--crm-ease);
}
.crm-followup-delay select { width: auto; min-width: 9.5rem; }
.crm-followup-label { font-size: .8rem; font-weight: 500; color: var(--crm-text-muted); }

/* La classe est posée par le navigateur quand la case est cochée. */
.crm-followup.is-active .crm-followup-delay { opacity: 1; }

/* ------------------------------------------------------------------ Modèles d'e-mails */

/*
 * Sélecteur de modèles ouvert en panneau au-dessus de la barre d'outils, avec recherche.
 * Une liste déroulante convenait à cinq modèles ; passé vingt, on ne trouve plus rien.
 */
/*
 * Le sélecteur est une **surcouche**, il ne partage plus la hauteur du message.
 *
 * Il était un panneau sous le corps du mail, et deux choses en découlaient. La première est
 * qu'on ne le trouvait pas : on cherche un modèle avant d'écrire, le regard est alors en haut
 * de la fenêtre, et la liste s'ouvrait à l'autre bout. La seconde est un partage de hauteur
 * délicat, qui a coûté trois réglages : le panneau refusait de rétrécir et réclamait 60 % de la
 * fenêtre, tout le manque retombait sur l'éditeur, sa barre de mise en forme tombait de 50 px à
 * 18 et venait chevaucher la ligne de recherche, pendant que la zone d'écriture gardait son
 * plancher et débordait par-dessous.
 *
 * En surcouche, ce problème n'existe pas : elle recouvre le message au lieu de le comprimer,
 * donc il n'y a plus rien à partager, et la classe `is-picking` qui organisait ce partage a
 * disparu avec lui. C'est le bon genre de correction : celle qui retire du réglage.
 *
 * Le fond assombri porte la fermeture au clic, la boîte l'arrête : d'où deux éléments.
 */
.crm-template-panel {
    position: absolute;
    inset: 0;
    z-index: 6;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    /* Le retrait du haut dégage la barre de titre de la fenêtre : on voit d'où l'on vient. */
    padding: 3rem 1rem 1.25rem;
    background: rgba(22, 28, 38, .38);
}
.crm-template-panel[hidden] { display: none; }

/*
 * La boîte, dimensionnée pour une liste et pas pour un formulaire.
 *
 * 34 rem : les modèles portent un nom court et un objet, et une boîte plus large étalerait
 * chaque ligne en ruban. C'est le même raisonnement que la largeur déclarée des fenêtres
 * centrées, qui prenaient celle du plus large de leurs écrans.
 */
.crm-template-dialog {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 34rem;
    max-height: 100%;
    background: var(--crm-surface);
    border-radius: var(--crm-radius-lg);
    box-shadow: 0 18px 48px rgba(22, 28, 38, .28);
    overflow: hidden;
}

/*
 * La surcouche se place par rapport au composeur, pas à la page.
 *
 * Sans cet ancrage, `inset: 0` remonterait au premier parent positionné, qui est le volet ou le
 * document : la boîte se centrerait sur l'écran entier et le fond assombri recouvrirait la
 * fiche derrière la fenêtre, alors que la voir est la raison de cette fenêtre.
 */
[data-crm-composer] .crm-drawer-card { position: relative; }

.crm-template-panel-head {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .6rem .5rem .9rem;
    border-bottom: 1px solid var(--crm-border-soft);
}
.crm-template-panel-head .crm-composer-btn { color: var(--crm-text-muted); }
.crm-template-panel-head .crm-composer-btn:hover { background: var(--crm-slate-100); color: var(--crm-slate-900); }

.crm-template-search { flex: 1 1 auto; display: flex; align-items: center; gap: .5rem; }
.crm-template-search .fas { color: var(--crm-text-faint); font-size: .8rem; }
.crm-template-search input {
    flex: 1 1 auto;
    border: 0;
    background: transparent;
    font-size: .85rem;
    padding: .3rem 0;
}
.crm-template-search input:focus { outline: none; }

.crm-template-list { flex: 1 1 auto; overflow-y: auto; padding: .35rem; scrollbar-width: thin; }

.crm-template-group[hidden] { display: none; }
.crm-template-group-label {
    padding: .5rem .55rem .25rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--crm-text-faint);
}

.crm-template-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: .45rem .55rem;
    border: 1px solid transparent;
    border-radius: var(--crm-radius-sm);
    background: transparent;
    transition: all var(--crm-ease);
}
.crm-template-item:hover,
.crm-template-item:focus {
    background: var(--crm-primary-soft);
    border-color: rgba(47, 91, 234, .3);
    outline: none;
}
.crm-template-item[hidden] { display: none; }

.crm-template-item-name {
    display: block;
    font-size: .84rem;
    font-weight: 600;
    color: var(--crm-slate-800);
}
.crm-template-item-name .fas { font-size: .65rem; color: var(--crm-text-faint); margin-left: .25rem; }
.crm-template-item-subject {
    display: block;
    font-size: .75rem;
    color: var(--crm-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.crm-template-empty { padding: 1.5rem 1rem; text-align: center; color: var(--crm-text-muted); }
.crm-template-empty[hidden] { display: none; }

@media (max-width: 575.98px) {
    .crm-composer,
    .crm-composer.is-expanded {
        right: 0;
        bottom: 0;
        transform: none;
        width: 100vw;
        height: 100vh;
        border-radius: 0;
    }
}

/* ================================================================== Badges et pastilles */

.badge {
    font-weight: 600;
    font-size: .72rem;
    padding: .3rem .5rem;
    border-radius: var(--crm-radius-sm);
    letter-spacing: .01em;
}

.badge-light {
    background: var(--crm-slate-100);
    color: var(--crm-slate-700);
    border: 1px solid var(--crm-border) !important;
    font-weight: 500;
}
.badge-secondary { background: var(--crm-slate-500); }
.badge-primary   { background: var(--crm-primary); }
.badge-success   { background: var(--crm-success); }
.badge-danger    { background: var(--crm-danger); }
.badge-warning   { background: var(--crm-warning-soft); color: var(--crm-warning); border: 1px solid rgba(150, 96, 26, .25); }
.badge-info      { background: var(--crm-info); color: #fff; }
.badge-dark      { background: var(--crm-slate-800); }

/* Pastille de condition ou de méta-donnée : bordure fine, fond très clair. */
.crm-chip {
    display: inline-flex;
    align-items: center;
    gap: .28rem;
    padding: .18rem .45rem;
    font-size: .74rem;
    font-weight: 500;
    line-height: 1.35;
    border-radius: var(--crm-radius-sm);
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border);
    color: var(--crm-slate-600);
    white-space: nowrap;
}
.crm-chip .fas, .crm-chip .far { font-size: .65rem; color: var(--crm-text-faint); }
.crm-chip-warning { background: var(--crm-warning-soft); border-color: rgba(150, 96, 26, .25); color: var(--crm-warning); }
.crm-chip-warning .fas { color: var(--crm-warning); }
.crm-chip-info { background: var(--crm-info-soft); border-color: rgba(31, 127, 156, .25); color: var(--crm-info); }
.crm-chip-info .fas { color: var(--crm-info); }
.crm-chip-success { background: var(--crm-success-soft); border-color: rgba(18, 133, 95, .25); color: var(--crm-success); }
.crm-chip-success .fas { color: var(--crm-success); }
.crm-chip-primary { background: var(--crm-primary-soft); border-color: rgba(47, 91, 234, .25); color: var(--crm-primary-dark); }
.crm-chip-primary .fas { color: var(--crm-primary); }
.crm-chip-danger { background: var(--crm-danger-soft); border-color: rgba(207, 48, 64, .25); color: var(--crm-danger); }
.crm-chip-danger .fas { color: var(--crm-danger); }

/* ------------------------------------------------------------------ Styles d'option */

/*
 * Présentation d'une valeur de liste, dans les deux styles colorés de HubSpot.
 *
 * Le point est volontairement discret : il sert à comparer des lignes entre elles, pas à
 * attirer l'œil. Le badge, lui, doit se voir avant qu'on lise : il est réservé aux valeurs
 * qui qualifient la fiche entière.
 */
.crm-option-dot { display: inline-flex; align-items: center; gap: .4rem; white-space: nowrap; }
.crm-option-bullet {
    flex: 0 0 auto;
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}

.crm-option-badge {
    display: inline-block;
    padding: .12rem .45rem;
    border-radius: var(--crm-radius-sm);
    color: #fff;
    font-size: .74rem;
    font-weight: 600;
    line-height: 1.45;
    white-space: nowrap;
    /* La couleur venant du champ peut être claire : un liseré garde la lisibilité. */
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1);
}

/* Groupe de pastilles qui passe à la ligne proprement dans une cellule. */
.crm-chip-set { display: flex; flex-wrap: wrap; gap: .25rem; }

/* ================================================================== Alertes */

.alert {
    border: 1px solid transparent;
    border-radius: var(--crm-radius);
    padding: .8rem 1rem;
    font-size: .875rem;
    box-shadow: none;
}
.alert-success { background: var(--crm-success-soft); border-color: rgba(18, 133, 95, .25); color: #0b5f44; }
.alert-danger  { background: var(--crm-danger-soft);  border-color: rgba(207, 48, 64, .25);  color: #96222e; }
.alert-warning { background: var(--crm-warning-soft); border-color: rgba(150, 96, 26, .25);  color: #7a4d14; }
.alert-info    { background: var(--crm-info-soft);    border-color: rgba(31, 127, 156, .25); color: #175f75; }

/*
 * Un lien dans un bandeau était **invisible**, partout dans le CRM.
 *
 * AdminLTE pose `.alert a { color: #fff }`, ce qui est juste pour ses propres bandeaux, dont le
 * fond est saturé. Les quatre variantes ci-dessus les ont repeints en fond très clair avec un
 * texte foncé, sans toucher au lien : « Droits et périmètres » s'affichait donc en blanc sur
 * #e6f4f8, mesuré à 122 px de large et parfaitement illisible. Huit gabarits sont concernés,
 * dont `contact/show` et le composeur d'e-mail, c'est-à-dire les deux écrans les plus vus.
 *
 * Rien ne le signalait : le texte est bien dans le DOM, la largeur est juste, et une relecture
 * du gabarit ne montre qu'un `<a>` ordinaire. C'est la quatrième fois que ce dépôt paie une
 * règle venue d'ailleurs, après `.crm-composer-tool`, `.navbar-badge` battue par `.badge`, et
 * `.crm-doc-guides` réemployée par deux fonctions.
 *
 * `inherit` plutôt qu'une couleur : le lien prend celle de sa variante, donc le vert du succès
 * et le rouge du danger, sans quatre règles à tenir d'accord. Le soulignement fait le reste du
 * travail, un lien de la même couleur que son texte ne se signalant plus autrement. Et pas
 * besoin d'`!important` : `crm.css` est chargée après AdminLTE, à spécificité égale.
 */
.alert a { color: inherit; text-decoration: underline; font-weight: 600; }
.alert a:hover, .alert a:focus { color: inherit; text-decoration: none; }

.callout {
    border-radius: var(--crm-radius);
    border-left-width: 4px;
    box-shadow: none;
    background: var(--crm-slate-50);
    padding: .9rem 1.1rem;
}
.callout.callout-info { border-left-color: var(--crm-info); background: var(--crm-info-soft); }
.callout.callout-warning { border-left-color: var(--crm-warning); background: var(--crm-warning-soft); }
.callout.callout-danger { border-left-color: var(--crm-danger); background: var(--crm-danger-soft); }

/* ================================================================== Avatars */

.crm-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    color: #fff;
    font-size: .75rem;
    font-weight: 600;
    line-height: 1;
    flex-shrink: 0;
    text-transform: uppercase;
}

.crm-avatar-sm { width: 1.6rem; height: 1.6rem; font-size: .65rem; }
.crm-avatar-lg { width: 4rem;   height: 4rem;   font-size: 1.4rem; }

/* Pile d'avatars des contacts associés à une carte Kanban (§8.3.3). */
.crm-avatar-stack { display: inline-flex; }
.crm-avatar-stack .crm-avatar { margin-left: -.4rem; border: 2px solid #fff; }
.crm-avatar-stack .crm-avatar:first-child { margin-left: 0; }

/* Pastille portant une photo (§5.6.1).
   Le fond est posé en style en ligne par le gabarit commun ; ces trois lignes sont tout ce qui
   distingue une photo d'une couleur. `cover` recadre au centre, exactement comme le stockage
   l'a fait à l'enregistrement : le cadrage ne change donc pas entre l'aperçu et l'écran.
   La bague intérieure est là pour les photos claires, qui se fondaient dans le fond blanc d'une
   carte au point qu'on ne voyait plus le cercle. Elle est posée en ombre et non en bordure : une
   bordure aurait rogné l'image de deux pixels sur une pastille de vingt-six.
   Une classe à elle, et non `.crm-avatar.has-photo` : quatre classes de pastille cohabitent
   (`crm-avatar`, `crm-inbox-avatar`, `crm-inbox-item-owner`, `crm-turn-avatar`), et un
   sélecteur qui en nommerait une aurait laissé la photo du conseiller absente des trois autres,
   c'est-à-dire de la boîte de conversations. Un nom préfixé plutôt qu'un `has-photo` nu, qui
   se serait retrouvé un jour sur autre chose. */
.crm-avatar-photo {
    background-size: cover;
    background-position: center;
    box-shadow: inset 0 0 0 1px rgba(15, 23, 42, .08);
}

/* La ligne de réglage de la pastille : l'aperçu ne doit pas s'étirer à la hauteur des deux
   champs posés à côté de lui. */
.crm-avatar-settings > [data-crm-avatar-preview] { flex: 0 0 auto; }

/* Les deux contrôles de la pastille ne s'étirent pas sur toute la largeur de la carte : un
   sélecteur de fichier de mille pixels pour un bouton de deux mots est le défaut déjà payé sur
   les lignes de réglage rendues en ruban. */
.crm-avatar-settings > div { max-width: 34rem; }

/* Le choix du cadre d'une photo de profil (§5.6.1).
   La scène est un carré strict : c'est ce qui permet de poser l'image en pourcentages, donc
   sans mesurer quoi que ce soit, et de ne pas dépendre d'un panneau encore replié dont la
   largeur vaudrait zéro. `aspect-ratio` la tient, et la largeur est bornée pour qu'elle reste
   une vignette réglable et non un ruban de la largeur de la carte. */
.crm-crop {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: flex-start;
    padding: .75rem;
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    background: var(--crm-bg);
}

.crm-crop-stage {
    position: relative;
    width: 15rem;
    max-width: 100%;
    aspect-ratio: 1;
    flex: 0 0 auto;
    overflow: hidden;
    border-radius: var(--crm-radius);
    background: var(--crm-navy);
    cursor: grab;
    /* Le glisser ne doit pas être confondu avec un défilement tactile : sans cette ligne, le
       doigt fait défiler la page au lieu de déplacer la photo. */
    touch-action: none;
    user-select: none;
}

.crm-crop-stage:focus-visible { outline: 2px solid var(--crm-primary); outline-offset: 2px; }
.crm-crop-stage.is-dragging { cursor: grabbing; }

.crm-crop-stage img {
    position: absolute;
    max-width: none; /* le cadrage donne la largeur en pourcentage : la borne de Bootstrap la ramènerait à la scène */
    display: block;
    pointer-events: none; /* le pointeur travaille sur la scène, l'image ne l'intercepte pas */
}

/* Le disque montre ce qui sera gardé : la pastille est ronde partout ailleurs, et un cadre
   carré aurait promis les coins. Il ne prend pas le pointeur, sinon le glisser s'arrêterait
   au bord du cercle. */
.crm-crop-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    box-shadow: 0 0 0 9999px rgba(15, 23, 42, .45);
    border: 2px solid rgba(255, 255, 255, .9);
    pointer-events: none;
}

.crm-crop-controls { flex: 1 1 12rem; min-width: 11rem; }
.crm-crop-zoom { width: 100%; max-width: 16rem; }

/* ================================================================== Recherche globale */

.crm-global-search { min-width: 18rem; max-width: 32rem; flex: 1 1 auto; }
.crm-notification-title {
    display: inline-block;
    max-width: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

.dropdown-menu {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    box-shadow: var(--crm-shadow);
    padding: .35rem;
    font-size: .875rem;
}
.dropdown-item { border-radius: var(--crm-radius-sm); padding: .45rem .6rem; }
.dropdown-item:hover { background: var(--crm-slate-100); }
.dropdown-header {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--crm-text-muted);
}
.dropdown-divider { border-color: var(--crm-border-soft); }

/* ================================================================== Vue liste */

/*
 * Le tableau défile horizontalement quand les colonnes sont nombreuses (§5.2). Une liste
 * de contacts en compte facilement quinze : la barre de défilement fait donc partie de
 * l'interface, et la barre native de Windows y est un gros bloc gris. On l'affine.
 */
/*
 * Défilement horizontal d'une vue liste (§5.6).
 *
 * `width: max-content` est le point clé. Avec `min-width: 100%`, le tableau se comprimait
 * pour tenir dans la fenêtre : les colonnes s'écrasaient, le texte passait à la ligne, et le
 * défilement horizontal ne se déclenchait jamais, donc paraissait absent. Le tableau prend
 * désormais la largeur que ses colonnes réclament, et c'est le conteneur qui défile.
 */
/* ================================================================ Tableau de bord (§16.2) */

/*
 * Les widgets partagent un cadre unique : même en-tête, même respiration. Onze cartes dessinées
 * chacune à sa façon se lisaient comme onze écrans collés.
 *
 * C'est une **grille CSS** et non la rangée Bootstrap d'avant. Une colonne Bootstrap s'étire à
 * la hauteur de la plus haute de sa rangée, mais la carte qu'elle porte garde la sienne :
 * mesuré, la page laissait 261 px de blanc sous « Ce qui demande votre attention » et 141 px
 * sous « Répartition des contacts », dans la couleur du fond, sans que rien ne les explique.
 * Ici la cellule et la carte font la même hauteur : le vide résiduel est **dans** l'encart,
 * donc bordé, donc lu comme une marge et non comme un défaut d'affichage.
 */
.crm-dashboard {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 1rem;
    align-items: stretch;
}

.crm-dash-cell { display: flex; min-width: 0; }
.crm-dash-cell > * { flex: 1 1 auto; min-width: 0; }

/*
 * Les largeurs sont des douzièmes, comme au catalogue. Elles passent par des classes et non par
 * une propriété personnalisée : une portée de grille ne se borne pas en CSS (`span min(...)`
 * n'existe pas), et il faut donc pouvoir les réécrire toutes à un point de rupture.
 */
.crm-dash-cell.is-w4  { grid-column: span 4; }
.crm-dash-cell.is-w6  { grid-column: span 6; }
.crm-dash-cell.is-w8  { grid-column: span 8; }
.crm-dash-cell.is-w12 { grid-column: span 12; }

/* Entre 992 et 1200 px, la paire 8 + 4 devient deux moitiés : à quatre douzièmes, le fil
   d'activité tombe sous 300 px et ses libellés se replient sur trois rangs. */
@media (max-width: 1199.98px) {
    .crm-dash-cell.is-w4,
    .crm-dash-cell.is-w8 { grid-column: span 6; }
}

/*
 * Une requête de média ne gagne rien par elle-même : c'est la spécificité qui tranche. Écrite
 * `.crm-dash-cell`, cette règle perdait contre `.crm-dash-cell.is-w6`, et la page rendait deux
 * colonnes sur un téléphone, avec 47 px de débordement horizontal. Mesuré, pas déduit.
 */
@media (max-width: 991.98px) {
    .crm-dash-cell.is-w4,
    .crm-dash-cell.is-w6,
    .crm-dash-cell.is-w8,
    .crm-dash-cell.is-w12 { grid-column: span 12; }
}

/*
 * La carte est une colonne : en-tête fixe, corps extensible. C'est ce qui permet au pied
 * (« 12 affichés sur 47 ») de se coller en bas par `margin-top: auto` plutôt que de flotter au
 * milieu d'un encart plus haut que son contenu.
 */
.crm-widget {
    display: flex;
    flex-direction: column;
    height: 100%;
    margin-bottom: 0;
    border: 1px solid var(--crm-border);
    box-shadow: none;
    transition: border-color var(--crm-ease), box-shadow var(--crm-ease);
}

.crm-widget:hover { border-color: var(--crm-slate-300); box-shadow: var(--crm-shadow-sm); }

/*
 * Replié, l'encart retrouve sa hauteur naturelle et cesse de s'étirer.
 *
 * `height: 100%` est ce qui ferme les trous blancs quand l'encart est ouvert ; laissé en
 * place au repliement, il rendait une carte de 511 px au corps vide, c'est-à-dire l'inverse
 * exact de ce qu'on demande en repliant. Rien ne le signalait : AdminLTE fait bien glisser
 * le corps et bascule son icône, seule la carte ne suivait pas.
 */
.crm-dash-cell > .crm-widget.collapsing-card,
.crm-dash-cell > .crm-widget.collapsed-card { height: auto; align-self: flex-start; }

.crm-widget-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex: 0 0 auto;
    padding: .55rem .9rem;
    background: transparent;
    border-bottom: 1px solid var(--crm-border-soft);
}

/*
 * L'icône de l'encart, dans un carré doux.
 *
 * Onze en-têtes de la même graisse, du même gris et de la même casse ne se distinguaient qu'en
 * les lisant, alors qu'un en-tête sert justement à ne pas avoir à lire. Sa largeur est fixe et
 * le catalogue a un glyphe de repli : un encart sans icône décalerait son titre, et la rangée
 * perdrait son aplomb pour un oubli de déclaration.
 */
.crm-widget-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: var(--crm-radius-sm);
    background: var(--crm-slate-100);
    color: var(--crm-slate-500);
    font-size: .72rem;
}

.crm-widget-title {
    margin: 0;
    min-width: 0;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--crm-slate-600);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Le nombre d'éléments, dans l'en-tête : sans lui il faut compter les lignes pour savoir s'il y
   a beaucoup ou peu à faire. */
.crm-widget-count {
    flex: 0 0 auto;
    padding: .05rem .4rem;
    border-radius: 999px;
    background: var(--crm-slate-100);
    color: var(--crm-slate-600);
    font-size: .72rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.crm-widget-tools { display: flex; align-items: center; gap: .25rem; margin-left: auto; }

.crm-widget-link {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: .76rem;
    font-weight: 500;
    white-space: nowrap;
}

.crm-widget-link .fas { font-size: .6rem; }

/* Le repliement se propose sans se réclamer : c'est un réglage de l'écran, pas une action de
   l'encart, et il ne doit pas peser autant que le lien à côté de lui. */
.crm-widget-fold { padding: .15rem .35rem; color: var(--crm-slate-300); font-size: .7rem; }
.crm-widget-fold:hover { color: var(--crm-slate-600); }

.crm-widget-body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding: .75rem .9rem;
}

.crm-widget-clear {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin: 0;
    padding: .4rem 0;
    color: var(--crm-success);
    font-size: .88rem;
}

/* Le pied d'un encart, poussé en bas dès que la carte est plus haute que son contenu. */
.crm-list-rest {
    margin: .7rem 0 0;
    margin-top: auto;
    padding-top: .5rem;
    border-top: 1px solid var(--crm-border-soft);
    font-size: .76rem;
    color: var(--crm-text-muted);
}

.crm-list-rest a { margin-left: .35rem; }

/*
 * Barre de compteurs de tâches.
 *
 * Quatre tuiles séparées de 283 x 94 px pour un nombre à deux chiffres, dont trois valaient
 * zéro : le contenu occupait un dixième de la largeur qu'on lui donnait, et les gouttières
 * faisaient lire quatre objets là où il y en a un, un état des lieux. Un seul cadre, des
 * segments séparés par un filet, et le vide devient une respiration symétrique au lieu d'un
 * bord droit désert.
 *
 * Le premier segment, ce qui est en retard, est teinté dès qu'il n'est pas nul : un chiffre
 * qu'on voit sans le chercher est ce qui distingue un tableau de bord d'un rapport. À zéro il
 * s'éteint, pour ne pas crier quand tout va bien.
 */
.crm-statbar {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    /*
     * Les filets viennent d'une gouttière d'un pixel qui laisse voir le fond du cadre, et non
     * d'une bordure posée sur chaque segment. C'est ce qui les rend justes quel que soit le
     * nombre de colonnes : repliée sur deux rangs, la barre portait sinon un filet au bord
     * gauche du troisième segment, et aucun entre les deux rangs.
     */
    gap: 1px;
    overflow: hidden;
    background: var(--crm-border-soft);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
}

.crm-stat {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .15rem;
    padding: .85rem .75rem;
    background: var(--crm-surface);
    color: var(--crm-slate-700);
    text-align: center;
    transition: background var(--crm-ease);
}
.crm-stat:hover { background: var(--crm-slate-50); color: var(--crm-slate-700); text-decoration: none; }

.crm-stat-value {
    font-size: 1.9rem;
    font-weight: 600;
    line-height: 1.05;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
}

.crm-stat-label {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    font-size: .74rem;
    color: var(--crm-slate-500);
}

.crm-stat-label .fas,
.crm-stat-label .far { font-size: .68rem; opacity: .75; }

/* Le liseré est en haut et non à gauche : dans une barre segmentée, un liseré gauche se
   confondrait avec le filet qui sépare du segment précédent. */
.crm-stat.is-danger:not(.is-zero)::before,
.crm-stat.is-warning:not(.is-zero)::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
}

.crm-stat.is-danger:not(.is-zero) { background: var(--crm-danger-soft); }
.crm-stat.is-danger:not(.is-zero)::before { background: var(--crm-danger); }
.crm-stat.is-danger:not(.is-zero) .crm-stat-value,
.crm-stat.is-danger:not(.is-zero) .crm-stat-label { color: var(--crm-danger); }
.crm-stat.is-danger:not(.is-zero):hover { background: #fbe0e3; }

.crm-stat.is-warning:not(.is-zero)::before { background: var(--crm-amber); }
.crm-stat.is-warning:not(.is-zero) .crm-stat-value { color: var(--crm-warning); }

.crm-stat.is-zero .crm-stat-value { color: var(--crm-slate-300); font-weight: 500; }

/*
 * Ce qui demande de l'attention.
 *
 * Le liseré gauche est devenu une pastille teintée : elle porte l'icône, donc le type, **et**
 * la couleur, donc l'urgence, là où le liseré ne portait que la seconde et laissait une icône
 * grise flotter au milieu de la ligne. La méta passe sous le libellé : à droite, séparée par
 * six cents pixels de vide sur une carte large, elle n'avait plus l'air d'appartenir à la même
 * ligne que lui.
 */
.crm-attention { list-style: none; margin: 0; padding: 0; }

.crm-attention-row {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .38rem .45rem;
    border-radius: var(--crm-radius);
}

.crm-attention-row + .crm-attention-row { margin-top: .1rem; }
.crm-attention-row:hover { background: var(--crm-slate-50); }

.crm-attention-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 1.65rem;
    height: 1.65rem;
    border-radius: 50%;
    font-size: .72rem;
    background: var(--crm-slate-100);
    color: var(--crm-slate-500);
}

.crm-attention-row.is-danger  .crm-attention-icon { background: var(--crm-danger-soft);  color: var(--crm-danger); }
.crm-attention-row.is-warning .crm-attention-icon { background: var(--crm-warning-soft); color: var(--crm-warning); }
.crm-attention-row.is-info    .crm-attention-icon { background: var(--crm-primary-soft); color: var(--crm-primary); }

.crm-attention-main { display: flex; flex-direction: column; gap: .05rem; flex: 1 1 auto; min-width: 0; }

/*
 * Le libellé tient sur deux lignes au plus. Les titres repris du portail font parfois trois
 * phrases : laissés libres, l'un d'eux occupait six rangs et l'encart affichait alors huit
 * lignes là où douze tiennent.
 */
.crm-attention-label {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: .86rem;
    font-weight: 500;
    line-height: 1.35;
    color: var(--crm-slate-800);
}

.crm-attention-label:hover { color: var(--crm-primary-dark); }
.crm-attention-meta { font-size: .73rem; color: var(--crm-slate-500); }
.crm-attention-row .crm-chip { flex: 0 0 auto; }

/*
 * Fil des dernières activités.
 *
 * La pastille grise, identique pour tous les types, est devenue l'icône du type dans sa teinte.
 * « Réunion », « Note » et « Cycle de vie » ne se distinguaient sinon qu'en lisant leur
 * libellé, alors que le type est précisément ce qu'on balaie dans un fil. Icône et teinte
 * viennent de `ActivityType`, donc du même endroit que partout ailleurs : un type ajouté plus
 * tard arrive ici avec son dessin, sans qu'on ait à y penser.
 */
.crm-feed { list-style: none; margin: 0; padding: 0; }

.crm-feed-row { display: flex; align-items: flex-start; gap: .55rem; padding: .32rem 0; }
.crm-feed-row + .crm-feed-row { border-top: 1px solid var(--crm-border-soft); }

.crm-feed-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1.5rem;
    margin-top: .1rem;
    border-radius: 50%;
    font-size: .65rem;
    background: var(--crm-slate-100);
    color: var(--crm-slate-500);
}

.crm-feed-icon.is-primary { background: var(--crm-primary-soft); color: var(--crm-primary); }
.crm-feed-icon.is-success { background: var(--crm-success-soft); color: var(--crm-success); }
.crm-feed-icon.is-info    { background: var(--crm-info-soft);    color: var(--crm-info); }
.crm-feed-icon.is-warning { background: var(--crm-warning-soft); color: var(--crm-warning); }
.crm-feed-icon.is-danger  { background: var(--crm-danger-soft);  color: var(--crm-danger); }

.crm-feed-main { display: flex; flex-direction: column; gap: .05rem; min-width: 0; }

/* Trois lignes au plus : un objet d'e-mail repris du portail en fait facilement dix. */
.crm-feed-head {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: .81rem;
    line-height: 1.35;
}

.crm-feed-type { font-weight: 600; color: var(--crm-slate-800); }
.crm-feed-subject { color: var(--crm-slate-600); }
.crm-feed-meta { font-size: .72rem; color: var(--crm-slate-500); }

/*
 * Chiffres clés : deux ou trois valeurs qui se comparent d'un regard, séparées par un filet
 * plutôt que par du vide. Sans lui, « 13 117 398,34 € » et « 6 064 238,34 € » posés côte à côte
 * se lisaient comme un seul nombre coupé en deux.
 */
.crm-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); }

.crm-figure {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    padding: .15rem 0 .15rem .9rem;
    box-shadow: inset 1px 0 0 var(--crm-border-soft);
    min-width: 0;
}

.crm-figure:first-child { padding-left: 0; box-shadow: none; }

.crm-figure-value {
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.15;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    color: var(--crm-slate-800);
}

.crm-figure-label {
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--crm-slate-500);
    line-height: 1.3;
}

/*
 * Barres proportionnelles plutôt que camembert : on compare des longueurs bien mieux que des
 * angles, et la liste reste lisible avec six catégories.
 */
.crm-bars { list-style: none; margin: 0; padding: 0; }

.crm-bar-row { display: grid; grid-template-columns: 9rem 1fr 3rem; gap: .6rem; align-items: center; padding: .3rem 0; }
.crm-bar-label { font-size: .8rem; color: var(--crm-slate-700); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.crm-bar-track { height: .5rem; background: var(--crm-slate-100); border-radius: 999px; overflow: hidden; }
.crm-bar-fill { display: block; height: 100%; background: var(--crm-primary); border-radius: 999px; }
.crm-bar-fill.is-warm { background: var(--crm-amber); }

/*
 * Un filet minimal dès que la catégorie n'est pas vide. « Autre fournisseur : 19 » sur quatorze
 * mille rendait une piste entièrement vide à côté d'un nombre non nul : la seule lecture
 * possible était « il n'y en a pas ».
 */
.crm-bar-fill.is-live { min-width: .3rem; }
.crm-bar-value { font-size: .8rem; text-align: right; font-variant-numeric: tabular-nums; color: var(--crm-slate-600); }

/*
 * Listes d'objets à traiter.
 *
 * Le nom d'un côté, la date brute de l'autre, et toute la largeur de la carte entre les deux :
 * sur un encart de 668 px, « MIS-00318 » et « Fin prévue 28/08/2026 » n'avaient plus l'air
 * d'appartenir à la même ligne. Le nom et sa légende forment maintenant un bloc, et l'échéance
 * est une pastille qui porte son urgence dans sa teinte.
 */
.crm-oblist { list-style: none; margin: 0; padding: 0; }

.crm-oblist-row {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .38rem 0;
}

.crm-oblist-row + .crm-oblist-row { border-top: 1px solid var(--crm-border-soft); }
.crm-oblist-main { display: flex; flex-direction: column; gap: .05rem; flex: 1 1 auto; min-width: 0; }

.crm-oblist-label {
    font-size: .85rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.crm-oblist-caption {
    font-size: .73rem;
    color: var(--crm-slate-500);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.crm-oblist-row .crm-chip { flex: 0 0 auto; }
.crm-oblist-empty { padding: .5rem 0; font-size: .84rem; color: var(--crm-text-muted); }

/* Le séparateur du sous-titre de l'écran : la date, puis le rôle. */
.crm-page-sep { color: var(--crm-slate-300); margin: 0 .15rem; }

/* Écran de réglage : la liste triable des widgets. */
.crm-widget-picker { list-style: none; margin: 0; padding: 0; }

.crm-widget-pick {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    padding: .6rem .9rem;
    border-bottom: 1px solid var(--crm-slate-100);
    background: #fff;
}

.crm-widget-pick:last-child { border-bottom: 0; }
.crm-widget-handle { color: var(--crm-slate-300); cursor: grab; padding-top: .1rem; }
.crm-widget-pick:hover .crm-widget-handle { color: var(--crm-slate-500); }
.crm-widget-pick-main { display: flex; gap: .5rem; margin: 0; flex: 1 1 auto; font-weight: 400; cursor: pointer; }
.crm-widget-pick-hint { display: block; font-size: .78rem; color: var(--crm-slate-500); line-height: 1.35; }
.crm-widget-pick-width { font-size: .72rem; color: var(--crm-slate-400); white-space: nowrap; }
.crm-widget-pick-ghost { height: 3rem; background: var(--crm-primary-soft, #eef2fe); border: 1px dashed var(--crm-primary); }

/*
 * Rangée de filtres nommés (§5.4.4).
 *
 * Toujours visible, contrairement au constructeur avancé. Chaque liste est un `<details>` :
 * fermée, elle n'occupe qu'un bouton ; ouverte, elle déroule ses options sous elle. Aucun
 * script, donc rien à réparer si le JavaScript échoue.
 */
.crm-quickbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: .4rem;
    padding: .6rem .9rem;
    background: var(--crm-slate-50);
    border-bottom: 1px solid var(--crm-slate-200);
}

.crm-quick { position: relative; }

.crm-quick-toggle {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .28rem .6rem;
    font-size: .82rem;
    color: var(--crm-slate-700);
    background: #fff;
    border: 1px solid var(--crm-slate-300);
    border-radius: 999px;
    cursor: pointer;
    white-space: nowrap;
    list-style: none;
    transition: border-color var(--crm-ease), background var(--crm-ease);
}

.crm-quick-toggle::-webkit-details-marker { display: none; }
.crm-quick-toggle:hover { border-color: var(--crm-slate-400); background: var(--crm-slate-50); }

/* Une liste qui filtre se voit sans l'ouvrir : c'est ce qui évite de chercher pourquoi la
   liste est courte. */
.crm-quick-toggle.is-active {
    border-color: var(--crm-primary);
    background: var(--crm-primary-soft, #eef2fe);
    color: var(--crm-primary);
    font-weight: 500;
}

.crm-quick-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 .25rem;
    border-radius: 999px;
    background: var(--crm-primary);
    color: #fff;
    font-size: .68rem;
    font-weight: 600;
}

/*
 * Libellé de l'option retenue, sur le bouton lui-même.
 *
 * Le bouton n'affichait qu'un compteur « 1 », qui ne disait pas *laquelle* des six options
 * était active : il fallait ouvrir le panneau pour le savoir. Le gabarit l'ouvrait donc de
 * lui-même, et ce panneau surgissait par-dessus le bandeau d'indicateurs : c'était le
 * comportement qu'on constatait en arrivant par un compteur de tête de liste.
 *
 * Tronqué à 11rem : « Plus de 90 jours » tient, un nom d'entreprise à rallonge ne pousse pas
 * la rangée sur deux lignes.
 */
.crm-quick-value {
    display: inline-block;
    max-width: 11rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
    padding: 0 .35rem;
    border-radius: 999px;
    background: var(--crm-primary);
    color: #fff;
    font-size: .68rem;
    font-weight: 600;
    line-height: 1.1rem;
}

.crm-quick-caret { font-size: .7rem; opacity: .6; }
.crm-quick[open] .crm-quick-caret { transform: rotate(180deg); }

.crm-quick-panel {
    position: absolute;
    z-index: 20;
    top: calc(100% + .25rem);
    left: 0;
    min-width: 13rem;
    max-height: 17rem;
    overflow-y: auto;
    padding: .45rem;
    background: #fff;
    border: 1px solid var(--crm-slate-200);
    border-radius: var(--crm-radius);
    box-shadow: var(--crm-shadow-lg, 0 10px 28px rgba(15, 23, 42, .14));
    scrollbar-width: thin;
}

.crm-quick-option {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin: 0;
    padding: .28rem .35rem;
    border-radius: var(--crm-radius-sm);
    font-size: .82rem;
    font-weight: 400;
    cursor: pointer;
}

.crm-quick-option:hover { background: var(--crm-slate-50); }
.crm-quick-option input { margin: 0; flex: 0 0 auto; }

.crm-quickbar-apply { margin-left: .2rem; }

.crm-quickbar-clear,
.crm-quickbar-more {
    align-self: center;
    padding: 0 .3rem;
    font-size: .8rem;
    color: var(--crm-slate-500);
    background: none;
    border: 0;
    cursor: pointer;
}

.crm-quickbar-clear:hover { color: var(--crm-danger, #cf3040); }
.crm-quickbar-more:hover { color: var(--crm-primary); }

/*
 * Sélecteur de mode d'affichage (tableau / pipeline).
 *
 * Deux icônes plutôt que deux libellés : le couple tableau-colonnes se reconnaît, et la barre
 * d'outils est déjà chargée. L'état actif est marqué par le fond, pas seulement par la teinte
 * du trait : une simple couleur de bordure ne se voit pas sur deux boutons collés.
 */
.crm-view-mode { margin-right: .4rem; }
.crm-view-mode .btn { padding: .25rem .55rem; }
.crm-view-mode .btn.active {
    background: var(--crm-slate-800);
    border-color: var(--crm-slate-800);
    color: #fff;
}

/*
 * Bandeau d'indicateurs de liste (§5.3.4).
 *
 * Ce qui manque à une liste, ce n'est pas ce qu'elle contient mais ce qui lui manque : les
 * fiches sans propriétaire, sans e-mail, sans activité depuis trois mois. Chaque compteur est
 * un lien qui applique le filtre correspondant, sinon c'est une statistique, et une
 * statistique sur laquelle on ne peut pas cliquer ne fait rien avancer.
 */
.crm-insights {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 1px;
    background: var(--crm-slate-200);
    border-bottom: 1px solid var(--crm-slate-200);
}

.crm-insight {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .1rem;
    padding: .7rem .8rem;
    background: #fff;
    text-align: center;
    color: var(--crm-slate-600);
    transition: background var(--crm-ease);
}

a.crm-insight:hover { background: var(--crm-slate-50); color: var(--crm-slate-900); text-decoration: none; }
a.crm-insight:focus-visible { outline: 2px solid var(--crm-primary); outline-offset: -2px; }

.crm-insight-label {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--crm-slate-500);
}

.crm-insight-value {
    font-size: 1.45rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--crm-slate-900);
    font-variant-numeric: tabular-nums;
}

/* Zéro n'est pas un manque : on l'éteint pour que l'œil aille sur les compteurs qui comptent. */
.crm-insight.is-empty .crm-insight-value { color: var(--crm-slate-400); font-weight: 500; }

/* Un compteur décoché, dans l'aperçu du réglage : présent, mais visiblement pas affiché. */
.crm-insight.is-off { opacity: .45; }

/*
 * L'engrenage du bandeau : régler les indicateurs depuis l'écran où on les lit.
 *
 * En position absolue plutôt qu'en cellule de la grille : les cellules font au moins 11 rem, et
 * une cellule de 11 rem pour une roue dentée aurait creusé un trou au bout du bandeau. Discret
 * au repos, on ne règle pas ses compteurs tous les jours, et net au survol.
 */
.crm-insights { position: relative; }
.crm-insights-config {
    position: absolute;
    top: .2rem;
    right: .3rem;
    padding: .15rem .3rem;
    font-size: .75rem;
    line-height: 1;
    color: var(--crm-slate-300);
    border-radius: var(--crm-radius-sm);
}
.crm-insights-config:hover {
    color: var(--crm-primary);
    background: var(--crm-slate-100);
    text-decoration: none;
}

/*
 * Allègement du tableau de liste.
 *
 * Les zébrures d'AdminLTE, le survol et les colonnes figées se superposaient : trois fonds
 * différents sur une même ligne, et la colonne figée qui changeait de couleur en défilant.
 * Un simple filet entre les lignes suffit à les suivre, et laisse le survol se voir.
 */
.crm-table.table-striped tbody tr:nth-of-type(odd) { background: transparent; }
.crm-table tbody tr { border-bottom: 1px solid var(--crm-slate-100); }
.crm-table tbody tr:hover { background: var(--crm-slate-50); }
.crm-table tbody td { border-top: 0; vertical-align: middle; padding: .5rem .75rem; }

.crm-table thead th {
    border-top: 0;
    border-bottom: 1px solid var(--crm-slate-200);
    padding: .5rem .75rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--crm-slate-500);
    white-space: nowrap;
}

/* ================================================ Page de liste sans défilement (§5.6) */

/*
 * La page ne défile pas : c'est la boîte du tableau qui prend la hauteur restante.
 *
 * Un `max-height` estimé en `calc(100vh - 22rem)` ne pouvait pas tenir cette promesse. La barre
 * d'outils, la rangée de filtres et le bandeau d'indicateurs n'ont pas la même hauteur d'un
 * module à l'autre : selon les cas, il restait un vide sous le tableau ou la pagination
 * tombait sous la ligne de flottaison, et on faisait défiler la page pour l'atteindre.
 *
 * Une chaîne de conteneurs en colonne résout cela sans aucune estimation. Le `min-height: 0`
 * répété est ce qui la fait fonctionner : un enfant de flex refuse par défaut de descendre sous
 * la hauteur de son contenu, si bien que le tableau poussait ses parents au lieu de défiler.
 */
/*
 * L'enveloppe entière devient la colonne, et non le seul conteneur de contenu.
 *
 * `height: 100vh` sur le conteneur de contenu ne pouvait pas marcher : la barre supérieure
 * occupe le flux, si bien que le conteneur commençait à 57 pixels du haut et débordait
 * d'autant. Retrancher cette hauteur en dur aurait tenu jusqu'au jour où la barre change.
 *
 * En faisant de l'enveloppe la colonne, la barre est un enfant qui garde sa hauteur et le
 * contenu prend ce qui reste : sans qu'aucune valeur soit écrite nulle part.
 */
body.crm-fixed-page { overflow: hidden; }

body.crm-fixed-page .wrapper {
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
}

body.crm-fixed-page .main-header { flex: 0 0 auto; }

body.crm-fixed-page .content-wrapper {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    height: auto;
    min-height: 0;
    overflow: hidden;
}

/*
 * L'en-tête d'écran est resserré sur les listes.
 *
 * Chaque pixel repris au-dessus est une ligne de plus dans le tableau, et la hauteur du
 * tableau est ce qui détermine si la liste se parcourt ou se filtre. Le titre reste lisible,
 * le fil d'Ariane et les actions gardent leur place.
 */
body.crm-fixed-page .content-header { flex: 0 0 auto; padding-top: .6rem; padding-bottom: .3rem; }
body.crm-fixed-page .content-header h1 { font-size: 1.4rem; }
body.crm-fixed-page .content-header .breadcrumb { margin-bottom: .2rem; }
body.crm-fixed-page .crm-page-subtitle { margin-bottom: 0; }
body.crm-fixed-page .crm-view-tabs-bar { margin-bottom: .5rem !important; }

body.crm-fixed-page .content {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding-bottom: 0;
}

body.crm-fixed-page .content > .container-fluid {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* La barre d'onglets et les messages gardent leur hauteur ; seule la carte s'étire. */
body.crm-fixed-page .crm-view-tabs-bar,
body.crm-fixed-page .alert { flex: 0 0 auto; }

body.crm-fixed-page .content > .container-fluid > .card {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    margin-bottom: .5rem;
}

/*
 * Tous les bandeaux de la carte gardent leur hauteur ; seule la boîte du tableau s'étire.
 *
 * La règle était une **énumération** : `.card-header`, `.card-footer`, `.crm-quickbar`,
 * `.crm-insights`, `#crmFilters`. Une liste à tenir à jour, donc une liste incomplète : la
 * carte d'une liste porte six bandeaux, et trois n'y figuraient pas : la barre d'outils, la
 * rangée de conditions actives et le bandeau « l'affichage diffère ».
 *
 * N'étant pas déclarés `flex: 0 0 auto`, ils héritaient de `flex-shrink: 1` et se faisaient
 * **écraser** dès que le tableau réclamait de la place : bandeau réduit à quelques pixels,
 * boutons « Enregistrer l'affichage » et « Réinitialiser » coupés en deux, conditions actives
 * illisibles sous le bandeau suivant. C'est ce qu'on voyait en arrivant par un compteur de
 * tête de liste, qui est précisément le cas où les trois s'affichent en même temps.
 *
 * La règle est donc inversée : tout enfant direct garde sa hauteur, et l'exception est
 * nommée. Ajouter un septième bandeau, la barre d'actions groupées l'a fait, ne peut plus
 * réintroduire le défaut.
 */
body.crm-fixed-page .content > .container-fluid > .card > * { flex: 0 0 auto; }

/* Sélecteur plus spécifique que la règle ci-dessus, sinon l'exception ne s'appliquerait pas. */
body.crm-fixed-page .content > .container-fluid > .card > .crm-table-scroll {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
}

/* Conservée pour les cartes de tableau hors écran de liste : administration, fiches. */
body.crm-fixed-page .crm-table-scroll { max-height: none; }

/*
 * Le pied de page est retiré des listes.
 *
 * Il porte le nom de l'outil et l'état de la connexion Google : l'un est dans le menu, l'autre
 * dans le menu du compte. Le garder aurait coûté les seuls pixels qui font défiler la page,
 * pour une information disponible ailleurs.
 */
body.crm-fixed-page .main-footer { display: none; }

/*
 * Le tableau défile dans sa propre boîte, sur les deux axes.
 *
 * C'est le point qui manquait : la page entière s'allongeait, si bien qu'atteindre la
 * pagination demandait de faire défiler tout l'écran, et l'en-tête des colonnes disparaissait
 * en route. Une boîte de hauteur bornée garde l'en-tête visible, la barre horizontale sous les
 * lignes, et la pagination immédiatement dessous : c'est le fonctionnement de HubSpot.
 *
 * La hauteur est calculée en retirant ce qui occupe l'écran au-dessus : barre de navigation,
 * onglets de vue, barre de filtres, pied de pagination. Une valeur fixe en pixels aurait laissé
 * un vide sur un grand écran et coupé les lignes sur un portable.
 */
.crm-table-scroll {
    overflow: auto;
    max-height: calc(100vh - 22rem);
    scrollbar-width: thin;
    scrollbar-color: var(--crm-slate-300) transparent;
    position: relative;
    overscroll-behavior: contain;
}

/* Écran court : on rend la main à la page plutôt que d'écraser le tableau à deux lignes. */
@media (max-height: 640px) {
    .crm-table-scroll { max-height: none; }
}

/*
 * L'en-tête reste en place pendant le défilement vertical.
 *
 * `z-index` supérieur à celui des cellules figées, sinon la première colonne passait
 * par-dessus l'en-tête au croisement des deux défilements.
 */
.crm-table-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--crm-slate-50);
}

.crm-table-scroll thead th.crm-frozen { z-index: 4; }
.crm-table-scroll tbody td.crm-frozen { z-index: 2; background: #fff; }
.crm-table-scroll tbody tr:hover td.crm-frozen { background: var(--crm-slate-50); }

.crm-table-scroll table { width: max-content; min-width: 100%; }

/* Largeur minimale par colonne : en dessous, une valeur tronquée ne dit plus rien. */
.crm-table th:not(.crm-frozen):not([style*="width"]):not(.crm-col-pick),
.crm-table td:not(.crm-frozen):not([style*="width"]):not(.crm-col-pick) { min-width: 9rem; }

/*
 * Les deux colonnes de service, case à cocher et bouton d'ouverture, ne portent pas de
 * donnée, donc pas de largeur minimale.
 *
 * L'en-tête de la case y échappait par son style en ligne, mais **pas** la cellule de corps :
 * la colonne prenait donc 9 rem, soit 144 px pour une case de 13 : une colonne vide plus large
 * que « Prénom », et le tableau poussé d'autant vers la droite.
 */
.crm-table th.crm-col-pick,
.crm-table td.crm-col-pick { min-width: 2.5rem; width: 2.5rem; padding-left: .75rem; padding-right: .5rem; }
.crm-table th.crm-col-pick.text-right,
.crm-table td.crm-col-pick.text-right { min-width: 3rem; width: 3rem; padding-left: .5rem; padding-right: .75rem; }

/* Les colonnes courtes n'ont pas besoin d'autant de place. */
.crm-table th.text-center:not(.crm-frozen),
.crm-table td.text-center:not(.crm-frozen) { min-width: 6rem; }

/*
 * Ombre de bord, posée par le JavaScript quand il reste du contenu hors écran.
 *
 * Sans elle, rien ne distingue une liste de six colonnes d'une liste de vingt : on ne pense
 * pas à faire défiler ce qu'on ne soupçonne pas. C'est le repère que HubSpot donne aussi.
 */
.crm-table-scroll::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 1.75rem;
    height: 100%;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--crm-ease);
    background: linear-gradient(to right, rgba(15, 23, 42, 0), rgba(15, 23, 42, .09));
}

.crm-table-scroll.has-more-right::after { opacity: 1; }

.crm-table-scroll::-webkit-scrollbar,
.crm-drawer-body::-webkit-scrollbar,
.crm-view-tabs::-webkit-scrollbar,
.crm-kanban::-webkit-scrollbar,
.crm-kanban-body::-webkit-scrollbar { width: 10px; height: 10px; }

.crm-table-scroll::-webkit-scrollbar-track,
.crm-drawer-body::-webkit-scrollbar-track,
.crm-view-tabs::-webkit-scrollbar-track,
.crm-kanban::-webkit-scrollbar-track,
.crm-kanban-body::-webkit-scrollbar-track { background: transparent; }

.crm-table-scroll::-webkit-scrollbar-thumb,
.crm-drawer-body::-webkit-scrollbar-thumb,
.crm-view-tabs::-webkit-scrollbar-thumb,
.crm-kanban::-webkit-scrollbar-thumb,
.crm-kanban-body::-webkit-scrollbar-thumb {
    background: var(--crm-slate-300);
    border: 3px solid transparent;
    border-radius: 6px;
    background-clip: content-box;
}
.crm-table-scroll::-webkit-scrollbar-thumb:hover,
.crm-drawer-body::-webkit-scrollbar-thumb:hover,
.crm-kanban::-webkit-scrollbar-thumb:hover { background: var(--crm-slate-400); background-clip: content-box; }

.crm-table { margin-bottom: 0; }

/* L'en-tête reste visible quand on descend dans les lignes. */
.crm-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    white-space: nowrap;
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--crm-text-muted);
    background: var(--crm-slate-50);
    border-top: 0;
    border-bottom: 1px solid var(--crm-border);
    padding: .6rem .85rem;
}

/*
 * Tri : la flèche neutre sur chaque colonne triable faisait quinze icônes grises dans
 * l'en-tête. Elle n'apparaît plus qu'au survol ; celle de la colonne triée reste, elle,
 * toujours visible et colorée : c'est une information, pas une affordance.
 */
.crm-table thead th a { color: var(--crm-text-muted); text-decoration: none; }
.crm-table thead th a:hover { color: var(--crm-slate-900); }
.crm-table thead th .fa-sort { opacity: 0; transition: opacity var(--crm-ease); }
.crm-table thead th:hover .fa-sort { opacity: .6; }
.crm-table thead th .fa-sort-up,
.crm-table thead th .fa-sort-down { color: var(--crm-primary); }
.crm-table thead th:has(.fa-sort-up) a,
.crm-table thead th:has(.fa-sort-down) a { color: var(--crm-primary); }

.crm-table td {
    vertical-align: middle;
    font-size: .875rem;
    padding: .7rem .85rem;
    border-top: 1px solid var(--crm-border-soft);
}

/*
 * La ligne survolée prend un liseré bleu à gauche : sur un tableau très large, un simple
 * changement de fond se perd, alors qu'un repère au bord suit l'œil pendant le défilement
 * horizontal.
 */
.crm-table tbody tr { transition: background var(--crm-ease), box-shadow var(--crm-ease); }
.crm-table tbody tr:hover { background-color: var(--crm-primary-soft); }
.crm-table tbody tr:hover > td:first-child { box-shadow: inset 3px 0 0 var(--crm-primary); }

/* Ligne zébrée : très léger, juste de quoi suivre une ligne longue de l'œil. */
.crm-table.table-striped tbody tr:nth-of-type(odd) { background-color: var(--crm-slate-50); }
.crm-table.table-striped tbody tr:nth-of-type(odd):hover { background-color: var(--crm-primary-soft); }

/* Les actions d'une ligne ne se révèlent qu'au survol : le tableau reste calme. */
.crm-table .crm-row-actions { opacity: .35; transition: opacity var(--crm-ease); }
.crm-table tbody tr:hover .crm-row-actions,
.crm-table tbody tr:focus-within .crm-row-actions { opacity: 1; }

/*
 * Barre d'onglets dynamiques (§5.3), présentée en sélecteur segmenté.
 *
 * Le soulignement d'origine se confondait avec du texte : les onglets d'un CRM sont des
 * boutons de navigation, et on en compte parfois dix. Chacun devient donc une pastille
 * posée sur un rail gris ; l'onglet actif est la seule pastille blanche, détachée par son
 * ombre. On lit l'onglet courant sans comparer des couleurs.
 */
/* Le rail défile ; le bouton de création reste à côté, toujours atteignable. */
.crm-view-tabs-bar { display: flex; align-items: stretch; gap: .4rem; }

.crm-view-tabs {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-wrap: nowrap;
    gap: .2rem;
    padding: .3rem;
    background: var(--crm-slate-100);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    overflow-x: auto;
    white-space: nowrap;
    scrollbar-width: thin;
}

.crm-view-tabs .nav-item { flex: 0 0 auto; }

/* La barre de défilement du rail est un liseré : elle ne doit pas l'épaissir. */
.crm-view-tabs::-webkit-scrollbar { height: 6px; }
.crm-view-tabs::-webkit-scrollbar-thumb { border-width: 1px; }

/*
 * Les onglets se voient, et l'onglet ouvert se voit **d'un coup d'œil**.
 *
 * Le reproche était « le bandeau des onglets doit être plus visible, pareil dans toutes les
 * listes ». Il l'était à peine : un onglet au repos en gris moyen sur un fond gris clair, un
 * onglet actif blanc à ombre discrète, et la seule différence de couleur portée par le texte.
 * Sur une liste de dix onglets, retrouver celui qu'on regarde demandait de lire les dix.
 *
 * Trois changements, et le troisième est celui qui compte : le texte au repos passe en
 * `slate-700` (contraste 7:1 au lieu de 4,6), l'onglet actif prend le **bleu plein** au lieu du
 * blanc, et il porte un **liseré haut** de deux pixels. C'est le liseré qui répond en vision
 * périphérique, là où une nuance de fond ne répond pas, et il survit à une impression en
 * niveaux de gris comme au daltonisme.
 */
.crm-view-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    position: relative;
    border: 1px solid transparent;
    border-radius: var(--crm-radius);
    color: var(--crm-slate-700, #334155);
    font-size: .84rem;
    font-weight: 500;
    padding: .42rem .75rem;
    transition: background var(--crm-ease), color var(--crm-ease), box-shadow var(--crm-ease);
}
.crm-view-tabs .nav-link:hover {
    background: var(--crm-surface);
    border-color: var(--crm-border);
    color: var(--crm-slate-900);
}
.crm-view-tabs .nav-link.active {
    background: var(--crm-primary);
    border-color: var(--crm-primary);
    box-shadow: 0 1px 4px rgba(47, 111, 235, .35);
    color: #fff;
    font-weight: 600;
}
/*
 * Le liseré est posé en `::after` et non par une bordure : une bordure haute de 2 px décalerait
 * le libellé de deux pixels au passage d'un onglet à l'autre, et la rangée entière tremblerait.
 */
.crm-view-tabs .nav-link.active::after {
    content: "";
    position: absolute;
    left: .45rem;
    right: .45rem;
    top: 0;
    height: 2px;
    border-radius: 0 0 2px 2px;
    background: rgba(255, 255, 255, .75);
}

/* Compteur de l'onglet : gris sur un onglet au repos, bleu sur l'onglet ouvert. */
.crm-view-tab-count {
    display: inline-block;
    min-width: 1.4rem;
    padding: .05rem .35rem;
    font-size: .7rem;
    font-weight: 600;
    text-align: center;
    line-height: 1.5;
    border-radius: 1rem;
    background: var(--crm-slate-200);
    color: var(--crm-slate-600);
}
/*
 * Sur l'onglet ouvert, désormais en bleu plein, le compteur passe en **blanc translucide**.
 *
 * Il portait `--crm-primary-soft` sur `--crm-primary-dark`, réglés pour un onglet blanc : posés
 * sur du bleu plein ils donnaient un bleu clair sur bleu moyen, illisible, et c'est justement le
 * chiffre qu'on vient chercher dans un onglet. Même raison pour le marqueur de portée.
 */
.crm-view-tabs .nav-link.active .crm-view-tab-count {
    background: rgba(255, 255, 255, .22);
    color: #fff;
}

/* Marqueur de portée (personnel / partagé), discret par nature. */
.crm-view-tab-scope { font-size: .65rem; color: var(--crm-text-faint); }
.crm-view-tabs .nav-link.active .crm-view-tab-scope { color: rgba(255, 255, 255, .8); }

/* Création d'un onglet : une pastille en pointillé, qui se lit comme un emplacement libre. */
.crm-view-tab-add {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .35rem;
    padding: .4rem .8rem;
    font-size: .84rem;
    font-weight: 500;
    border: 1px dashed var(--crm-slate-300);
    border-radius: var(--crm-radius-lg);
    background: var(--crm-surface);
    color: var(--crm-text-muted);
    text-decoration: none;
    transition: all var(--crm-ease);
}
.crm-view-tab-add:hover {
    border-color: var(--crm-primary);
    border-style: solid;
    color: var(--crm-primary);
    background: var(--crm-primary-soft);
    text-decoration: none;
}

/*
 * Barre d'outils de la liste : la recherche à gauche, les réglages de vue à droite. Le
 * champ et son bouton forment un seul objet arrondi, au lieu de deux contrôles accolés.
 */
.crm-list-toolbar { gap: .5rem; }

.crm-search-group .form-control {
    border-right: 0;
    border-radius: var(--crm-radius) 0 0 var(--crm-radius);
    min-width: 13rem;
}
.crm-search-group .btn {
    border-left: 0;
    border-radius: 0 var(--crm-radius) var(--crm-radius) 0;
    background: var(--crm-surface);
    border-color: var(--crm-slate-300);
    color: var(--crm-text-muted);
    box-shadow: none;
}
.crm-search-group .btn:hover { transform: none; color: var(--crm-primary); background: var(--crm-slate-50); }
.crm-search-group:focus-within .form-control,
.crm-search-group:focus-within .btn { border-color: var(--crm-primary); }
.crm-search-group:focus-within .form-control { box-shadow: none; }
.crm-search-group:focus-within { box-shadow: var(--crm-ring); border-radius: var(--crm-radius); }

/* Pastilles de filtres actifs (§5.4.1). */
.crm-filter-chip { display: inline-flex; align-items: center; gap: .35rem; margin: 0 .25rem .25rem 0; }

/*
 * Barre d'actions de masse, révélée par la sélection (§5.6.4).
 *
 * Cocher des lignes fait entrer dans un mode : la barre est donc teintée, pour qu'on voie
 * qu'on n'est plus en simple consultation et que l'action portera sur une sélection.
 */
.crm-bulk-bar { display: none; }
.crm-bulk-bar.is-visible {
    display: flex;
    background: var(--crm-primary-soft) !important;
    border-bottom: 1px solid rgba(47, 91, 234, .25);
    box-shadow: inset 3px 0 0 var(--crm-primary);
}
.crm-bulk-bar [data-crm-bulk-count] { color: var(--crm-primary-dark); }

/* Cases et boutons radio natifs alignés sur la couleur de l'application. */
input[type="checkbox"],
input[type="radio"] { accent-color: var(--crm-primary); }

.pagination { font-size: .875rem; margin: 0; gap: .2rem; }
.page-item { margin: 0; }
.page-link {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-sm) !important;
    color: var(--crm-slate-600);
    min-width: 2rem;
    text-align: center;
    padding: .3rem .55rem;
    transition: all var(--crm-ease);
}
.page-link:hover {
    background: var(--crm-slate-50);
    border-color: var(--crm-slate-400);
    color: var(--crm-slate-900);
}
.page-item.active .page-link {
    background: var(--crm-primary);
    border-color: var(--crm-primary-dark);
    color: #fff;
    box-shadow: 0 1px 3px rgba(47, 91, 234, .3);
}

/* ================================================================== Fiche détail */

.crm-block .card-header { cursor: pointer; }
.crm-block-label {
    font-size: .72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--crm-text-muted);
    margin-bottom: .1rem;
}
.crm-block-value { font-size: .9rem; margin-bottom: .75rem; word-break: break-word; }
.crm-block-value:last-child { margin-bottom: 0; }

/* Champ éditable en ligne (§6.7.1) : l'affordance n'apparaît qu'au survol. */
.crm-inline-edit {
    border-bottom: 1px dashed transparent;
    cursor: text;
    border-radius: 2px;
    transition: background var(--crm-ease);
}
.crm-inline-edit:hover { border-bottom-color: var(--crm-slate-400); background: var(--crm-slate-50); }

/*
 * Fil d'avancement d'un pipeline (§8.4.4).
 *
 * Des chevrons plutôt que des pastilles : un pipeline est un chemin, et la forme doit le dire
 * sans qu'on lise les libellés. Le remplissage s'arrête à la phase courante, ce qui donne
 * l'avancement au premier regard.
 *
 * Le fil défile horizontalement au lieu de passer à la ligne. Un pipeline de huit phases
 * réparties sur trois lignes perd son sens de lecture : on ne sait plus laquelle suit
 * laquelle.
 */
.crm-pipeline-head { display: flex; align-items: baseline; gap: .6rem; margin-bottom: .45rem; }

.crm-pipeline-heading {
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--crm-slate-500);
    margin: 0;
}

.crm-pipeline-name { font-size: .8rem; color: var(--crm-slate-500); }

.crm-pipeline {
    display: flex;
    align-items: stretch;
    overflow-x: auto;
    padding-bottom: .3rem;
    margin-bottom: .6rem;
    scrollbar-width: thin;
}

.crm-pipeline-step {
    flex: 1 0 auto;
    min-width: 7.5rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .1rem;
    padding: .45rem .7rem .45rem 1.35rem;
    margin-left: -0.62rem;
    border: 0;
    background: var(--crm-slate-100);
    color: var(--crm-slate-600);
    font-size: .78rem;
    line-height: 1.25;
    text-align: left;
    white-space: nowrap;
    /* La pointe et l'encoche donnent le chevron ; la première n'a pas d'encoche. */
    clip-path: polygon(0 0, calc(100% - .62rem) 0, 100% 50%, calc(100% - .62rem) 100%, 0 100%, .62rem 50%);
    transition: background var(--crm-ease), color var(--crm-ease);
}

.crm-pipeline-step:first-child {
    margin-left: 0;
    padding-left: .8rem;
    clip-path: polygon(0 0, calc(100% - .62rem) 0, 100% 50%, calc(100% - .62rem) 100%, 0 100%);
}

.crm-pipeline-step:last-child {
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, .62rem 50%);
}

.crm-pipeline-step:first-child:last-child { clip-path: none; border-radius: var(--crm-radius-sm); }

/* Phase franchie : assez marquée pour se distinguer du reste à venir, pas plus. */
.crm-pipeline-step.is-past { background: var(--crm-slate-300); color: var(--crm-slate-800); }
.crm-pipeline-tick { font-size: .62rem; margin-right: .2rem; opacity: .75; }

/* Phase courante : sa propre teinte, avec une encre calculée pour rester lisible dessus. */
.crm-pipeline-step.is-current {
    background: var(--step-color, var(--crm-primary));
    color: var(--step-ink, #fff);
    font-weight: 600;
    z-index: 1;
}

.crm-pipeline-since { font-size: .68rem; opacity: .85; font-weight: 400; }

/* Une phase cliquable se signale au survol ; les autres ne bougent pas. */
button.crm-pipeline-step { cursor: pointer; }
button.crm-pipeline-step:hover { background: var(--crm-slate-200); color: var(--crm-slate-900); }
button.crm-pipeline-step:focus-visible { outline: 2px solid var(--crm-primary); outline-offset: -2px; }
.crm-pipeline-step.is-terminal { font-style: italic; opacity: .7; }

.crm-pipeline-facts {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem 1.1rem;
    font-size: .82rem;
    color: var(--crm-slate-600);
    margin-bottom: .6rem;
}

.crm-pipeline-fact b { color: var(--crm-slate-900); font-weight: 600; }

.crm-pipeline-stale {
    font-size: .82rem;
    color: #96601a;
    background: #fdf6e7;
    border-left: 3px solid var(--crm-amber);
    padding: .45rem .7rem;
    border-radius: 0 var(--crm-radius-sm) var(--crm-radius-sm) 0;
    margin-bottom: .6rem;
}

.crm-pipeline-history { margin-bottom: 1rem; }
.crm-pipeline-history > summary { font-size: .82rem; color: var(--crm-slate-500); cursor: pointer; }
.crm-pipeline-history > summary:hover { color: var(--crm-primary); }

/*
 * Zone de dépôt de fichier (§6.7.2).
 *
 * Basse à dessein : deux lignes suffisent à désigner une cible de dépôt, et la place du
 * panneau doit rester à la catégorie et à la description. Les zones hautes qu'on voit
 * ailleurs n'aident pas à viser, elles repoussent seulement le reste du formulaire.
 *
 * Le champ natif couvre toute la surface plutôt que d'être masqué : le clic, le clavier et
 * le dépôt marchent alors sans une ligne de JavaScript, et le glisser-déposer reste un
 * raccourci qu'on peut perdre sans rien casser.
 */
.crm-dropzone {
    position: relative;
    border: 1.5px dashed var(--crm-slate-300);
    border-radius: var(--crm-radius);
    background: var(--crm-slate-50);
    transition: border-color var(--crm-ease), background var(--crm-ease);
    margin-bottom: .5rem;
}

.crm-dropzone-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.crm-dropzone-face {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .55rem;
    padding: .85rem 1rem;
    pointer-events: none;
    color: var(--crm-slate-600);
    font-size: .875rem;
}

.crm-dropzone-face i { font-size: 1.1rem; color: var(--crm-slate-400); }
.crm-dropzone-link { color: var(--crm-primary); text-decoration: underline; }

.crm-dropzone:hover,
.crm-dropzone-input:focus-visible + .crm-dropzone-face { border-color: var(--crm-primary); }
.crm-dropzone:hover { border-color: var(--crm-primary); background: var(--crm-primary-soft, #eef2fe); }

/* État pendant le survol d'un fichier glissé, posé par le JavaScript. */
.crm-dropzone.is-dragover {
    border-color: var(--crm-primary);
    border-style: solid;
    background: var(--crm-primary-soft, #eef2fe);
}

/* Fichier choisi : la zone le dit, sinon on ne sait pas si le dépôt a été pris. */
.crm-dropzone.is-filled { border-style: solid; border-color: var(--crm-success, #12855f); background: #fff; }
.crm-dropzone.is-filled .crm-dropzone-face { color: var(--crm-slate-800); font-weight: 500; }
.crm-dropzone.is-filled .crm-dropzone-face i { color: var(--crm-success, #12855f); }

.crm-window-target { font-size: .875rem; color: var(--crm-slate-600); margin-bottom: .9rem; }

/*
 * Tâches ouvertes d'une fiche (§10.4).
 *
 * Placées avant la timeline, elles disent ce qu'il reste à faire là où celle-ci dit ce qui a
 * été fait. La coche est volontairement grande et à gauche : terminer une tâche est le geste
 * le plus fréquent de cet encart, il ne doit pas demander de viser.
 */
.crm-tasks-card .card-header { background: var(--crm-slate-50); }

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

.crm-task-row {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    padding: .55rem .9rem;
    border-bottom: 1px solid var(--crm-slate-100);
}

.crm-task-row:last-child { border-bottom: 0; }
.crm-task-row:hover { background: var(--crm-slate-50); }

/* Une échéance dépassée se voit au bord, sans lire la date. */
.crm-task-row.is-overdue { box-shadow: inset 3px 0 0 var(--crm-danger, #cf3040); }

.crm-task-check { margin: .1rem 0 0; }

.crm-task-tick {
    width: 1.15rem;
    height: 1.15rem;
    padding: 0;
    border: 1.5px solid var(--crm-slate-400);
    border-radius: 50%;
    background: transparent;
    cursor: pointer;
    position: relative;
    transition: border-color var(--crm-ease), background var(--crm-ease);
}

.crm-task-tick::after {
    content: '';
    position: absolute;
    left: .28rem;
    top: .12rem;
    width: .3rem;
    height: .55rem;
    border: solid transparent;
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
    transition: border-color var(--crm-ease);
}

.crm-task-tick:hover { border-color: var(--crm-success, #12855f); background: var(--crm-success, #12855f); }
.crm-task-tick:hover::after { border-color: #fff; }
.crm-task-tick:focus-visible { outline: 2px solid var(--crm-primary); outline-offset: 2px; }

.crm-task-main { flex: 1 1 auto; min-width: 0; }

.crm-task-title {
    display: block;
    font-size: .9rem;
    font-weight: 500;
    color: var(--crm-slate-800);
    line-height: 1.3;
}

.crm-task-title:hover { color: var(--crm-primary); }

.crm-task-meta { font-size: .78rem; color: var(--crm-slate-500); line-height: 1.4; }

.crm-task-postpone { margin: 0; flex: 0 0 auto; }

/*
 * Adresse postale d'une fiche.
 *
 * Une adresse se lit d'un tenant : la voie, puis le code postal et la ville sur la ligne
 * suivante. Ses trois parties se corrigent pourtant séparément, d'où trois valeurs distinctes
 * mises en ligne plutôt qu'empilées : l'affichage reste celui d'une adresse, sans renoncer à
 * pouvoir changer un code postal sans toucher au reste.
 *
 * La largeur minimale des parties est ce qui rend une valeur vide cliquable : un tiret seul
 * offre une cible de quelques pixels, qu'on manque une fois sur deux.
 */
.crm-address .crm-address-street { display: block; }
.crm-address-locality { display: flex; align-items: baseline; gap: .35rem; }
.crm-address .crm-address-part { display: inline-block; min-width: 2.5rem; margin-bottom: 0; }

/*
 * Listes déroulantes de l'édition en place.
 *
 * Les options portent la même pastille et le même point que la valeur affichée sur la fiche.
 * Ce n'est pas une coquetterie : sans elle, on lit un badge vert « Ressource » puis on choisit
 * dans une liste de texte gris, et il faut relire pour se convaincre qu'il s'agit bien de la
 * même valeur. Avec, la couleur suffit à la reconnaître.
 */
.crm-inline-edit .select2-container { min-width: 100%; }
.crm-inline-edit .select2-selection { border-color: var(--crm-slate-300); }

/*
 * Le menu se lit en entier, quelle que soit la largeur de la cellule qui l'ouvre.
 *
 * Select2 recopie la largeur du conteneur dans un style **en ligne** sur le menu. Dans la
 * colonne « Statut » d'une liste, mesuré : 77 px de large, un débordement horizontal de 24 px
 * avec sa barre de défilement, et « Validé pour entretien » replié sur trois lignes, 84 px de
 * haut au lieu de 36. Les sept options réclamaient 348 px pour 225 visibles : on faisait défiler
 * une liste de sept valeurs, dont aucune n'était lisible en entier.
 *
 * `min-width` suffit, et c'est la raison de l'employer plutôt qu'une largeur : il l'emporte sur
 * une largeur en ligne plus petite **par la cascade**, sans `!important`. Le menu garde donc la
 * largeur du champ partout où celle-ci est déjà suffisante, une fiche par exemple, et ne
 * s'élargit que là où il le faut.
 *
 * Le menu est posé sur le `<body>`, hors de `.crm-inline-edit` : la classe lui est donnée à
 * l'ouverture par `dropdownCssClass`, il n'y a pas de sélecteur descendant possible.
 */
.select2-dropdown.crm-inline-dropdown { min-width: 15rem; }

/*
 * Une liste de statuts se voit en entier.
 *
 * Le theme plafonne les résultats à 15 em, soit 240 px : les sept statuts d'un positionnement en
 * réclament 252, et le septième restait sous le bord. Faire défiler une liste de sept valeurs
 * pour atteindre la dernière est le genre de détail qui fait croire à un écran cassé. 22 rem en
 * tiennent neuf, au-delà de quoi le défilement est légitime.
 */
.select2-dropdown.crm-inline-dropdown .select2-results > .select2-results__options { max-height: 22rem; }

/*
 * Une option tient sur une ligne et se tronque, comme une cellule de liste.
 *
 * Le repliage était le symptôme le plus visible du menu trop étroit ; l'élargir suffit dans
 * l'immense majorité des cas, mais un libellé long dans un champ de relation (le nom complet
 * d'une entreprise) le ferait revenir. Une option sur deux lignes casse l'alignement de toutes
 * les autres et rend la hauteur du menu imprévisible.
 */
.select2-dropdown.crm-inline-dropdown .select2-results__option {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.select2-results__option .crm-option-badge,
.select2-selection__rendered .crm-option-badge { vertical-align: middle; }

.select2-results__option .crm-option-dot,
.select2-selection__rendered .crm-option-dot { vertical-align: middle; }

/*
 * Étiquettes d'une liste à choix multiples.
 *
 * Select2 pose son propre fond gris et sa propre bordure sur chaque valeur retenue ; le badge
 * coloré qu'on y glisse s'en trouvait cerné d'un liseré qui en cassait la couleur. On efface
 * donc le fond de l'étiquette et on laisse le badge la porter, la croix de suppression restant
 * lisible parce qu'elle passe en blanc.
 */
.crm-inline-edit .select2-selection--multiple .select2-selection__choice {
    background: transparent;
    border: 0;
    padding: 0 0 0 1.1rem;
    margin: .15rem .25rem .15rem 0;
    position: relative;
}

.crm-inline-edit .select2-selection--multiple .select2-selection__choice__remove {
    position: absolute;
    left: .2rem;
    top: 50%;
    transform: translateY(-50%);
    margin: 0;
    color: var(--crm-slate-500);
    font-size: 1rem;
    line-height: 1;
}

.crm-inline-edit .select2-selection--multiple .select2-selection__choice__remove:hover {
    color: var(--crm-danger, #cf3040);
}

/* ------------------------------------------------------------------ Coordonnées */

/*
 * Bandeau de coordonnées de la fiche (§6.3.2).
 *
 * L'e-mail et le téléphone sont les deux informations qu'on vient chercher le plus
 * souvent sur une fiche, et les deux qu'on veut soit ouvrir, soit copier. Chacun devient
 * donc une ligne cliquable sur toute sa largeur, avec son bouton de copie révélé au
 * survol : plutôt qu'un lien nu suivi d'une icône minuscule.
 */
.crm-contact-rows { display: flex; flex-direction: column; gap: .35rem; text-align: left; }

.crm-contact-row {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .4rem .5rem;
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border-soft);
    border-radius: var(--crm-radius);
    transition: background var(--crm-ease), border-color var(--crm-ease), box-shadow var(--crm-ease);
}
.crm-contact-row:hover {
    background: var(--crm-surface);
    border-color: var(--crm-border);
    box-shadow: var(--crm-shadow-sm);
}

.crm-contact-row-icon {
    flex: 0 0 auto;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: var(--crm-radius-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .72rem;
    background: var(--crm-slate-100);
    color: var(--crm-slate-600);
}
.crm-contact-row-icon.is-mail  { background: var(--crm-primary-soft); color: var(--crm-primary); }
.crm-contact-row-icon.is-phone { background: var(--crm-success-soft); color: var(--crm-success); }

/*
 * La valeur seule sur une ligne : l'icône dit déjà de quoi il s'agit, et un libellé
 * « E-MAIL » au-dessus doublait la hauteur de chaque ligne dans une colonne étroite. La
 * nature du champ reste annoncée aux lecteurs d'écran par l'aria-label du lien.
 */
.crm-contact-row-value {
    flex: 1 1 auto;
    min-width: 0;
    font-size: .82rem;
    font-weight: 500;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Le bouton de copie n'encombre pas la ligne au repos, mais reste atteignable au clavier. */
.crm-contact-row-copy {
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--crm-radius-sm);
    background: transparent;
    color: var(--crm-text-faint);
    font-size: .7rem;
    opacity: 0;
    transition: all var(--crm-ease);
}
.crm-contact-row:hover .crm-contact-row-copy,
.crm-contact-row:focus-within .crm-contact-row-copy { opacity: 1; }
.crm-contact-row-copy:hover {
    background: var(--crm-surface);
    border-color: var(--crm-border);
    color: var(--crm-primary);
}
/* Confirmation de copie : la coche remplace l'icône une seconde, sans message à lire. */
.crm-contact-row-copy.is-copied { opacity: 1; color: var(--crm-success); border-color: var(--crm-success); background: var(--crm-success-soft); }

/* ------------------------------------------------------------------ Barre d'activités */

/*
 * Rangée de pastilles rondes de la colonne d'identité, relevée sur HubSpot : un cercle
 * bordé, l'icône dedans, le libellé dessous. Plus léger qu'une tuile encadrée : la colonne
 * est étroite et déjà dense en informations, la barre ne doit pas y peser autant qu'une
 * carte.
 */
.crm-activity-icons {
    display: flex;
    justify-content: space-between;
    gap: .25rem;
}

.crm-activity-icon {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .3rem;
    padding: 0;
    font-size: .64rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--crm-slate-600);
    text-align: center;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color var(--crm-ease);
}
.crm-activity-icon:hover { text-decoration: none; }

.crm-activity-icon-circle {
    width: 2.35rem;
    height: 2.35rem;
    border: 1px solid var(--crm-border);
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--crm-surface);
    color: var(--crm-slate-600);
    font-size: .85rem;
    transition: all var(--crm-ease);
}
.crm-activity-icon:hover .crm-activity-icon-circle {
    box-shadow: var(--crm-shadow-sm);
    transform: translateY(-1px);
}

/* La couleur par nature d'action, déjà établie pour les tuiles, s'applique au cercle. */
.crm-activity-icon.crm-qa-note:hover { color: var(--crm-warning); }
.crm-activity-icon.crm-qa-note:hover .crm-activity-icon-circle {
    border-color: var(--crm-warning);
    background: var(--crm-warning-soft);
    color: var(--crm-warning);
}
.crm-activity-icon.crm-qa-mail:hover { color: var(--crm-primary); }
.crm-activity-icon.crm-qa-mail:hover .crm-activity-icon-circle {
    border-color: var(--crm-primary);
    background: var(--crm-primary-soft);
    color: var(--crm-primary);
}
.crm-activity-icon.crm-qa-call:hover { color: var(--crm-success); }
.crm-activity-icon.crm-qa-call:hover .crm-activity-icon-circle {
    border-color: var(--crm-success);
    background: var(--crm-success-soft);
    color: var(--crm-success);
}
.crm-activity-icon.crm-qa-task:hover { color: var(--crm-info); }
.crm-activity-icon.crm-qa-task:hover .crm-activity-icon-circle {
    border-color: var(--crm-info);
    background: var(--crm-info-soft);
    color: var(--crm-info);
}
.crm-activity-icon.crm-qa-meet:hover { color: #6435c9; }
.crm-activity-icon.crm-qa-meet:hover .crm-activity-icon-circle {
    border-color: #6435c9;
    background: #f0eaff;
    color: #6435c9;
}
/*
 * Le SMS prend un rose profond, et le choix se fait par élimination : les cinq autres tiennent
 * le bleu, le vert, l'or, le turquoise et le violet, et le rouge appartient au danger. Une
 * couleur déjà prise aurait rendu la barre illisible d'un coup d'œil, ce qui est la seule
 * chose que ces couleurs servent à faire.
 */
.crm-activity-icon.crm-qa-sms:hover { color: #a32178; }
.crm-activity-icon.crm-qa-sms:hover .crm-activity-icon-circle {
    border-color: #a32178;
    background: #fbe9f4;
    color: #a32178;
}

/* ------------------------------------------------------------------ Actions rapides */

/*
 * Actions rapides d'une fiche (§6.3.2, §6.4.2).
 *
 * Cinq icônes nues accolées en un seul bloc n'apprenaient rien : il fallait survoler
 * chacune pour savoir ce qu'elle faisait. Chaque action devient une tuile (pastille
 * colorée par nature d'action, libellé sous l'icône) assez compacte pour tenir à cinq
 * dans une colonne étroite, et assez explicite pour être lue d'un coup.
 */
/*
 * Une seule rangée, cinq colonnes égales.
 *
 * Un `auto-fit` se réorganisait selon la largeur disponible (trois tuiles puis deux, ou
 * deux puis deux puis une dans une colonne étroite) et la bande changeait de forme d'un
 * écran à l'autre. Cinq colonnes fixes conservent la disposition d'origine (les cinq
 * actions côte à côte) et la position de chaque action reste mémorisable.
 */
.crm-quick-actions {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: .3rem;
}

/*
 * Variante horizontale, pour la zone centrale.
 *
 * La base flex est volontairement courte : à 10 rem, cinq tuiles réclamaient 800 px et la
 * cinquième passait à la ligne, où elle s'étirait sur toute la largeur, une bande à quatre
 * plus une, du plus mauvais effet. À 6 rem elles tiennent sur une ligne dès 480 px, et se
 * partagent l'espace disponible à parts égales.
 */
.crm-quick-actions-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.crm-quick-actions-row .crm-quick-action {
    flex: 1 1 6rem;
    min-width: 0;
    flex-direction: row;
    justify-content: center;
    gap: .5rem;
    padding: .6rem .5rem;
    font-size: .78rem;
    text-align: left;
}

.crm-quick-action {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .3rem;
    padding: .5rem .15rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    color: var(--crm-slate-600);
    font-size: .64rem;
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: all var(--crm-ease);
}
.crm-quick-action:hover {
    text-decoration: none;
    box-shadow: var(--crm-shadow-sm);
    transform: translateY(-1px);
}

.crm-quick-action i {
    flex: 0 0 auto;
    width: 1.7rem;
    height: 1.7rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .72rem;
    background: var(--crm-slate-100);
    color: var(--crm-slate-600);
    transition: all var(--crm-ease);
}

/* La variante horizontale a de la place : elle garde une icône et un texte de pleine taille. */
.crm-quick-actions-row .crm-quick-action i { width: 1.9rem; height: 1.9rem; font-size: .8rem; }

/*
 * Une couleur par nature d'action : on finit par reconnaître « la tuile jaune » sans
 * lire. La pastille se remplit au survol, ce qui confirme la cible du clic.
 */
.crm-qa-note i  { background: var(--crm-warning-soft); color: var(--crm-warning); }
.crm-qa-note:hover  { border-color: var(--crm-warning); color: var(--crm-warning); }
.crm-qa-note:hover i  { background: var(--crm-warning); color: #fff; }

.crm-qa-mail i  { background: var(--crm-primary-soft); color: var(--crm-primary); }
.crm-qa-mail:hover  { border-color: var(--crm-primary); color: var(--crm-primary); }
.crm-qa-mail:hover i  { background: var(--crm-primary); color: #fff; }

.crm-qa-call i  { background: var(--crm-success-soft); color: var(--crm-success); }
.crm-qa-call:hover  { border-color: var(--crm-success); color: var(--crm-success); }
.crm-qa-call:hover i  { background: var(--crm-success); color: #fff; }

.crm-qa-task i  { background: var(--crm-info-soft); color: var(--crm-info); }
.crm-qa-task:hover  { border-color: var(--crm-info); color: var(--crm-info); }
.crm-qa-task:hover i  { background: var(--crm-info); color: #fff; }

.crm-qa-meet i  { background: #f0eaff; color: #6435c9; }
.crm-qa-meet:hover  { border-color: #6435c9; color: #6435c9; }
.crm-qa-meet:hover i  { background: #6435c9; color: #fff; }

/*
 * La tuile SMS n'est posée par aucun écran livré, la carte « Actions rapides » ne portant que
 * les trois gestes les plus fréquents. Sa couleur est déclarée quand même : l'encart composé
 * d'actions peut la placer, et une tuile sans couleur au milieu de cinq colorées se lit comme
 * un défaut d'affichage.
 */
.crm-qa-sms i  { background: #fbe9f4; color: #a32178; }
.crm-qa-sms:hover  { border-color: #a32178; color: #a32178; }
.crm-qa-sms:hover i  { background: #a32178; color: #fff; }

/* Timeline d'activités (§10.3.1). */
.crm-timeline { position: relative; padding-left: 2.25rem; }
.crm-timeline::before {
    content: '';
    position: absolute;
    left: .85rem;
    top: .25rem;
    bottom: .25rem;
    width: 2px;
    background: var(--crm-border);
}
.crm-timeline-item { position: relative; padding-bottom: 1.1rem; }
.crm-timeline-icon {
    position: absolute;
    left: -2.25rem;
    top: 0;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: .7rem;
    box-shadow: 0 0 0 3px var(--crm-surface);
}
/* Le menu d'actions d'une entrée ne se révèle qu'au survol : la chronologie se lit
   d'abord, elle ne se corrige qu'ensuite. */
.crm-timeline-actions { opacity: 0; transition: opacity var(--crm-ease); }
.crm-timeline-item:hover .crm-timeline-actions,
.crm-timeline-item:focus-within .crm-timeline-actions,
.crm-timeline-actions.show { opacity: 1; }

.crm-timeline-day {
    font-size: .72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--crm-text-muted);
    margin: .5rem 0;
}

/* ================================================================== Parcours de phases */

/*
 * Bandeau de suivi de phase (§8.4.4), dessiné en chevrons : la direction du parcours
 * se lit dans la forme, sans avoir à comparer des couleurs.
 */
.crm-stage-tracker { display: flex; flex-wrap: wrap; gap: .3rem; }

.crm-stage-step {
    flex: 1 1 0;
    min-width: 7.5rem;
    position: relative;
    padding: .45rem .6rem;
    font-size: .78rem;
    font-weight: 500;
    text-align: center;
    background: var(--crm-slate-100);
    color: var(--crm-slate-600);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-sm);
}
.crm-stage-step.is-current { color: #fff; font-weight: 600; border-color: transparent; }
.crm-stage-step.is-past { background: var(--crm-slate-200); color: var(--crm-slate-700); }
.crm-stage-step-meta { font-size: .68rem; opacity: .8; margin-top: .1rem; }

/*
 * Aperçu du parcours dans la configuration : chevrons enchaînés, avec la couleur réelle
 * de chaque phase en liseré supérieur. C'est ce que verra le commercial.
 */
.crm-flow {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
    align-items: stretch;
}
.crm-flow-step {
    flex: 1 1 8rem;
    min-width: 8rem;
    position: relative;
    padding: .5rem .65rem .55rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-top: 3px solid var(--crm-slate-400);
    border-radius: var(--crm-radius-sm);
    box-shadow: var(--crm-shadow-sm);
}
.crm-flow-step-name {
    display: block;
    font-size: .8rem;
    font-weight: 600;
    color: var(--crm-slate-800);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.crm-flow-step-proba {
    font-size: .7rem;
    font-weight: 600;
    color: var(--crm-text-muted);
    letter-spacing: .01em;
}
.crm-flow-step-meta {
    display: flex;
    flex-wrap: wrap;
    gap: .2rem;
    margin-top: .3rem;
}
.crm-flow-step-meta .fas { font-size: .62rem; color: var(--crm-text-faint); }

/* Jauge de probabilité : une valeur en pourcentage se compare mieux qu'elle ne se lit. */
.crm-meter {
    height: 4px;
    border-radius: 2px;
    background: var(--crm-slate-200);
    overflow: hidden;
    margin-top: .35rem;
}
.crm-meter > span { display: block; height: 100%; border-radius: 2px; background: var(--crm-primary); }

/* ================================================================== Éditeur de phases */

/*
 * Liste des phases d'un pipeline. Un tableau à sept colonnes devenait illisible :
 * chaque phase occupe désormais une ligne à deux niveaux (identité à gauche, règles
 * à droite) et se déplace par glisser-déposer sur sa poignée.
 */
.crm-stage-list { list-style: none; margin: 0; padding: 0; }

.crm-stage-row {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    padding: .8rem 1.15rem;
    border-bottom: 1px solid var(--crm-border-soft);
    background: var(--crm-surface);
    transition: background var(--crm-ease);
}
.crm-stage-row:last-child { border-bottom: 0; }
.crm-stage-row:hover { background: var(--crm-slate-50); }

.crm-stage-handle {
    flex: 0 0 auto;
    width: 1.4rem;
    padding-top: .35rem;
    color: var(--crm-slate-300);
    cursor: grab;
    text-align: center;
    font-size: .85rem;
}
.crm-stage-row:hover .crm-stage-handle { color: var(--crm-slate-500); }
.crm-stage-handle:active { cursor: grabbing; }

/* Vignette colorée portant la position : le repère visuel de la phase. */
.crm-stage-marker {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    border-radius: var(--crm-radius);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: .78rem;
    font-weight: 700;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08);
}

.crm-stage-main { flex: 1 1 auto; min-width: 0; }
.crm-stage-name {
    font-size: .9rem;
    font-weight: 600;
    color: var(--crm-slate-800);
    text-decoration: none;
}
.crm-stage-name:hover { color: var(--crm-primary); text-decoration: underline; }

.crm-stage-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .3rem;
    margin-top: .35rem;
}

.crm-stage-side {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .9rem;
    padding-top: .1rem;
}

/* Compteur « n besoins » adossé à chaque phase. */
.crm-stage-count { text-align: right; min-width: 4.2rem; }
.crm-stage-count-value { font-size: 1.05rem; font-weight: 600; color: var(--crm-slate-800); line-height: 1.1; }
.crm-stage-count-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; color: var(--crm-text-faint); }
.crm-stage-count-value.is-zero { color: var(--crm-slate-300); }

.crm-stage-actions { display: flex; gap: .25rem; opacity: .4; transition: opacity var(--crm-ease); }
.crm-stage-row:hover .crm-stage-actions,
.crm-stage-row:focus-within .crm-stage-actions { opacity: 1; }

/* États du glisser-déposer. */
.crm-stage-row.is-dragging { opacity: .5; }
.crm-stage-placeholder {
    height: 3.6rem;
    margin: 0;
    background: var(--crm-primary-soft);
    border: 2px dashed var(--crm-primary);
    border-radius: var(--crm-radius);
}
.crm-sortable-helper {
    box-shadow: var(--crm-shadow-lg);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    background: var(--crm-surface) !important;
}

/* Sélecteur de couleur de phase : la valeur hexadécimale reste visible et modifiable. */
.crm-color-field { display: flex; align-items: center; gap: .5rem; }
.crm-color-field input[type="color"] {
    width: 2.6rem;
    height: calc(2.4rem + 2px);
    padding: .2rem;
    border: 1px solid var(--crm-slate-300);
    border-radius: var(--crm-radius);
    background: var(--crm-surface);
    cursor: pointer;
    flex: 0 0 auto;
}

/* ================================================================== Statistiques */

/* Tuile de chiffre clé, utilisée en tête d'écran de configuration ou de tableau de bord. */
.crm-stat-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.crm-stat {
    flex: 1 1 7rem;
    padding: .6rem .8rem;
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border-soft);
    border-radius: var(--crm-radius);
}
.crm-stat-value { font-size: 1.25rem; font-weight: 600; color: var(--crm-slate-900); line-height: 1.15; }
.crm-stat-label {
    font-size: .68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--crm-text-muted);
    margin-top: .1rem;
}

/* ================================================================== Kanban (§8.3) */

.crm-kanban { display: flex; gap: .75rem; overflow-x: auto; padding-bottom: .5rem; align-items: flex-start; }

.crm-kanban-column {
    flex: 0 0 18rem;
    background: var(--crm-slate-100);
    border-radius: var(--crm-radius);
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 15rem);
}

.crm-kanban-header { padding: .55rem .7rem; border-bottom: 3px solid var(--crm-slate-400); }
.crm-kanban-title {
    font-size: .78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--crm-slate-700);
}
.crm-kanban-body { overflow-y: auto; padding: .5rem; flex: 1 1 auto; min-height: 4rem; }
.crm-kanban-footer {
    padding: .45rem .7rem;
    border-top: 1px solid var(--crm-border);
    font-size: .75rem;
    color: var(--crm-slate-600);
}

.crm-kanban-card {
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    box-shadow: var(--crm-shadow-sm);
    padding: .6rem .7rem;
    margin-bottom: .5rem;
    cursor: grab;
    font-size: .8rem;
    transition: box-shadow var(--crm-ease), transform var(--crm-ease);
}
.crm-kanban-card:hover { box-shadow: var(--crm-shadow); transform: translateY(-1px); }
.crm-kanban-card:last-child { margin-bottom: 0; }
.crm-kanban-card.is-dragging { opacity: .45; }
.crm-kanban-card-title { font-weight: 600; display: block; margin-bottom: .3rem; color: var(--crm-slate-800); }
.crm-kanban-card-title:hover { text-decoration: underline; }

/* Cible de dépôt mise en évidence pendant le glisser (§8.3.4). */
.crm-kanban-column.is-drop-target .crm-kanban-body {
    background: var(--crm-primary-soft);
    outline: 2px dashed var(--crm-primary);
    outline-offset: -4px;
    border-radius: var(--crm-radius-sm);
}

/* ================================================================== Divers */

/* État vide : on dit ce qui manque et on propose l'action qui le comble. */
.crm-empty { padding: 2.5rem 1rem; text-align: center; color: var(--crm-text-muted); }
.crm-empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    background: var(--crm-slate-100);
    color: var(--crm-slate-400);
    font-size: 1.25rem;
    margin-bottom: .85rem;
}
.crm-empty-title { font-size: .95rem; font-weight: 600; color: var(--crm-slate-700); margin-bottom: .3rem; }
.crm-empty-text { font-size: .85rem; max-width: 46ch; margin: 0 auto; }

.crm-stale { color: #d1670c; }
.crm-sensitive { font-family: var(--crm-font-mono); letter-spacing: .05em; }

/* Le tableau d'une section d'objets liés reste compact sur la fiche détail. */
.crm-related-table td, .crm-related-table th { padding: .4rem .55rem; font-size: .8rem; }

.main-footer {
    background: var(--crm-surface);
    border-top: 1px solid var(--crm-border);
    color: var(--crm-text-muted);
    padding: .85rem 1.15rem;
}

/* Notifications transitoires alignées sur le reste de l'interface. */
#toast-container > div {
    border-radius: var(--crm-radius);
    box-shadow: var(--crm-shadow-lg);
    opacity: 1;
    font-size: .875rem;
}

@media (max-width: 991.98px) {
    .crm-kanban-column { flex-basis: 15rem; }
    .crm-global-search { min-width: 10rem; }
    .crm-page-actions { justify-content: flex-start; margin-top: .75rem; }
    .crm-stage-row { flex-wrap: wrap; }
    .crm-stage-side { width: 100%; justify-content: flex-end; }
}

@media (max-width: 575.98px) {
    .content-header h1 { font-size: 1.25rem; }
    .crm-stage-handle { display: none; }
}

/* Le glisser-déposer n'a pas de sens au clavier ni au doigt : les flèches restent. */
@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

/* ============================================================================
   Sélecteur de colonnes et colonnes figées (§5.5.1)
   ============================================================================ */

/* Les deux volets défilent indépendamment : le catalogue d'un contact tient une
   cinquantaine de champs, la sélection en tient dix. */
.crm-column-editor .crm-column-catalog {
    max-height: 26rem;
    overflow-y: auto;
}

.crm-column-chip {
    display: flex;
    align-items: center;
    padding: .4rem .6rem;
    margin-bottom: .35rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-sm);
    cursor: grab;
}

.crm-column-chip:hover { border-color: var(--crm-slate-300); }
.crm-column-chip.is-dragging { opacity: .6; }
.crm-column-chip .close { font-size: 1rem; line-height: 1; opacity: .5; }
.crm-column-chip .close:hover { opacity: 1; }

.crm-column-chip-placeholder {
    height: 2.1rem;
    margin-bottom: .35rem;
    background: var(--crm-primary-soft);
    border: 1px dashed var(--crm-primary);
    border-radius: var(--crm-radius-sm);
}

/* Colonnes figées : le décalage horizontal de chacune est posé en ligne par le
   gabarit, qui seul connaît la largeur des précédentes. */
.crm-table th.crm-frozen,
.crm-table td.crm-frozen {
    position: sticky;
    z-index: 2;
    background: var(--crm-surface);
}

.crm-table thead th.crm-frozen { z-index: 3; }

/* Sur une ligne zébrée, une cellule figée transparente laisserait défiler le
   contenu des colonnes voisines sous elle. */
.crm-table.table-striped tbody tr:nth-of-type(odd) td.crm-frozen { background: var(--crm-slate-50); }
.crm-table.table-hover tbody tr:hover td.crm-frozen { background: var(--crm-primary-soft); }

/* Le bord droit de la dernière colonne figée marque la limite du défilement. */
.crm-table th.crm-frozen-last,
.crm-table td.crm-frozen-last { border-right: 2px solid var(--crm-border); }

/* Bandeau d'état non enregistré : assez visible pour être vu, assez sobre pour ne pas
   masquer le tableau qu'il commente. */
.crm-view-dirty {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    background: var(--crm-warning-soft);
    border-bottom: 1px solid var(--crm-border);
}

@media (max-width: 767.98px) {
    .crm-column-editor .border-right { border-right: 0 !important; }
    .crm-column-editor .crm-column-catalog { max-height: 18rem; }
}

/* ============================================================================
   Redimensionnement des colonnes (§5.5.1)
   ============================================================================ */

.crm-table th { position: relative; }

/* La poignée déborde volontairement sur la colonne voisine : viser un trait de 1 px
   est un exercice d'adresse, pas une interaction. */
.crm-col-resize {
    position: absolute;
    top: 0;
    right: -3px;
    width: 7px;
    height: 100%;
    cursor: col-resize;
    user-select: none;
    z-index: 4;
}

.crm-col-resize::after {
    content: '';
    position: absolute;
    top: 20%;
    left: 3px;
    width: 1px;
    height: 60%;
    background: var(--crm-border);
    transition: background-color .12s ease;
}

.crm-table th:hover .crm-col-resize::after,
.crm-col-resize:hover::after { background: var(--crm-primary); }

/* Pendant le glissement, le curseur reste col-resize partout et rien ne se sélectionne :
   sortir de l'en-tête ne doit pas interrompre le geste. */
body.crm-resizing { cursor: col-resize; user-select: none; }
body.crm-resizing .crm-col-resize::after { background: var(--crm-primary); }

/* Une colonne à largeur imposée doit couper son contenu, sinon la cellule s'élargit
   d'elle-même et la largeur réglée n'est jamais respectée. */
.crm-table .crm-col-clipped {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ============================================================================
   Modèles d'e-mails (§14.5)
   ============================================================================ */

/* Les variables sont nombreuses : les serrer les rend balayables d'un regard, là où une
   liste verticale obligerait à faire défiler pour en trouver une. */
.crm-variable-list {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
}

.crm-variable-list .btn {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .75rem;
}

/* L'aperçu doit ressembler à un e-mail, pas à un champ de formulaire : fond neutre,
   retours à la ligne préservés, largeur de lecture confortable. */
.crm-email-preview {
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border-soft);
    border-radius: var(--crm-radius-sm);
    padding: .75rem 1rem;
    max-height: 22rem;
    overflow-y: auto;
    line-height: 1.55;
}

/* Le champ de rédaction du corps mérite une police à largeur fixe : les variables
   « {{prenom}} » se relisent mieux, et l'alignement d'une signature devient visible. */
textarea[data-crm-template-field="body"] {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .85rem;
    line-height: 1.5;
}

/* ============================================================================
   Densité de la fiche détail (§6.6)
   ============================================================================ */

/* Le mode compact ne réduit pas la taille du texte, illisible passé un certain point,
   mais l'espace autour : c'est là que se gagnent les lignes à l'écran. */
.crm-density-compact .card { margin-bottom: .5rem; }
.crm-density-compact .card-header.py-2 { padding-top: .25rem !important; padding-bottom: .25rem !important; }
.crm-density-compact .card-body.py-2 { padding-top: .35rem !important; padding-bottom: .35rem !important; }
.crm-density-compact .crm-block-label { margin-bottom: 0; }
.crm-density-compact .crm-block-value { margin-bottom: .4rem; }
.crm-density-compact .table td,
.crm-density-compact .table th { padding-top: .3rem; padding-bottom: .3rem; }

/* ============================================================================
   Consultants retenus à la clôture d'un besoin gagné (§8.6.5)
   ============================================================================ */

/* Une ligne par positionnement : le nom à gauche, les deux taux à droite. La ligne cochée
   se distingue nettement : c'est elle qui va produire une mission, une convention et deux
   commandes, et l'utilisateur doit pouvoir relire sa sélection d'un coup d'œil. */
.crm-winner-list {
    border: 1px solid var(--crm-border-soft);
    border-radius: var(--crm-radius-sm);
    overflow: hidden;
}

.crm-winner-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: .6rem .85rem;
    background: var(--crm-surface);
    border-top: 1px solid var(--crm-border-soft);
}

.crm-winner-row:first-child { border-top: 0; }

.crm-winner-row.is-picked {
    background: var(--crm-success-soft);
    box-shadow: inset 3px 0 0 var(--crm-success);
}

.crm-winner-pick { flex: 1 1 14rem; min-width: 0; }

.crm-winner-name { display: block; font-weight: 600; }

.crm-winner-meta {
    display: block;
    font-size: .8rem;
    color: var(--crm-text-muted);
}

.crm-winner-rates {
    display: flex;
    gap: .5rem;
    margin-left: auto;
}

.crm-winner-rate { width: 8.5rem; }

.crm-winner-rate label {
    display: block;
    margin-bottom: .1rem;
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--crm-text-muted);
}

/* Les taux d'une ligne non retenue restent lisibles mais visiblement inertes : les
   masquer ferait sauter la mise en page à chaque case cochée. */
.crm-winner-row:not(.is-picked) .crm-winner-rates { opacity: .45; }

/* Marqueur d'héritage sur la fiche mission (§9.2).

   Discret : l'information utile est la valeur, pas sa provenance. Mais cliquable, parce que
   la question qui suit : « et si je la corrige ? » : se règle sur le besoin. */
.crm-inherited {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    padding: 0 .3rem;
    border: 1px solid var(--crm-border);
    border-radius: 10rem;
    font-size: .68rem;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
    color: var(--crm-text-muted);
    background: var(--crm-slate-50);
    vertical-align: middle;
}

.crm-inherited:hover {
    color: var(--crm-primary);
    border-color: var(--crm-primary);
    background: var(--crm-primary-soft);
    text-decoration: none;
}

.crm-inherited i { font-size: .6rem; }

/* ============================================================================
   Zones d'encarts de l'écran d'agencement (§6.6)
   ============================================================================ */

/* Les deux colonnes sont des cibles de dépôt : elles doivent se voir comme telles, y compris
   vides, une zone sans repère ne s'offre pas au glisser. */
.crm-layout-zone {
    min-height: 4.5rem;
    padding: .35rem;
    border: 1px dashed var(--crm-border);
    border-radius: var(--crm-radius-sm);
    background: var(--crm-slate-50);
}

.crm-layout-zone-empty {
    padding: .75rem .5rem;
    color: var(--crm-text-faint);
    font-size: .78rem;
    text-align: center;
}

/* Un encart porte désormais deux étages : sa ligne, et son panneau de condition replié. */
.crm-column-chip.is-stacked {
    display: block;
    align-items: initial;
}

.crm-chip-row {
    display: flex;
    align-items: center;
}

.crm-chip-rule {
    margin-top: .5rem;
    padding-top: .5rem;
    border-top: 1px solid var(--crm-border-soft);
}

.crm-chip-rule select { font-size: .78rem; }

/* ---------------------------------------------------------------- Relations qualifiées (§6.8) */

/*
 * Le formulaire de rattachement tient sur une ligne : la fiche à relier, son libellé, le
 * bouton. Empilé, il occupait la moitié de l'encart pour trois champs.
 */
.crm-relation-add { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.crm-relation-add > select { flex: 1 1 8rem; min-width: 8rem; }

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

.crm-relation-row {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .32rem 0;
    border-bottom: 1px solid var(--crm-slate-100);
    font-size: .86rem;
}

.crm-relation-row:last-child { border-bottom: 0; }
.crm-relation-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/*
 * Nature du lien, en pastille neutre.
 *
 * `.crm-option-badge` seule attend une couleur en ligne, venue du champ : sans elle, le texte
 * blanc restait sur un fond transparent, donc invisible. Le qualificatif n'a pas de couleur
 * propre à porter (ce n'est pas une valeur de liste fermée), d'où un gris qui se lit sans tirer
 * l'œil : c'est la fiche reliée qu'on lit d'abord, le titre du lien ensuite.
 */
.crm-relation-qualifier {
    background: var(--crm-slate-100);
    color: var(--crm-slate-600);
    box-shadow: inset 0 0 0 1px var(--crm-slate-200);
    flex: 0 0 auto;
}

/* Un seul lien possible : son nom se lit, il ne se choisit pas. */
.crm-relation-only-type { flex: 0 0 auto; font-size: .8rem; }

/* La croix de retrait n'apparaît qu'au survol : elle ne doit pas concurrencer le libellé. */
.crm-relation-remove { margin: 0; opacity: 0; transition: opacity var(--crm-ease); }
.crm-relation-row:hover .crm-relation-remove { opacity: 1; }
.crm-relation-remove button:focus-visible { opacity: 1; outline: 2px solid var(--crm-primary); }

/* ------------------------------------------------------------------ Fenêtre centrée
 *
 * Troisième position de la même fenêtre, après le volet de bord et l'ancrage en bas.
 * Deux colonnes, rédaction et aperçu, ne tiennent pas dans 52 rem de bord : la boîte
 * de rédaction du portail fait la largeur d'un e-mail, l'aperçu celle d'un e-mail rendu.
 * Réutiliser le volet plutôt qu'écrire une seconde mécanique de fenêtre : le chargement,
 * la soumission sans quitter la page, la fermeture par Échap et le garde-fou de saisie
 * en cours sont déjà là.
 */
.crm-drawer.is-modal {
    top: 50%;
    left: 50%;
    right: auto;
    bottom: auto;
    width: min(88rem, calc(100vw - 3rem));
    max-height: calc(100vh - 3rem);
    border-radius: var(--crm-radius-lg);
    box-shadow: 0 24px 64px rgba(22, 28, 38, .28);
    /* Le volet arrive par la droite ; la fenêtre centrée monte d'un cran, sinon elle
       traverserait l'écran de droite à gauche à l'ouverture. */
    transform: translate(-50%, calc(-50% + 1.25rem));
    opacity: 0;
    transition: opacity 160ms ease, transform 200ms cubic-bezier(.32, .72, 0, 1);
    overflow: hidden;
}
.crm-drawer.is-modal.is-open { transform: translate(-50%, -50%); opacity: 1; }

/*
 * Fenêtre **pleine** : largeur et hauteur.
 *
 * `max-height` seul ne suffisait pas : la fenêtre restait à la hauteur de son contenu, et un
 * éditeur de contrat s'ouvrait sur un tiers d'écran alors qu'il a dix-neuf pages à montrer. La
 * hauteur est donc imposée, et c'est l'intérieur qui répartit.
 *
 * Une marge de 1 rem seulement, contre 3 pour une fenêtre ordinaire : à ce format, le voile
 * autour ne sert plus qu'à rappeler qu'on est dans une fenêtre, pas à laisser voir la fiche.
 */
.crm-drawer.is-modal.is-fill {
    width: calc(100vw - 2rem);
    height: calc(100vh - 2rem);
    max-height: calc(100vh - 2rem);
}
.crm-drawer.is-modal .crm-drawer-head { border-radius: var(--crm-radius-lg) var(--crm-radius-lg) 0 0; }

/*
 * Les boutons restent visibles : seul le contenu défile.
 *
 * Mesuré avant d'y venir : la boîte de rédaction fait 575 px, le corps de la fenêtre 605 :
 * la barre d'actions tombait 120 px sous le bas de la fenêtre, donc hors de vue jusqu'à ce
 * qu'on pense à faire défiler. Un formulaire dont on ne voit pas le bouton d'enregistrement
 * passe pour un formulaire qu'on ne peut pas enregistrer.
 */
.crm-drawer.is-modal .crm-drawer-body { display: flex; flex-direction: column; overflow: hidden; }
.crm-drawer.is-modal .crm-tpl { flex: 1 1 auto; min-height: 0; }
.crm-drawer.is-modal .crm-tpl-cols { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: .25rem; }
.crm-drawer.is-modal .crm-tpl-actions { flex: 0 0 auto; }

/* ------------------------------------------------------------------ Modèle d'e-mail
 *
 * La boîte du portail : un seul cadre pour l'audience, le nom, l'objet et le corps. Une
 * pile de `form-group` donnait six blocs séparés là où il n'y a qu'un e-mail à écrire.
 */
.crm-tpl-window { padding: 1.25rem 1.5rem 1.5rem; }
.crm-tpl { display: flex; flex-direction: column; gap: 1rem; }

.crm-tpl-cols {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
}
/* L'aperçu masqué, la rédaction prend toute la largeur. */
.crm-tpl-cols.is-solo { grid-template-columns: minmax(0, 1fr); }
.crm-tpl-cols.is-solo .crm-tpl-preview { display: none; }

.crm-tpl-lead {
    margin: 0 0 .5rem;
    font-size: .9375rem;
    font-weight: 600;
    color: var(--crm-slate-900);
}

.crm-tpl-box {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    background: var(--crm-surface);
    overflow: hidden;
}
.crm-tpl-meta,
.crm-tpl-line,
.crm-tpl-strip {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .375rem .625rem;
    border-bottom: 1px solid var(--crm-border);
    min-height: 2.5rem;
}
.crm-tpl-strip { border-bottom: 0; border-top: 1px solid var(--crm-border); font-size: .8125rem; }
.crm-tpl-meta { flex-wrap: wrap; background: var(--crm-slate-50, #f8fafc); }
.crm-tpl-owner { font-size: .8125rem; color: var(--crm-text-muted); }
.crm-tpl-tag {
    font-size: .8125rem;
    padding: .125rem .5rem;
    border: 1px solid var(--crm-border);
    border-radius: 999px;
    color: var(--crm-text-muted);
}

.crm-tpl-key {
    flex: 0 0 auto;
    margin: 0;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--crm-slate-900);
}

/* Champ « plat » : la ligne du cadre tient lieu de bordure. Un `form-control` complet
   redessinerait une boîte dans la boîte, ce qui est précisément ce qu'on retire. */
.crm-tpl-flat,
.crm-tpl-meta select.crm-tpl-inline {
    flex: 1 1 auto;
    min-width: 0;
    border: 1px solid transparent;
    border-radius: var(--crm-radius-sm, .25rem);
    background: transparent;
    padding: .25rem .375rem;
    font-size: .875rem;
    color: var(--crm-slate-900);
}
.crm-tpl-flat:focus,
.crm-tpl-meta select.crm-tpl-inline:focus {
    outline: none;
    border-color: var(--crm-primary, #2f6feb);
    background: var(--crm-surface);
}
.crm-tpl-meta select.crm-tpl-inline { flex: 0 1 auto; width: auto; font-size: .8125rem; }

.crm-tpl-area { padding: .25rem .625rem; }
/* 11 rem, pas 16 : à 1280×720, la taille d'écran la plus courante ici, un corps de 16 rem
   faisait dépasser la boîte de la zone visible, et il fallait faire défiler pour atteindre le
   pied. La poignée de redimensionnement reste, pour qui veut plus de place. */
.crm-tpl-textarea {
    display: block;
    width: 100%;
    min-height: 11rem;
    resize: vertical;
    line-height: 1.5;
}

.crm-tpl-insert .btn { padding: 0 .25rem; font-size: .8125rem; text-decoration: none; }
.crm-tpl-vars { max-height: 20rem; overflow-y: auto; min-width: 18rem; }
.crm-tpl-vars .dropdown-item { white-space: normal; }

.crm-tpl-under { margin-top: .5rem; }
.crm-tpl-under .form-group { margin-bottom: 0; }

.crm-tpl-pick { display: flex; gap: .5rem; margin-bottom: .5rem; }
.crm-tpl-pick > select { flex: 1 1 auto; min-width: 0; }

.crm-tpl-paper {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    background: var(--crm-surface);
    padding: 1rem;
    min-height: 22rem;
    max-height: 32rem;
    overflow-y: auto;
}
.crm-tpl-blank {
    height: 100%;
    min-height: 20rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--crm-text-muted);
}
.crm-tpl-on { font-size: .8125rem; margin-bottom: .5rem; }
.crm-tpl-subject { margin-bottom: .75rem; }

.crm-tpl-actions {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding-top: 1rem;
    border-top: 1px solid var(--crm-border);
}

/* Sous 62 rem les deux colonnes se superposeraient à moitié : l'aperçu passe dessous. */
@media (max-width: 62rem) {
    .crm-tpl-cols { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------------------ Modèles de documents
 *
 * La colonne de droite de l'éditeur de modèle porte deux panneaux, la palette de jetons et
 * l'aperçu. Ils partagent la même boîte et ne s'affichent jamais ensemble : c'est le seul
 * moyen de garder au corps du document la largeur qui lui revient.
 *
 * Les rayons viennent des variables, jamais écrits en dur : `--crm-radius-lg` pour un encart,
 * `--crm-radius` pour un contrôle, `--crm-radius-sm` pour une pastille. C'est ce que
 * `crm-chat.css` et `crm-settings.css` avaient manqué, ce qui leur donnait des coins
 * visiblement plus secs que les cartes d'à côté.
 */

/* ---- L'éditeur de modèle en fenêtre pleine ----
 *
 * Le corps prend la place, la colonne de droite devient un **rail** de 20 rem. En deux colonnes
 * égales, le contrat s'écrivait sur 512 px : la moitié de l'écran servait à une palette qu'on
 * consulte du coin de l'œil, et le paragraphe qu'on rédige tenait sur cinq mots par ligne.
 */
.crm-doc-cols {
    grid-template-columns: minmax(0, 1fr) 20rem;
    align-items: stretch;
    /*
     * Le défilement passe **dans** les deux colonnes, et non sur leur conteneur : deux panneaux
     * visuellement distincts qui défilent chacun chez eux se comprennent, là où un conteneur
     * unique faisait remonter le rail avec le texte, donc disparaître la palette dès qu'on
     * descendait dans le contrat.
     */
    overflow: hidden;
}
.crm-doc-cols .crm-tpl-compose,
.crm-doc-cols .crm-tpl-preview { min-height: 0; overflow-y: auto; padding-right: .25rem; }

/* En fenêtre pleine, la liste des jetons suit la hauteur du rail : son plafond de 26 rem
   laissait un grand vide sous elle et faisait défiler pour rien. */
.crm-doc-cols .crm-doc-tokens { max-height: none; }

/* La zone d'écriture prend ce qui reste : c'est elle qu'on est venu remplir. */
.crm-doc-cols .crm-tpl-box { display: flex; flex-direction: column; min-height: 0; }
.crm-doc-cols .crm-tpl-area { flex: 1 1 auto; min-height: 18rem; }

@media (max-width: 75rem) {
    /* Sous 1 200 px, le rail et le texte ne tiennent plus côte à côte sans que l'un des deux
       devienne inutilisable : la palette repasse dessous. */
    .crm-doc-cols { grid-template-columns: minmax(0, 1fr); overflow-y: auto; }
    .crm-doc-cols .crm-tpl-compose,
    .crm-doc-cols .crm-tpl-preview { overflow: visible; }
}

.crm-doc-tabs { border-bottom: 1px solid var(--crm-border); margin-bottom: .625rem; }
.crm-doc-tabs .nav-link {
    border: 0;
    background: none;
    padding: .375rem .75rem;
    font-size: .8125rem;
    color: var(--crm-text-muted);
    border-bottom: 2px solid transparent;
}
.crm-doc-tabs .nav-link.active {
    color: var(--crm-primary);
    border-bottom-color: var(--crm-primary);
    font-weight: 600;
}

.crm-doc-pane { display: none; }
.crm-doc-pane.is-active { display: block; }

.crm-doc-search { margin-bottom: .5rem; }

/* Une seule zone défile : la liste des jetons. Trois zones de défilement dans une fenêtre
   rendent la molette imprévisible, le défaut déjà payé sur le réglage des encarts. */
.crm-doc-tokens {
    max-height: 26rem;
    overflow-y: auto;
    padding-right: .25rem;
}

.crm-doc-group { margin-bottom: .625rem; }
.crm-doc-group-title {
    margin: 0 0 .25rem;
    font-size: .75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--crm-text-muted);
}

.crm-doc-chips { display: flex; flex-wrap: wrap; gap: .25rem; }

/* Une pastille, donc le petit rayon. Serrée à hauteur de jeton et non de bouton : une palette
   de quatre-vingts jetons à 40 px de haut ferait défiler un kilomètre pour une liste qu'on
   parcourt des yeux. */
.crm-doc-chip {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-sm);
    background: var(--crm-surface);
    color: var(--crm-slate-900);
    font-size: .75rem;
    line-height: 1.2;
    padding: .1875rem .375rem;
    max-width: 100%;
    text-align: left;
    cursor: pointer;
}
.crm-doc-chip:hover { border-color: var(--crm-primary); color: var(--crm-primary); }

/* La palette porte le même code couleur que les pastilles du corps : sans cela, la couleur
   n'apprendrait rien, il faudrait l'apprendre deux fois. */
.crm-doc-chip.is-fiche { background: #e8f0fe; border-color: #c6dafc; color: #14418b; }
.crm-doc-chip.is-lie { background: #f3e8fd; border-color: #ddc4f7; color: #5b21b6; }
.crm-doc-chip.is-moi { background: #ccfbf1; border-color: #5eead4; color: #115e59; }
.crm-doc-chip.is-doc { background: var(--crm-slate-100, #f1f5f9); color: var(--crm-slate-700, #334155); }
.crm-doc-chip.is-fiche:hover, .crm-doc-chip.is-lie:hover,
.crm-doc-chip.is-moi:hover, .crm-doc-chip.is-doc:hover { border-color: currentColor; }
/* Un jeton sensible se signale sans crier : un fond d'alerte sur quinze jetons enverrait le
   regard au danger plutôt qu'au contenu, comme les corbeilles rouges d'une ligne de réglage. */
.crm-doc-chip.is-sensitive { border-style: dashed; }
.crm-doc-chip.is-sensitive .fa-lock { color: var(--crm-warning); margin-right: .25rem; }

.crm-doc-preview-head { display: flex; align-items: center; margin-bottom: .5rem; }

.crm-doc-paper {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    background: var(--crm-surface);
    overflow: hidden;
}
/* Le cadre est en bac à sable : rendu dans la page, l'aperçu hériterait de la feuille de style
   du CRM et paraîtrait plus soigné que le PDF, ce qui est l'inverse de ce qu'un aperçu doit
   faire. Sa hauteur est fixe, il porte son propre défilement. */
.crm-doc-frame {
    display: block;
    width: 100%;
    height: 26rem;
    border: 0;
    background: #fff;
}

/* ---- La feuille A4 ----
 *
 * L'éditeur est un traitement de texte : fond gris, page blanche à la largeur du papier
 * (210 mm = 794 px), marges du PDF (18,8 / 10,3 / 22 mm), et surtout **la typographie du
 * PDF** : Arial 15 px, interligne 1,4, paragraphes sans marge. Sans elle, l'éditeur, l'aperçu
 * et le document produit montraient trois mises en page différentes du même texte.
 */
/* Ancre du positionneur : `inset: 0` doit couvrir l'éditeur, pas le document entier. */
.crm-doc-editor { position: relative; }

.crm-doc-toolstrip {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .25rem 0 .5rem;
    /* Collante : la colonne de composition défile sur un contrat de trente pages, et une
       barre qui part avec le texte est une barre qu'on n'a jamais sous la main. Au-dessus de
       la barre de mise en forme de Summernote (elle-même collante à 2,75 rem plus bas). */
    position: sticky;
    top: 0;
    z-index: 6;
    background: var(--crm-body-bg, #f4f6f9);
}
/*
 * Sur la **page pleine** (le recours, hors fenêtre), c'est la fenêtre du navigateur qui
 * défile, sous la barre de navigation fixe : deux conséquences que la fenêtre d'édition n'a
 * pas. D'abord, `overflow-y: auto` sur la colonne en fait le « scrollport » du sticky alors
 * qu'elle ne défile jamais ici : la barre ne collait à rien. Ensuite, les décalages doivent
 * passer sous la barre de navigation (3,5 rem + 1 px), sinon la rangée glisse dessous.
 */
.content-wrapper .crm-doc-cols { overflow: visible; }
.content-wrapper .crm-doc-cols .crm-tpl-compose,
.content-wrapper .crm-doc-cols .crm-tpl-preview { overflow: visible; }
.content-wrapper .crm-doc-toolstrip { top: calc(3.5rem + 1px); }
.content-wrapper .crm-doc-sheet-area .note-toolbar { top: calc(3.5rem + 1px + var(--crm-doc-strip-h, 2.75rem)); }
.crm-doc-sheet-area .note-editor.note-frame {
    border: 0;
    background: var(--crm-slate-200, #e9ecef);
    border-radius: var(--crm-radius);
}
/*
 * La barre de mise en forme reste sous la main quand on défile.
 *
 * Elle **se cale sous la rangée d'outils** (2,75 rem), et non sous le bord. Le décalage était
 * écrit vingt lignes plus haut, sur le même sélecteur, donc à spécificité égale : c'est ce bloc,
 * plus bas dans la feuille, qui gagnait avec son `top: 0`. Les deux barres se collaient alors au
 * même endroit, et la rangée d'outils, mieux empilée (`z-index` 6 contre 5) et opaque, recouvrait
 * entièrement la barre de mise en forme. Elle avait donc l'air de disparaître au premier
 * défilement, alors qu'elle était là, dessous.
 *
 * C'est le piège de `.navbar-badge` contre `.badge` : rien, dans le bloc qu'on lit, ne dit que le
 * réglage vient d'ailleurs. Le décalage vit maintenant **ici**, avec la déclaration qui le rend
 * collante ; la page pleine le surcharge par un sélecteur plus spécifique, donc sans dépendre de
 * l'ordre.
 *
 */
/*
 * Le décalage vient d'une **mesure**, jamais d'un nombre écrit à la main.
 *
 * Il valait `2.75rem` d'un côté et `6.25rem + 1px` de l'autre, pour une rangée d'outils qui
 * mesure en réalité 42 px : deux pixels d'écart, et par cette fente de deux pixels le contrat
 * défilait **visiblement** entre les deux barres. Le signalement était exactement celui-là,
 * « l'affichage visible en dessous le bandeau », et il ne se voit qu'en défilant.
 *
 * Deux pixels n'étaient d'ailleurs que le meilleur des cas : la rangée porte une phrase et un
 * compteur de pages, elle passe à deux lignes sur une fenêtre étroite, et la fente devenait
 * alors une bande de quarante pixels. Un nombre en dur ne pouvait pas suivre.
 *
 * `--crm-doc-strip-h` est posée par `calerBarresCollantes()` sur le formulaire, depuis la
 * hauteur réelle de la rangée, et reprise à chaque mise en pages comme à chaque
 * redimensionnement. La valeur de repli couvre le temps d'avant la première mesure.
 */
.crm-doc-sheet-area .note-toolbar {
    border-bottom: 1px solid var(--crm-border);
    position: sticky;
    top: var(--crm-doc-strip-h, 2.75rem);
    z-index: 5;
}
/*
 * Le fond, et pourquoi ce sélecteur est si long.
 *
 * La zone porte **les deux** classes, `crm-tpl-area` et `crm-doc-sheet-area`, et
 * `.crm-tpl-area .note-editor .note-toolbar`, huit cents lignes plus bas, met ce fond à
 * `transparent` : trois classes contre deux, elle l'emportait. Mesuré dans la page :
 * `rgba(0, 0, 0, 0)`. Une barre collante transparente laisse le contrat défiler **au travers**
 * de ses boutons, ce qui est pire que pas de barre du tout.
 *
 * Quatre classes, donc, et non un `!important` : la spécificité dit ici quelque chose de vrai,
 * cette barre est celle d'une feuille de document et non d'une zone de saisie ordinaire. Le
 * décalage `top` reste sur les sélecteurs courts, sinon celui de la page pleine
 * (`.content-wrapper …`, trois classes) perdrait contre celui-ci.
 */
.crm-tpl-area.crm-doc-sheet-area .note-editor .note-toolbar {
    background: var(--crm-surface);
}
/* `position: relative` : la surcouche des repères de page se positionne dans cette zone. */
.crm-doc-sheet-area .note-editing-area {
    position: relative;
    background: var(--crm-slate-200, #e9ecef);
    padding: 1.25rem 0;
    overflow-x: auto;
}
/*
 * La feuille plus large que sa colonne se **fait défiler**, elle ne se fait plus rogner.
 *
 * La règle voisine promet qu'« sur un écran étroit, c'est la zone qui défile horizontalement,
 * comme un traitement de texte ». Elle ne le faisait pas : `.note-editing-area`, la boîte que
 * Summernote pose autour du contenu, porte `overflow-x: hidden`. Mesuré à 1 440 x 900, éditeur
 * de modèle avec son rail de 20 rem : la boîte annonçait 679 px de large pour 806 de contenu,
 * donc **127 px de feuille inatteignables**, marge droite du contrat comprise, et rien à
 * l'écran pour dire qu'il y avait quelque chose au-delà. C'est le même défaut que la colonne
 * qui rognait la feuille sur l'écran de génération, à l'endroit où l'empiler n'est pas une
 * option : le rail de l'éditeur a ses raisons d'être là.
 */
/*
 * Quatre classes, et c'est le minimum : Summernote écrit
 * `.note-editor.note-frame .note-editing-area { overflow: hidden }`, soit trois classes.
 * La même règle à deux classes ne s'appliquait pas, et la valeur calculée le disait
 * (`overflow-x` restait `hidden`) alors que la déclaration était bien là : c'est le piège
 * déjà payé sur la barre de mise en forme collante, et il ne se voit qu'en mesurant.
 */
.crm-doc-sheet-area .note-editor.note-frame .note-editing-area { overflow-x: auto; }
.crm-doc-sheet-area .note-editable {
    /* La largeur du papier, jamais rétrécie : une feuille écrasée change tous les retours
       à la ligne, donc le compte de pages, et l'éditeur mentait de seize pages sur un
       contrat. Sur un écran étroit, c'est la zone qui défile horizontalement, comme un
       traitement de texte. */
    width: 794px;
    max-width: none;
    flex: 0 0 auto;
    margin: 0 auto;
    /* Marges Word des contrats d'origine : 24,9 mm de côtés et de tête, 27,5 mm de pied
       (le pied de page du PDF y vit). */
    padding: 94px 94px 104px !important;
    background: #fff;
    box-shadow: 0 1px 4px rgba(24, 28, 33, .22);
    /* La typographie du PDF : Times New Roman 15 px, interligne simple, mesurée sur le
       document du portail à l'échelle 1 (et non sur sa barre latérale, qui est en Arial). */
    font-family: 'Times New Roman', Times, serif;
    font-size: 15px;
    line-height: 1.0;
    min-height: 1123px;
    height: auto !important;
    overflow: visible !important;
}
/*
 * La feuille reprend **toute** la feuille de style du PDF (`PdfRenderer::CSS`), convertie en
 * pixels (1 pt = 4/3 px). Ce n'est pas de la coquetterie : c'est la colonne et le rythme
 * vertical qui décident des retours à la ligne, donc du compte de pages, et l'éditeur promet de
 * montrer le document tel qu'il sortira.
 *
 * Quatre familles y manquaient, et la première se voyait à l'œil nu : le logo de la charte
 * d'engagement, 1 200 px de large, débordait de la feuille et de sa colonne. Les trois autres
 * ne se voyaient pas et faussaient le compte de pages : une liste prenait l'indentation et les
 * marges verticales du navigateur (1 em au-dessus et au-dessous, 40 px de retrait) au lieu des
 * 14 pt du PDF sans marge, et un tableau n'avait ni marge basse ni fond d'en-tête.
 */
.crm-doc-sheet-area .note-editable p { margin: 0; }
.crm-doc-sheet-area .note-editable h1 { font-size: 21px; margin: 0; }
.crm-doc-sheet-area .note-editable h2 { font-size: 18px; margin: 0; }
.crm-doc-sheet-area .note-editable h3 { font-size: 16px; margin: 0; }
.crm-doc-sheet-area .note-editable ul,
.crm-doc-sheet-area .note-editable ol { margin: 0 0 0 18.7px; padding: 0; }
.crm-doc-sheet-area .note-editable li { margin: 0; }
.crm-doc-sheet-area .note-editable table { border-collapse: collapse; width: 100%; margin: 0 0 10.7px; }
.crm-doc-sheet-area .note-editable th,
.crm-doc-sheet-area .note-editable td { border: 1px solid #999; padding: 4px 6.7px; vertical-align: top; }
.crm-doc-sheet-area .note-editable th { background: #f2f2f2; font-weight: bold; }
/* La règle qui manquait le plus visiblement. Bornée à la feuille et non à la zone entière : la
   barre d'outils de Summernote porte aussi des images. */
.crm-doc-sheet-area .note-editable img { max-width: 100%; }

/* Le saut de page voulu est l'espace entre deux pages : sa hauteur d'affichage est posée par
   `layoutDocumentPages()` (le reste de la page, les marges, la gouttière), et la surcouche y
   dessine la coupure grise. Le div lui-même reste invisible ; sa hauteur n'est jamais
   enregistrée, la normalisation la retire avant l'envoi. */
.crm-doc-sheet-area .note-editable div[style*="break-before"] {
    margin: 0;
    min-height: 4px;
}

/* Un champ de signature posé dans le texte : le style de boîte est en ligne (mPDF le lit),
   la teinte, elle, n'est que pour l'éditeur. */
.crm-doc-sheet-area .note-editable [data-crm-field] {
    background: rgba(76, 110, 245, .06);
    cursor: default;
    user-select: none;
}

/* La mise en pages : dessinée dans une surcouche, jamais dans le contenu. */
.crm-doc-guides {
    position: absolute;
    pointer-events: none;
    z-index: 4;
}
/* Le temps qu'un menu de page soit ouvert, la surcouche passe au-dessus de celle des champs
   volants (z-index 6) : sans cela, une boîte de signature posée en haut de la page suivante
   se dessinerait par-dessus le menu. Elle reste inerte au clic, son `pointer-events` ne
   changeant pas. */
.crm-doc-guides.has-open-menu { z-index: 8; }

/* La coupure entre deux pages : le fond gris de la zone reprend ses droits, avec l'ombre du
   bas de la page au-dessus et celle du haut de la page suivante. C'est ce qui fait lire deux
   cartes là où le DOM n'a qu'une seule feuille. */
.crm-doc-gutter {
    position: absolute;
    background: var(--crm-slate-200, #e9ecef);
    box-shadow: inset 0 8px 6px -6px rgba(24, 28, 33, .25), inset 0 -8px 6px -6px rgba(24, 28, 33, .25);
    display: flex;
    align-items: center;
    justify-content: center;
}
.crm-doc-gutter-chip {
    pointer-events: auto;
    /* Le menu de page s'y accroche : sans repère, il se centrerait sur la zone d'édition. */
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: 10px;
    color: var(--crm-slate-500, #6c757d);
    background: var(--crm-surface, #fff);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-sm);
    padding: 1px 8px;
    line-height: 1.4;
}
/* Le « … » de la pastille : les gestes qui portent sur la page qu'elle nomme. */
.crm-doc-gutter-menu {
    border: 0;
    background: none;
    color: var(--crm-slate-400);
    font-size: 11px;
    line-height: 1;
    padding: 0 2px;
    cursor: pointer;
}
.crm-doc-gutter-menu:hover { color: var(--crm-primary, #4c6ef5); }

/* Le menu lui-même : posé sous la pastille, il recouvre le haut de la page suivante, ce qui
   est le propre d'un menu. Sa largeur est celle de sa plus longue entrée : repliée, « Fusionner
   avec la page ci-dessus » se lirait sur deux lignes dans un menu de trois. */
.crm-doc-page-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 12;
    min-width: 15rem;
    padding: .25rem 0;
    background: var(--crm-surface, #fff);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius, 8px);
    box-shadow: 0 8px 20px rgba(24, 28, 33, .18);
    text-align: left;
}
.crm-doc-page-menu button {
    display: flex;
    align-items: center;
    gap: .5rem;
    width: 100%;
    border: 0;
    background: none;
    color: var(--crm-text, #212529);
    font-size: 12px;
    line-height: 1.4;
    text-align: left;
    padding: .35rem .75rem;
    cursor: pointer;
}
.crm-doc-page-menu button i {
    width: 14px;
    text-align: center;
    color: var(--crm-slate-400);
}
.crm-doc-page-menu button:hover { background: var(--crm-slate-100, #f4f6f8); }
.crm-doc-page-menu button.is-danger,
.crm-doc-page-menu button.is-danger i { color: var(--crm-danger, #dc3545); }

/* Le saut de page naturel du PDF : un marqueur en marge, comme au portail. Il ne coupe pas la
   feuille : le texte coule, c'est le PDF qui coupera là. */
.crm-doc-natural-break {
    position: absolute;
    border-top: 1px dashed rgba(24, 28, 33, .35);
}
.crm-doc-natural-label {
    pointer-events: auto;
    position: absolute;
    top: -9px;
    width: 84px;
    font-size: 9px;
    line-height: 1.15;
    color: var(--crm-slate-500, #6c757d);
    background: var(--crm-slate-200, #e9ecef);
    padding: 1px 3px;
    display: inline-flex;
    align-items: center;
    gap: 3px;
}
.crm-doc-natural-add {
    border: 1px solid var(--crm-border);
    background: var(--crm-surface, #fff);
    color: var(--crm-slate-500, #6c757d);
    border-radius: 50%;
    width: 15px;
    height: 15px;
    line-height: 1;
    font-size: 11px;
    padding: 0;
    cursor: pointer;
    flex: 0 0 auto;
}
.crm-doc-natural-add:hover { color: var(--crm-primary); border-color: var(--crm-primary); }

/* La couche des champs volants : au-dessus de la feuille, jamais dans le contenu. Les
   boîtes portent la couleur de leur rôle, posée en style par le script. */
.crm-doc-float-layer {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 6;
    pointer-events: none;
}
.crm-doc-float-field {
    position: absolute;
    pointer-events: auto;
    border: 1.5px solid #667788;
    border-radius: 3px;
    font-size: 11px;
    display: flex;
    /* `stretch` et non `flex-start` : le libellé est alors **borné par la boîte**, et son
       débordement se coupe dedans. À `flex-start` il prenait la hauteur de son contenu et
       sortait de la boîte, mesuré à 31 px sur une question longue dans une petite case. Le
       texte reste en haut de toute façon : il s'écoule depuis le haut. */
    align-items: stretch;
    padding: 2px 5px;
    overflow: hidden;
    cursor: move;
    user-select: none;
    background: rgba(102, 119, 136, .08);
}
/*
 * L'icône du type, à gauche du libellé.
 *
 * Les huit types rendaient la même boîte, un rectangle de la couleur du rôle avec son nom
 * écrit dedans : « Case à cocher », « Boutons radio » et « Liste déroulante » côte à côte ne se
 * distinguaient qu'en lisant, alors que ce sont trois contrôles différents. L'icône hérite de la
 * couleur du rôle, posée en style sur la boîte : elle dit le type, la couleur dit qui remplit.
 */
.crm-doc-float-icon {
    pointer-events: none;
    flex: 0 0 auto;
    margin-right: 4px;
    line-height: 1.25;
    opacity: .75;
}

.crm-doc-float-field .crm-doc-float-label {
    pointer-events: none;
    /*
     * Le texte occupe la boîte, sur plusieurs lignes quand elle en a la place, et il
     * **contourne** les icônes du coin haut-droit au lieu de passer dessous.
     *
     * L'intercalaire flottant leur réserve leur place sur la **première ligne seulement** :
     * les suivantes gardent toute la largeur. Un simple retrait à droite l'aurait ôtée à
     * toutes, alors que rien ne flotte au-dessus d'elles. Avant, `nowrap` tenait le texte
     * sur une ligne et l'ellipse se calculait sur la largeur entière : les derniers
     * caractères finissaient sous l'engrenage, illisibles, dans une boîte à moitié vide.
     */
    flex: 1 1 auto;
    min-width: 0;
    white-space: normal;
    overflow: hidden;
    line-height: 1.25;
    overflow-wrap: anywhere;
}
.crm-doc-float-field .crm-doc-float-label::before {
    content: '';
    float: right;
    /* La largeur réellement occupée par l'engrenage et la croix, mesurée : 30 px. */
    width: 30px;
    height: 1.25em;
}

/*
 * Le rôle, en second plan dans le libellé.
 *
 * Il était collé au nom du champ à la même graisse (« Case à cocher - Mytek ») : les deux se
 * lisaient d'un bloc, alors qu'on cherche des yeux ce que le champ **demande**, le rôle venant
 * ensuite, et la couleur de la boîte le disant déjà. Dans le flux du libellé et non à côté :
 * une boîte étroite le renvoie alors à la ligne au lieu de rogner le nom du champ.
 */
.crm-doc-float-field .crm-doc-float-label em {
    font-style: normal;
    opacity: .62;
}
.crm-doc-float-field .crm-doc-float-label em::before {
    content: ' · ';
}

.crm-doc-role-chip { background: var(--crm-surface, #fff); border: 1px solid; }
.crm-doc-role-chip:hover { filter: brightness(.92); }

/* Les gestes de glisser : la pastille et le champ disent qu'ils se prennent. */
[data-crm-doc-fieldchip] { cursor: grab; }
.crm-doc-sheet-area .note-editable [data-crm-field] { cursor: grab; }
.crm-doc-sheet-area .note-editable [data-crm-field]:active { cursor: grabbing; }
.crm-doc-sheet-area .note-editable [data-crm-field].is-dragging { opacity: .35; }

/* Pendant un glisser au pointeur : plus de sélection de texte (le geste balayait la page et
   surlignait tout), un fantôme qui suit la souris, un repère au point d'insertion. */
body.crm-doc-dragging { user-select: none; cursor: grabbing; }
.crm-doc-drag-ghost {
    position: fixed;
    z-index: 3000;
    pointer-events: none;
    background: var(--crm-surface, #fff);
    border: 1px solid var(--crm-primary, #4c6ef5);
    border-radius: var(--crm-radius-sm);
    box-shadow: 0 2px 8px rgba(24, 28, 33, .25);
    padding: 3px 10px;
    font-size: 12px;
    color: var(--crm-primary, #4c6ef5);
    max-width: 240px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.crm-doc-drag-caret {
    position: fixed;
    z-index: 2999;
    pointer-events: none;
    width: 2px;
    background: var(--crm-primary, #4c6ef5);
    box-shadow: 0 0 0 1px rgba(76, 110, 245, .25);
}

/* ---- Le rail : six onglets dans 20 rem ---- */

/* Icône au-dessus d'un libellé court : six libellés en ligne ne tenaient pas, et des icônes
   seules obligeaient à survoler pour savoir où l'on va. */
.crm-doc-rail .crm-doc-tabs { display: flex; flex-wrap: nowrap; }
.crm-doc-rail .crm-doc-tabs .nav-item { flex: 1 1 0; min-width: 0; }
.crm-doc-rail .crm-doc-tabs .nav-link {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    width: 100%;
    padding: .3125rem .125rem;
    font-size: .625rem;
}
.crm-doc-rail .crm-doc-tabs .nav-link i { font-size: .8125rem; }

/* ---- Rôles ---- */

.crm-doc-role {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    padding: .375rem .5rem;
    margin-bottom: .5rem;
    background: var(--crm-surface);
}
.crm-doc-role-row { display: flex; align-items: center; gap: .375rem; }
.crm-doc-role-row .form-control { flex: 1 1 auto; }
.crm-doc-role-remove {
    border: 0;
    background: none;
    color: var(--crm-slate-400);
    padding: .25rem;
    line-height: 1;
    flex: 0 0 auto;
}
.crm-doc-role-remove:hover { color: var(--crm-danger, #dc3545); }
.crm-doc-role-chips { display: flex; gap: .25rem; margin-top: .375rem; flex-wrap: wrap; }

/* ---- Annexes ---- */

.crm-doc-annexe {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    padding: .375rem .5rem;
    margin-bottom: .5rem;
    background: var(--crm-surface);
    position: relative;
}
.crm-doc-annexe-name {
    font-size: .8125rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding-right: 1.5rem;
}
.crm-doc-annexe-meta { font-size: .6875rem; color: var(--crm-text-muted); margin: .125rem 0 .375rem; }
.crm-doc-annexe-actions { display: flex; align-items: center; gap: .375rem; }
.crm-doc-annexe .crm-doc-role-remove { position: absolute; top: .25rem; right: .25rem; }

/* ---- Historique ---- */

.crm-doc-version {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .375rem 0;
    border-bottom: 1px solid var(--crm-border-soft, var(--crm-border));
}
.crm-doc-version:last-child { border-bottom: 0; }
.crm-doc-version-meta { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; font-size: .75rem; }

/* ---- Réglages ---- */

.crm-doc-setting { margin-bottom: .625rem; }
.crm-doc-setting-title {
    font-size: .6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--crm-text-muted);
    margin: 0 0 .25rem;
}
.crm-doc-setting-duo { display: flex; gap: .5rem; }
.crm-doc-setting-duo > div { flex: 1 1 0; }
.crm-doc-setting-duo label {
    display: block;
    font-size: .6875rem;
    font-weight: 600;
    color: var(--crm-text-muted);
    margin-bottom: .1875rem;
}
.crm-doc-setting > label {
    display: block;
    font-size: .6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--crm-text-muted);
    margin-bottom: .1875rem;
}

/* ---- Envoi et historique d'un document généré ---- */

.crm-doc-send-config { display: flex; gap: .625rem; margin-bottom: .25rem; }
.crm-doc-send-config > div { flex: 1 1 0; }
.crm-doc-send-config label {
    display: block;
    font-size: .6875rem;
    font-weight: 600;
    color: var(--crm-text-muted);
    margin-bottom: .1875rem;
}

.crm-doc-events { display: flex; flex-direction: column; }
.crm-doc-event {
    display: grid;
    grid-template-columns: 7.5rem minmax(0, 1fr) 11rem;
    gap: .5rem;
    align-items: baseline;
    padding: .375rem 0;
    border-bottom: 1px solid var(--crm-border-soft, var(--crm-border));
    font-size: .8125rem;
}
.crm-doc-event:last-child { border-bottom: 0; }
.crm-doc-event-when { color: var(--crm-text-muted); font-size: .75rem; white-space: nowrap; }
.crm-doc-event-who { text-align: right; font-size: .75rem; display: inline-flex; align-items: center; gap: .25rem; justify-content: flex-end; }

/* ---- Le positionneur de champs d'annexe ----
 *
 * Il recouvre la fenêtre entière : on règle des positions au pixel, l'écran entier n'est pas
 * de trop, et le document reste intact derrière.
 */
.crm-doc-positioner {
    position: absolute;
    inset: 0;
    z-index: 60;
    background: var(--crm-surface, #fff);
    display: flex;
    flex-direction: column;
    border-radius: inherit;
}
.crm-doc-positioner[hidden] { display: none; }
.crm-doc-positioner-bar {
    display: flex;
    align-items: center;
    gap: .625rem;
    padding: .5rem .875rem;
    border-bottom: 1px solid var(--crm-border);
    flex-wrap: wrap;
}
.crm-doc-pos-nav { display: flex; align-items: center; gap: .375rem; font-size: .8125rem; }
.crm-doc-pos-role { width: 12rem; }
.crm-doc-pos-adds { display: flex; gap: .25rem; }
.crm-doc-positioner-stage {
    flex: 1 1 auto;
    overflow: auto;
    background: var(--crm-slate-200, #e9ecef);
    padding: 1.25rem;
    display: flex;
    justify-content: center;
    align-items: flex-start;
}
.crm-doc-positioner-page {
    position: relative;
    box-shadow: 0 1px 4px rgba(24, 28, 33, .22);
    background: #fff;
}
.crm-doc-positioner-page canvas { display: block; }
.crm-doc-pos-layer { position: absolute; inset: 0; }
.crm-doc-pos-field {
    position: absolute;
    border: 1.5px solid #4c6ef5;
    background: rgba(76, 110, 245, .12);
    border-radius: 2px;
    font-size: 11px;
    color: #37478f;
    cursor: move;
    display: flex;
    align-items: flex-start;
    padding: 2px 4px;
    overflow: hidden;
    user-select: none;
}
.crm-doc-pos-field span { pointer-events: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crm-doc-pos-field.is-texte { border-style: dashed; background: rgba(32, 156, 100, .1); border-color: #209c64; color: #14603d; }
.crm-doc-pos-del {
    position: absolute;
    top: 0;
    right: 0;
    border: 0;
    background: none;
    color: inherit;
    font-size: 12px;
    line-height: 1;
    padding: 1px 3px;
    cursor: pointer;
}
.crm-doc-pos-resize {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 10px;
    height: 10px;
    cursor: nwse-resize;
    background: linear-gradient(135deg, transparent 50%, currentColor 50%);
    opacity: .6;
}

/* La barre de menus de l'éditeur (Fichier / Modifier / Insérer) : du texte discret, comme
   dans un traitement de texte, séparé des boutons d'action par un filet. */
.crm-doc-menubar { display: flex; align-items: center; }
.crm-doc-menubar .crm-doc-menubtn {
    color: var(--crm-text, #343a40);
    text-decoration: none;
    padding: .25rem .625rem;
    font-size: .8125rem;
}
.crm-doc-menubar .crm-doc-menubtn:hover { background: var(--crm-slate-200, #e9ecef); border-radius: var(--crm-radius, 8px); }
.crm-doc-menubar { border-right: 1px solid var(--crm-border, #dee2e6); margin-right: .25rem; padding-right: .5rem; }
.crm-doc-menubar .dropdown-item .float-right { font-size: .75rem; }

/* La liste des documents générés : nom tronqué plutôt que tableau élargi. */
.crm-doc-table .crm-doc-cell-name { max-width: 26rem; }
.crm-doc-table .crm-doc-cell-name a { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.crm-doc-status-pills { display: flex; gap: .375rem; flex-wrap: wrap; }
.crm-doc-status-pills .badge { font-size: .75rem; padding: .375rem .625rem; }

/* Le crayon d'un champ à remplir : sa question et ses choix se règlent sur place. */
.crm-doc-pos-edit {
    position: absolute;
    top: 0;
    right: 14px;
    border: 0;
    background: none;
    color: inherit;
    font-size: 9px;
    line-height: 1;
    padding: 2px 3px;
    cursor: pointer;
    opacity: .75;
}
.crm-doc-pos-edit:hover { opacity: 1; }

/* Le panneau de réglage d'un champ, posé sous sa boîte dans la surcouche. */
.crm-doc-field-editor {
    position: absolute;
    z-index: 30;
    width: 240px;
    background: var(--crm-surface, #fff);
    border: 1px solid #cfd6e0;
    border-radius: var(--crm-radius, 8px);
    box-shadow: 0 6px 18px rgba(16, 24, 40, .18);
    padding: 10px 12px;
    pointer-events: auto;
    cursor: default;
    font-size: 12px;
}
.crm-doc-field-editor label { display: block; font-weight: 600; margin: 0 0 3px; color: #374151; }
.crm-doc-field-editor input,
.crm-doc-field-editor textarea {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid #cfd6e0;
    border-radius: 6px;
    padding: 4px 7px;
    font-size: 12px;
    margin-bottom: 8px;
}
.crm-doc-field-editor-actions { display: flex; gap: 8px; }

/* Le marqueur d'un PDF inséré dans le corps : une carte dans le flux, jamais rendue au PDF
   (le compositeur découpe le corps dessus et importe les pages à sa place). */
.crm-doc-sheet-area .note-editable [data-crm-pdf-annexe] {
    border: 1px dashed #8a94a6;
    border-radius: 6px;
    padding: 8px 12px;
    margin: 10px 0;
    color: #4a5468;
    background: #f4f6fa;
    font-size: 12px;
}

/* ---- Menu de génération, dans l'encart d'une fiche ---- */

/* Une colonne d'encarts fait 235 px : sans plafond ni troncature, un menu portant « Contrat de
   travail CDI - Cadre forfait jour - Consultant » s'étalait bien au-delà de la carte. */
.crm-doc-menu { max-width: 22rem; max-height: 20rem; overflow-y: auto; }

/* ---- Documents produits, dans l'encart ---- */

.crm-doc-list { display: flex; flex-direction: column; }
.crm-doc-row {
    display: flex;
    align-items: center;
    gap: .375rem;
    padding: .25rem 0;
    border-bottom: 1px solid var(--crm-border-soft, var(--crm-border));
}
.crm-doc-row:last-child { border-bottom: 0; }
/* `min-width: 0` : sans lui, un enfant en `flex` refuse de rétrécir sous sa largeur de contenu
   et la troncature ne s'applique jamais. Le nom d'un contrat déborde alors de la carte. */
.crm-doc-row-main { flex: 1 1 auto; min-width: 0; }
.crm-doc-row-name { display: block; font-size: .8125rem; }
.crm-doc-row-meta { display: block; font-size: .6875rem; color: var(--crm-text-muted); }
.crm-doc-row-action { flex: 0 0 auto; }
/* Une croix grise qui ne rougit qu'au survol : on ne supprime presque rien ici. */
.crm-doc-row-remove {
    border: 0;
    background: none;
    color: var(--crm-slate-400);
    padding: .125rem .25rem;
    line-height: 1;
    cursor: pointer;
}
.crm-doc-row-remove:hover { color: var(--crm-danger); }

/* ---- Fenêtre de génération ----
 *
 * L'écran réutilise la grille de l'éditeur de modèle (`crm-doc-cols`) : le document prend la
 * place, le rail des valeurs à saisir vaut 20 rem, chaque colonne défile chez elle. Il portait
 * un aperçu en `<iframe>` de hauteur figée à 26 rem dans une colonne de moitié de largeur : la
 * feuille A4 fait 794 px, il en restait 640, et le contrat qu'on venait relire arrivait avec sa
 * barre de défilement horizontale.
 *
 * Ce qui reste ici est ce que l'éditeur de modèle n'a pas : les bandeaux de tête, le rail de
 * saisie, et le titre tronqué de la page pleine.
 */

.crm-doc-gen { display: flex; flex-direction: column; min-height: 0; }

/* Les bandeaux de tête gardent leur hauteur, quel qu'en soit le nombre : c'est la règle de la
   carte d'une liste, où l'énumération des bandeaux à protéger finissait toujours incomplète. */
.crm-doc-gen-banners {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: .375rem;
    margin-bottom: .625rem;
}
/*
 * Un bandeau tient sur une ligne ou deux.
 *
 * Le rembourrage d'alerte du thème (.8rem 1rem) plus la marge basse de Bootstrap coûtaient une
 * soixantaine de pixels par message, et il peut y en avoir trois à la file : autant de pris au
 * document pour dire trois phrases. La gouttière du conteneur remplace la marge, sinon le
 * dernier bandeau en laisse une avant la grille.
 */
.crm-doc-gen-banner {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    margin: 0;
    padding: .4rem .75rem;
    font-size: .8125rem;
}
.crm-doc-gen-banner > i { flex: 0 0 auto; }

/*
 * La portée d'une retouche se dit dans la barre d'outils, là où l'on s'apprête à retoucher :
 * rien d'autre à l'écran ne distingue « ce document » de « le modèle », et confondre les deux
 * corrigerait un contrat pour tout le monde.
 *
 * Elle se tronque au lieu d'être masquée sous un seuil : la barre vit dans la colonne du
 * document, dont la largeur dépend du rail, et un seuil sur la **fenêtre** l'aurait effacée à
 * 1 280 px là où elle tient encore largement, faute de rail. Le texte entier reste en infobulle.
 */
.crm-doc-gen-scope {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Pas de pied de page sous une barre d'actions collante.
 *
 * `main-footer` d'AdminLTE vit après `.content-wrapper` et mesure 48 px. Sur les deux écrans
 * d'édition de document, dont la barre d'actions est collante en bas, il laissait donc une
 * **bande grise de 48 px sous la barre** dès qu'on arrivait au bout du document : la barre
 * atteint la fin de son conteneur, s'y arrête, et le pied apparaît en dessous. Mesuré au bas du
 * contrat : barre à 799..852 pour une fenêtre de 900.
 *
 * Il était déjà masqué sur les listes (`body.crm-fixed-page`) pour la même raison. Ces deux
 * écrans ne sont pas des pages fixes, c'est la fenêtre qui y défile, d'où leur propre règle.
 */
body.crm-doc-gen-page .main-footer,
body.crm-doc-editor-page .main-footer { display: none; }

/* ---- La barre d'actions ----
 *
 * La phrase de conséquence est poussée à droite et se tronque avant de bousculer les boutons :
 * c'est une aide, pas une action, et sur une fenêtre étroite elle doit céder la place plutôt que
 * de renvoyer « Générer le document » à la ligne. Effacée sous 62 rem, où la place manque
 * vraiment et où les deux boutons suffisent.
 */
.crm-doc-gen-bar-hint {
    margin-left: auto;
    flex: 0 1 auto;
    min-width: 0;
    font-size: .8125rem;
    color: var(--crm-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
@media (max-width: 62rem) {
    .crm-doc-gen-bar-hint { display: none; }
}

/* ---- Le nom du document, modifiable ----
 *
 * Un champ à lui, au-dessus de la feuille : le motif du modèle le propose, il ne le décide pas.
 * Borné en largeur comme les valeurs à saisir, sinon un nom de trois mots s'étalait sur
 * mille pixels, le défaut déjà payé sur les lignes de réglage d'un bloc de fiche.
 */
.crm-doc-gen-name {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    background: var(--crm-surface);
    padding: .625rem .75rem;
    margin-bottom: .625rem;
}
.crm-doc-gen-name label {
    display: block;
    margin-bottom: .15rem;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--crm-slate-900);
}
.crm-doc-gen-name input { max-width: 42rem; }

/* ---- Les valeurs à saisir ----
 *
 * Une rangée de champs qui s'enroule, au-dessus de la feuille, et non un rail à côté d'elle : à
 * 20 rem de rail, la colonne du document tombait à 703 px pour une feuille A4 de 794, et ses
 * 101 derniers pixels étaient rognés sans barre de défilement (`scrollWidth` égal à
 * `clientWidth`, mesuré à 1 440 x 900).
 */
.crm-doc-gen-values {
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    background: var(--crm-surface);
    padding: .625rem .75rem;
    margin-bottom: .625rem;
}
.crm-doc-gen-values .crm-tpl-lead { margin-bottom: .125rem; }
.crm-doc-gen-values .crm-tpl-hint { margin-bottom: .5rem; }

.crm-doc-gen-fields { display: flex; flex-wrap: wrap; gap: .5rem .75rem; }
/*
 * Le libellé **au-dessus** de son champ, et le champ borné.
 *
 * Un libellé de jeton est du texte libre, écrit par qui a rédigé le modèle : « Date de
 * l'entretien (Mardi 16 mars 2023) » en mesure 302. Posé en ligne, il ne laissait au champ que
 * quelques pixels ; posé sans borne de largeur, le champ s'étalait en ruban sur toute la
 * rangée, le défaut déjà payé sur les lignes de réglage d'un bloc de fiche.
 */
.crm-doc-gen-field {
    flex: 1 1 16rem;
    min-width: 0;
    max-width: 26rem;
}
.crm-doc-gen-field label {
    display: block;
    margin-bottom: .125rem;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--crm-slate-900);
    /* Tronqué plutôt qu'enroulé : trois lignes de libellé décaleraient les champs voisins de la
       rangée les uns par rapport aux autres. Le texte entier reste dans l'infobulle du champ. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Une pastille remplie se lit comme une valeur, pas comme un jeton.
 *
 * Le texte d'une pastille de saisie est remplacé par ce qu'on tape dans le rail, et le jeton
 * survit dans `data-crm-token` : sans un signe visible, on ne saurait plus si le mot lu est du
 * texte du contrat ou une valeur qui vient d'ailleurs. Le fond s'efface, le pointillé reste :
 * c'est encore un emplacement, il est simplement rempli.
 */
.crm-token.is-saisie.is-rempli {
    background: transparent;
    border-style: dashed;
    font-weight: 600;
}

/* ---- La page pleine ----
 *
 * C'est le chemin réel de cet écran : on n'y arrive que par la redirection du POST de
 * « Nouveau document ». Elle laisse défiler la fenêtre du navigateur, comme la page pleine de
 * l'éditeur de modèle, et la barre d'actions reste visible par son `position: sticky`.
 *
 * Le titre, lui, tient sur une ligne, tronqué, avec le nom complet en infobulle. Le nom d'un
 * modèle repris du portail en fait trois (« HOLENEK - [Rupture conventionnelle] Invitation
 * Entretien rupture Conventionnelle [Contact.FirstName] [Contact.LastName] »), soit une
 * cinquantaine de pixels pris au document pour une information que l'écran donne déjà deux
 * fois : le nom **résolu** est dans la barre d'actions, et le nom du modèle dans l'onglet du
 * navigateur.
 *
 * La troncature est portée par une enveloppe et non par le `h1`, qui est un conteneur **flex**
 * (l'icône y est une vignette de 2,1 rem) : `text-overflow` ne s'applique qu'à un conteneur de
 * bloc. Posée sur le `h1`, elle coupait le nom net sur « ruptu », sans points de suite, ce qui
 * se lit comme un défaut d'affichage et non comme une troncature voulue. Et `min-width: 0`,
 * sans quoi un élément de flex ne descend pas sous la largeur de son contenu.
 */
body.crm-doc-gen-page .crm-doc-gen-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- En fenêtre centrée ----
 *
 * Une seule zone défile, et la barre d'actions est **hors** d'elle : dedans, « Générer le
 * document » tombait sous le bas de la fenêtre, et un formulaire dont on ne voit pas le bouton
 * passe pour un formulaire qu'on ne peut pas envoyer.
 *
 * En page pleine, `.crm-doc-gen-scroll` ne porte rien : c'est la fenêtre du navigateur qui
 * défile, comme sur la page pleine de l'éditeur de modèle, et la barre d'actions y reste
 * visible par son `position: sticky`.
 */
.crm-drawer.is-modal .crm-doc-gen-window .crm-doc-gen { flex: 1 1 auto; min-height: 0; }
.crm-drawer.is-modal .crm-doc-gen-window .crm-doc-gen-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* La bascule « Actif » sur la ligne d'audience : le libellé ne doit pas passer à la ligne
   quand la ligne est déjà chargée. */
.crm-tpl-state { flex: 0 0 auto; font-size: .8125rem; white-space: nowrap; }

/* Garde-fou : sans Select2 (script en échec), un `select multiple` s'affiche en liste haute
   et la ligne d'audience passait de 40 à 150 px. */
.crm-tpl-meta select.crm-tpl-inline[multiple] { height: 2rem; max-width: 14rem; }

/* ------------------------------------------------------------------ Rattachements
 *
 * Une activité peut se rapporter à plusieurs objets : les pastilles s'enroulent au lieu de
 * pousser la largeur du formulaire, et celles qui ne sont pas encore enregistrées se
 * distinguent, sinon on ne sait pas ce qui partira à la validation.
 */
.crm-link-list { display: flex; flex-wrap: wrap; gap: .375rem; }
.crm-link-chip {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    max-width: 100%;
    padding: .175rem .5rem;
    font-size: .8125rem;
    border: 1px solid var(--crm-border);
    border-radius: 999px;
    background: var(--crm-surface);
}
.crm-link-chip.is-pending { border-style: dashed; }
.crm-link-drop {
    border: 0;
    background: transparent;
    color: var(--crm-text-muted);
    padding: 0 0 0 .25rem;
    line-height: 1;
}
.crm-link-drop:hover { color: var(--crm-danger, #dc3545); }

/* La barre de recherche des modèles ne prend pas toute la largeur : au-delà, l'œil ne fait
   plus le lien entre le champ et le compteur qui le termine. */
.crm-tpl-search { max-width: 40rem; }

/* ------------------------------------------------------------------ Frise unifiée
 *
 * Le bloc « À venir » se distingue du passé : sur une frise qui se lit comme un historique,
 * une échéance future placée au-dessus sans marque se lisait comme un évènement passé.
 */
.crm-timeline-day.is-upcoming {
    color: var(--crm-primary, #2f6feb);
    border-bottom: 1px dashed var(--crm-border);
    padding-bottom: .25rem;
}
.crm-timeline-upcoming { margin-bottom: 1rem; }
/* Terminé ou annulé : le titre se barre, plutôt qu'un badge de plus sur une ligne déjà chargée. */
.crm-done { text-decoration: line-through; opacity: .7; }

/* Un compteur d'alerte se voit : « hors délai » à 3 dans la même teinte que « reçues » à 12
   se lisait comme une statistique de plus. Réservé aux dépassements : s'il s'allumait pour
   tout, il n'allumerait plus rien. */
.crm-insight.is-alert { background: #fef2f2; }
.crm-insight.is-alert .crm-insight-value { color: var(--crm-danger, #dc3545); }
.crm-insight.is-alert .crm-insight-label { color: #b91c1c; }

/* Hors d'une carte, le bandeau garde son quadrillage mais reprend un bord complet : posé nu
   sur le fond de page, il n'avait de trait qu'en bas et flottait. */
.crm-insights.mb-3 { border: 1px solid var(--crm-slate-200); border-radius: var(--crm-radius); overflow: hidden; }

/* ------------------------------------------------------------------ Documentation intégrée */
/* Le sommaire suit le défilement : sur une page de treize rubriques, remonter pour changer de
   sujet coûtait un aller-retour à chaque question. */
.crm-doc-toc { position: sticky; top: 1rem; }
.crm-doc-toc .list-group-item { border: 0; padding: .5rem .9rem; font-size: .875rem; }

/* L'ancre s'arrête sous la barre du haut : sans cette marge, le titre de la rubrique visée
   passait derrière l'en-tête fixe et on atterrissait au milieu du texte. */
.crm-doc-section { scroll-margin-top: 4.5rem; }
.crm-doc-summary { font-size: 1rem; color: var(--crm-slate-700); }
.crm-doc-heading {
    margin-top: 1.1rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--crm-slate-500);
}
.crm-doc-list { padding-left: 1.1rem; margin-bottom: 0; }
.crm-doc-list li { margin-bottom: .35rem; line-height: 1.5; }
/* Les règles se distinguent du reste : c'est la partie qu'on relit. */
.crm-doc-rules li { color: var(--crm-slate-800); }
.crm-doc-tech {
    margin-top: 1.1rem;
    padding: .6rem .8rem;
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    background: var(--crm-slate-50, #f8fafc);
    font-size: .8125rem;
}
.crm-doc-tech > summary { cursor: pointer; font-weight: 600; color: var(--crm-slate-700); }
.crm-doc-tech[open] > summary { margin-bottom: .6rem; }
.crm-doc-tech code { font-size: .8125rem; }

/* Le cadre d'aperçu occupe la largeur du papier et grandit avec son contenu jusqu'à une
   hauteur raisonnable : au-delà, c'est lui qui défile, pas la fenêtre. */
.crm-tpl-frame {
    display: block;
    width: 100%;
    min-height: 18rem;
    height: 26rem;
    border: 0;
    background: #fff;
}

/* Le cadre d'aperçu d'une **signature**, plus court que celui d'un corps d'e-mail.
   `.crm-tpl-frame` fait 26 rem, ce qu'il faut pour lire un message ; une signature en occupe
   quatre, et le même cadre laissait 300 px de blanc sous elle, qui se lisaient comme un aperçu
   vide plutôt que comme une signature courte. */
.crm-signature-frame { height: 11rem; min-height: 0; }

/* L'aperçu suit le défilement : on règle une couleur en la regardant, et il partait sous la
   ligne de flottaison dès le troisième réglage. `top` dégage la barre supérieure. */
.crm-signature-preview { position: sticky; top: 1rem; }
/* L'éditeur riche remplace le textarea plat : la boîte du cadre lui sert de bordure, comme
   pour les autres lignes du composeur. */
.crm-tpl-area .note-editor.note-frame { border: 0; margin-bottom: 0; }
.crm-tpl-area .note-editor .note-toolbar { border-bottom: 1px solid var(--crm-border); background: transparent; }
.crm-tpl-area .note-editor .note-statusbar { display: none; }

/* ------------------------------------------------------------------ Jetons de modèle
 *
 * Une variable se lit et se manipule comme un objet, pas comme du texte : `{{prenom}}` en
 * clair au milieu d'une phrase s'édite par accident, on en efface la moitié sans le voir, et
 * le modèle part avec un `{{preno}}` que rien ne remplacera. La pastille est insécable
 * (`contenteditable="false"`) : elle se supprime d'un coup ou pas du tout.
 */
.crm-token {
    display: inline-block;
    padding: .05rem .4rem;
    margin: 0 .05rem;
    border-radius: var(--crm-radius-sm, .25rem);
    background: #e8f0fe;
    border: 1px solid #c6dafc;
    color: #14418b;
    font-size: .875em;
    line-height: 1.4;
    white-space: nowrap;
    cursor: default;
    user-select: all;
}
.crm-token::before { content: "\f02b"; font-family: "Font Awesome 5 Free"; font-weight: 900; font-size: .8em; margin-right: .25rem; opacity: .6; }

/* ---- Nature du jeton, par la couleur ----
 *
 * La couleur répond d'un coup d'œil à « d'où vient cette valeur ? », qui est la question qu'on
 * se pose en relisant un contrat : de la fiche, d'un objet lié, de moi, de l'horloge, ou de
 * quelqu'un qui devra la taper. Tous en bleu, rien ne les distinguait.
 *
 * Le pictogramme double l'information : une couleur seule ne se lit pas en niveaux de gris, et
 * c'est sur papier que ces documents finissent.
 */
.crm-token.is-lie { background: #f3e8fd; border-color: #ddc4f7; color: #5b21b6; }
.crm-token.is-lie::before { content: "\f0c1"; }

.crm-token.is-saisie { background: #fef3c7; border-color: #fcd34d; color: #92400e; }
.crm-token.is-saisie::before { content: "\f303"; }

.crm-token.is-moi { background: #ccfbf1; border-color: #5eead4; color: #115e59; }
.crm-token.is-moi::before { content: "\f007"; }

.crm-token.is-doc { background: var(--crm-slate-100, #f1f5f9); border-color: var(--crm-border); color: var(--crm-slate-700, #334155); }
.crm-token.is-doc::before { content: "\f073"; }

/*
 * Une valeur venue de la fiche : **discrète**.
 *
 * Le corps d'un contrat en porte cent dix-neuf. Peintes comme un jeton de rédaction, bordure et
 * fond bleus, elles faisaient du contrat un damier illisible : or ce qu'on vient relire est le
 * contrat, et la pastille n'est là que pour dire « ceci vient de la fiche ». Un soulignement
 * pointillé et un fond à peine teinté suffisent, sans icône : le texte reste du texte.
 */
.crm-token.is-valeur {
    background: rgba(47, 111, 235, .06);
    border-color: transparent;
    border-bottom: 1px dashed rgba(47, 111, 235, .45);
    border-radius: 0;
    color: inherit;
    padding: 0 .1rem;
}
.crm-token.is-valeur::before { content: none; }
.crm-token.is-valeur:hover { background: rgba(47, 111, 235, .14); }

/*
 * Une valeur **vide** sur la fiche : elle se voit, parce que c'est un trou dans le contrat.
 *
 * C'est l'inverse du réglage ci-dessus, et pour la même raison : ce qu'on cherche des yeux
 * avant d'envoyer n'est pas ce qui est juste, c'est ce qui manque. Le fond ambre et le
 * pictogramme d'alerte la désignent, et l'infobulle dit quoi faire.
 */
.crm-token.is-vide {
    background: #fef3c7;
    border-color: #fcd34d;
    border-style: dashed;
    color: #92400e;
    cursor: text;
}
.crm-token.is-vide::before { content: "\f071"; opacity: .8; }

/*
 * Un champ **protégé** : la valeur est là, masquée ici, reprise en clair dans le PDF.
 *
 * En pointillés comme le jeton inconnu, mais en gris et sous un cadenas : le pointillé dit
 * « ce n'est pas la valeur définitive », la couleur neutre dit que ce n'est pas une anomalie.
 * En rouge on l'aurait pris pour une coquille, en bleu de champ de fiche pour une valeur que la
 * reprise aurait manquée, ce qui est précisément la conclusion qu'on en tirait.
 */
.crm-token.is-protege {
    background: var(--crm-slate-100, #f1f5f9);
    border-color: var(--crm-slate-400, #94a3b8);
    border-style: dashed;
    color: var(--crm-slate-700, #334155);
    letter-spacing: .04em;
}
.crm-token.is-protege::before { content: "\f023"; opacity: .75; }

/*
 * Un jeton que le catalogue ne connaît pas : presque toujours une faute de frappe. Il se
 * découvrait jusqu'ici à la génération, sur un document déjà troué. En rouge et en pointillés,
 * il se voit en écrivant.
 */
.crm-token.is-inconnu {
    background: #fee2e2;
    border-color: #fca5a5;
    border-style: dashed;
    color: #991b1b;
}
.crm-token.is-inconnu::before { content: "\f071"; opacity: .8; }

/* ---- Les mêmes pastilles dans un champ de texte simple ----
 *
 * Un modèle de SMS est du texte brut dans un `<textarea>`, et le restera : l'éditeur riche y
 * injecterait des balises qui comptent comme des caractères et partent en clair chez le
 * destinataire (point 74). Or un `<textarea>` ne stylise pas une partie de son contenu, et
 * `{{prenom}}` s'y lisait donc comme du texte au milieu d'une phrase, exactement ce que la
 * pastille existe pour éviter.
 *
 * Le surlignage est un **miroir** posé derrière le champ : même texte, mêmes métriques, seuls
 * les jetons y portent un fond. Le champ garde son texte visible et reste un `<textarea>`
 * ordinaire, ce qui est le point qui compte : le chemin d'écriture, le compteur de segments,
 * l'insertion au curseur et la saisie mobile ne changent pas d'un caractère. Ce dépôt a déjà
 * payé deux fois la destruction de jetons par un éditeur qui s'interpose (points 57 et 62).
 *
 * Le miroir ne doit **rien** ajouter à la métrique du texte, sinon tout ce qui suit un jeton
 * se décale : pas de padding, pas de bordure, pas d'autre taille de police. Le liseré est donc
 * un `box-shadow`, qui ne prend aucune place.
 *
 * Rien ici ne s'applique tant que le script n'a pas posé `is-active` : sans lui, le champ reste
 * un champ normal. Une transparence portée par la feuille seule aurait rendu le texte invisible
 * le jour où le script ne tourne pas.
 */
.crm-token-mirror-wrap { position: relative; }
.crm-token-mirror {
    position: absolute;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    color: transparent;
    pointer-events: none;
}
.crm-token-mirror-wrap > textarea { position: relative; z-index: 1; }

/* Le fond et la bordure de mise au point passent au conteneur : `.crm-tpl-flat:focus` pose un
   fond **opaque** sur le champ, et les pastilles disparaissaient donc au premier clic, c'est-à-dire
   au seul moment où l'on regarde ce qu'on écrit. */
.crm-token-mirror-wrap.is-active {
    border: 1px solid transparent;
    border-radius: var(--crm-radius-sm, .25rem);
}
.crm-token-mirror-wrap.is-active:focus-within {
    border-color: var(--crm-primary, #2f6feb);
    background: var(--crm-surface);
}
.crm-token-mirror-wrap.is-active > textarea,
.crm-token-mirror-wrap.is-active > textarea:focus {
    border-color: transparent;
    background: transparent;
}

.crm-token-mark {
    border-radius: var(--crm-radius-sm, .25rem);
    background: #e8f0fe;
    box-shadow: 0 0 0 1px #c6dafc;
}

/* ------------------------------------------------------------------ Endosser un compte
 *
 * Au bas de la barre latérale, comme sur l'extranet MYTEK. Détaché du menu par un trait : ce
 * n'est pas une entrée de navigation, c'est un geste, et le confondre avec les autres lignes
 * ferait cliquer dessus par erreur.
 */
.crm-switch {
    margin: .5rem .75rem 1rem;
    padding: .6rem .7rem;
    border-top: 1px solid rgba(255, 255, 255, .10);
    border-radius: var(--crm-radius);
    background: rgba(255, 255, 255, .04);
}
.crm-switch-title {
    display: block;
    margin: 0 0 .4rem;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .02em;
    color: rgba(255, 255, 255, .62);
    text-transform: uppercase;
}
.crm-switch-form { display: flex; gap: .35rem; }
.crm-switch-form select { min-width: 0; flex: 1 1 auto; }
.crm-switch-form .btn { flex: 0 0 auto; }

/*
 * Pendant qu'on endosse quelqu'un, la place change de sens et doit changer de couleur.
 *
 * C'est le seul état du CRM où l'écran ne montre pas vos données : le confondre avec le sien
 * est la façon la plus simple d'écrire une note au nom d'un collègue sans s'en apercevoir. Le
 * fond ambre le dit, et le nom endossé est écrit en clair plutôt que sous-entendu.
 */
.crm-switch.is-active {
    background: rgba(245, 158, 11, .16);
    border-top-color: rgba(245, 158, 11, .45);
}
.crm-switch.is-active .crm-switch-title {
    color: #fcd34d;
    text-transform: none;
    font-size: .8125rem;
    line-height: 1.35;
}
.crm-switch.is-active .crm-switch-title strong { color: #fff; }
.crm-switch-exit {
    display: inline-block;
    font-size: .8125rem;
    font-weight: 600;
    color: #fff;
    text-decoration: underline;
}
.crm-switch-exit:hover { color: #fcd34d; }

/* ------------------------------------------------------------------ Onglets d'objet
 *
 * Bandeau de navigation entre les écrans de configuration d'un même objet. Il se détache du
 * contenu par un trait continu : sans lui, les onglets flottaient au-dessus du premier titre
 * et on les lisait comme un fil d'Ariane.
 */
.crm-object-tabs { margin-bottom: 1.25rem; border-bottom: 1px solid var(--crm-border); }
.crm-object-tabs .nav-tabs { border-bottom: 0; flex-wrap: wrap; }
.crm-object-tabs .nav-link {
    border: 0;
    border-bottom: 2px solid transparent;
    padding: .6rem .9rem;
    color: var(--crm-slate-600);
    font-size: .875rem;
}
.crm-object-tabs .nav-link:hover { border-bottom-color: var(--crm-slate-300); color: var(--crm-slate-900); }
.crm-object-tabs .nav-link.active {
    background: transparent;
    border-bottom-color: var(--crm-primary, #2f6feb);
    color: var(--crm-slate-900);
    font-weight: 600;
}
.crm-object-tabs .nav-link.disabled { cursor: default; }
.crm-object-tabs .nav-link.disabled:hover { border-bottom-color: transparent; }

/* ============================================================================
   Journée de l'organisateur, dans le formulaire de rendez-vous
   ============================================================================ */

/* Les lignes sont séparées par un filet plutôt que par des marges : une journée chargée
   tiendrait sinon plus haut que le formulaire, et le créneau saisi sortirait de l'écran. */
.crm-agenda-day > li + li { border-top: 1px dashed var(--crm-border); }

/* Un chevauchement se signale sur toute la ligne, pas seulement par son icône : c'est ce qu'on
   cherche du regard, et l'icône seule se perdait au bout d'un titre long. */
.crm-agenda-day > li.crm-agenda-clash {
    background: var(--crm-warning-soft);
    margin: 0 -.5rem;
    padding-left: .5rem;
    padding-right: .5rem;
    border-radius: .25rem;
}

/*
 * Liens qualifiés rendus dans l'encart d'un objet.
 *
 * Séparés par un filet et introduits par un intitulé discret : sans cette césure, un lien
 * qualifié se lisait comme un objet de la colonne, alors que les deux ne veulent pas dire la
 * même chose, l'un est une structure (« ce contact est le candidat de ce positionnement »),
 * l'autre un rôle nommé par l'organisation.
 */
.crm-relation-inline { margin-top: .6rem; padding-top: .5rem; border-top: 1px dashed var(--crm-border); }

.crm-relation-inline-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--crm-text-faint);
    margin-bottom: .2rem;
}

.crm-relation-inline-head .btn-link { padding: 0; font-size: .74rem; text-transform: none; letter-spacing: 0; }

/* ============================================================================
   Dépliage d'une ligne de liste, et menu de colonne
   ============================================================================ */

/* Colonne du chevron : étroite, comme celle des cases. */
.crm-table th.crm-col-expand,
.crm-table td.crm-col-expand { width: 2.2rem; min-width: 2.2rem; padding-left: .5rem; padding-right: 0; }

.crm-row-toggle { padding: 0 .2rem; color: var(--crm-text-faint); }
.crm-row-toggle:hover { color: var(--crm-primary); text-decoration: none; }
.crm-row-toggle i { transition: transform var(--crm-ease); }
.crm-row-toggle[aria-expanded="true"] i { transform: rotate(90deg); }

/* Le détail se lit comme un encart, pas comme une ligne de tableau : fond propre et
   séparation nette, sinon l'œil le confond avec la ligne suivante. */
.crm-row-details > td { background: var(--crm-slate-50); border-top: 0; padding: .75rem 1rem; }

.crm-row-details-grid {
    display: grid;
    /* Deux à quatre colonnes selon la largeur : une seule colonne rendait le dépliage plus
       haut que l'écran dès huit champs. */
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: .35rem 1.5rem;
    margin: 0 0 .5rem;
}

.crm-row-details-grid dt {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--crm-text-faint);
    margin: 0;
}

.crm-row-details-grid dd { margin: 0 0 .4rem; font-size: .86rem; }

/*
 * Le menu d'une colonne n'apparaît qu'au survol de son en-tête, comme la poignée de
 * redimensionnement : trois points sur chaque colonne en permanence, c'est une ligne d'en-tête
 * qui ne parle plus que d'elle-même.
 */
.crm-col-menu { opacity: 0; transition: opacity var(--crm-ease); }
.crm-table th:hover .crm-col-menu,
.crm-col-menu.show,
.crm-col-menu:focus-within { opacity: 1; }
.crm-col-menu-btn { padding: 0 .25rem; color: var(--crm-text-muted); }
.crm-col-menu-btn:hover { color: var(--crm-slate-900); text-decoration: none; }

/* ============================================================================
   Encarts composés typés
   ============================================================================ */

/* Table d'objets liés dans un encart : la même que les listes, en plus serré, un encart de
   300 px ne porte pas les paddings d'un tableau plein écran. */
.crm-card-table th { font-size: .7rem; text-transform: uppercase; letter-spacing: .02em; color: var(--crm-text-faint); }
.crm-card-table td { font-size: .84rem; vertical-align: middle; }

/* Suivi des phases : une colonne de puces reliées, la phase courante en évidence. Le chemin
   complet est visible : « où en est-on » suppose de voir ce qui reste. */
.crm-card-stages { list-style: none; margin: 0; padding: 0; }

.crm-card-stages li {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .28rem 0;
    font-size: .86rem;
    color: var(--crm-text-muted);
}

.crm-card-stages li.is-current { color: var(--crm-slate-900); font-weight: 600; }

.crm-card-stage-dot {
    flex: 0 0 auto;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--crm-slate-300);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1);
}

.crm-card-stages li.is-current .crm-card-stage-dot { background: var(--crm-primary); }
.crm-card-stage-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Totaux d'activité : des chiffres qu'on compare d'un coup d'œil, donc alignés en grille et non
   en phrases. */
.crm-card-totals { display: grid; grid-template-columns: repeat(auto-fit, minmax(4.5rem, 1fr)); gap: .4rem; }

.crm-card-total {
    text-align: center;
    padding: .4rem .2rem;
    background: var(--crm-slate-50);
    border-radius: var(--crm-radius);
}

.crm-card-total-value { display: block; font-size: 1.1rem; font-weight: 600; color: var(--crm-slate-900); }
.crm-card-total-label { display: block; font-size: .7rem; color: var(--crm-text-muted); }

/* Automatisations : un interrupteur, ce qu'il fait, et quand. Le « quand » est mis en retrait et
   non en infobulle : c'est l'information qui décide, elle ne doit pas demander un survol. */
.crm-automation { padding: .8rem 0; border-bottom: 1px solid var(--crm-border-soft); }
.crm-automation:last-child { border-bottom: 0; }
.crm-automation-help { margin: .3rem 0 .15rem 2.2rem; font-size: .875rem; }
.crm-automation-effect { margin: 0 0 0 2.2rem; font-size: .8rem; color: var(--crm-text-muted); }

/* ============================================================================
   Édition en place dans une cellule de liste
   ============================================================================ */

/*
 * Le repère est **discret et au survol**, contrairement à la fiche où le soulignement pointillé
 * est permanent : vingt-cinq lignes sur six colonnes feraient cent cinquante pointillés à
 * l'écran, ce qui donne l'impression d'un tableau en travaux. Le crayon apparaît au survol de la
 * cellule, comme dans le portail.
 */
.crm-cell-edit {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    max-width: 100%;
    min-width: 0;
    border-radius: var(--crm-radius-sm);
    cursor: text;
}

.crm-cell-edit > * { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.crm-cell-edit::after {
    content: '\f304'; /* crayon FontAwesome */
    font-family: 'Font Awesome 5 Free';
    font-weight: 900;
    font-size: .7rem;
    color: var(--crm-text-faint);
    opacity: 0;
    transition: opacity var(--crm-ease);
    flex: 0 0 auto;
}

.crm-table tbody tr:hover .crm-cell-edit::after { opacity: 1; }

/* En cours de saisie, la cellule s'affranchit de la troncature : un champ à demi visible ne se
   remplit pas. Le contrôle prend la largeur de la cellule, pas celle de son contenu. */
.crm-cell-edit:focus-within { cursor: auto; }
.crm-cell-edit:focus-within::after { opacity: 0; }
.crm-cell-edit input,
.crm-cell-edit select,
.crm-cell-edit textarea { width: 100%; min-width: 7rem; font-size: .82rem; padding: .1rem .3rem; }

/*
 * La cellule en édition doit pouvoir déborder de son `overflow: hidden`.
 *
 * Toutes les cellules sont tronquées sur une ligne (`crm-col-clipped`) : un menu Select2 ouvert
 * dedans était coupé net. La cellule qui contient un contrôle relâche donc la troncature.
 */
.crm-table td.crm-col-clipped:has(.crm-cell-edit input),
.crm-table td.crm-col-clipped:has(.crm-cell-edit select),
.crm-table td.crm-col-clipped:has(.crm-cell-edit textarea) { overflow: visible; }

/* =============================================================================================
 * Éditeur d'agencement de fiche (/admin/fiches/{objet})
 *
 * Les trois colonnes de l'éditeur reproduisent celles de la fiche, aux mêmes largeurs relatives.
 * C'est tout l'intérêt de l'écran : avant, « au centre » et « à droite » n'étaient que deux
 * intitulés de listes à puces, et il fallait ouvrir une fiche dans un autre onglet pour juger du
 * résultat. Une table de dix colonnes posée à droite se voit désormais tout de suite.
 * ============================================================================================= */

.crm-editor-bar {
    position: sticky;
    top: 0;
    z-index: 1020;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    margin-bottom: 1rem;
    background: var(--crm-slate-900);
    color: #fff;
    border-radius: var(--crm-radius-lg);
    box-shadow: var(--crm-shadow);
}

.crm-editor-quit { color: rgba(255, 255, 255, .75); font-size: .85rem; }
.crm-editor-quit:hover { color: #fff; text-decoration: none; }

.crm-editor-history .btn {
    color: rgba(255, 255, 255, .8);
    background: rgba(255, 255, 255, .08);
    border: 1px solid rgba(255, 255, 255, .16);
}
.crm-editor-history .btn:hover:not(:disabled) { color: #fff; background: rgba(255, 255, 255, .18); }
.crm-editor-history .btn:disabled { opacity: .35; }

.crm-editor-title {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    margin-left: .5rem;
    font-weight: 600;
}
.crm-editor-view { font-size: .78rem; font-weight: 400; color: rgba(255, 255, 255, .7); }
.crm-editor-view small { color: rgba(255, 255, 255, .5); }

.crm-editor-views {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: .75rem;
}

/*
 * Le plan de la fiche. Les proportions sont celles de `contact/show.html.twig` : identité
 * étroite, centre large, encarts liés étroits. En dessous de 1200 px les colonnes s'empilent :
 * un glisser-déposer entre trois colonnes de 200 px n'aurait aucune précision.
 */
.crm-editor-canvas {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 5fr) minmax(0, 3fr);
    gap: .75rem;
    align-items: start;
    margin-bottom: 1rem;
}

@media (max-width: 1199.98px) {
    .crm-editor-canvas { grid-template-columns: minmax(0, 1fr); }
}

.crm-editor-col {
    background: var(--crm-bg);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    padding: .6rem;
}

.crm-editor-col-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .5rem;
    font-size: .78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--crm-text-muted);
}
.crm-editor-col-head small { text-transform: none; letter-spacing: 0; font-weight: 400; }

/* Une zone garde sa hauteur même vide : sans elle, on ne pourrait rien déposer dans une colonne
   qu'on vient de vider, et le premier encart y serait irrattrapable sans recharger. */
.crm-editor-zone { min-height: 3.5rem; margin-bottom: .5rem; }

.crm-editor-empty {
    padding: .75rem;
    font-size: .8rem;
    text-align: center;
    color: var(--crm-text-faint);
    border: 1px dashed var(--crm-border);
    border-radius: var(--crm-radius);
}

.crm-editor-card {
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    margin-bottom: .4rem;
    box-shadow: var(--crm-shadow-sm);
}
.crm-editor-card.is-dragging { box-shadow: var(--crm-shadow-lg); opacity: .95; }

.crm-editor-card-head { display: flex; align-items: center; padding: .45rem .5rem; }
.crm-editor-card-name { display: flex; flex-direction: column; min-width: 0; margin-right: auto; }
.crm-editor-card-title { font-size: .88rem; font-weight: 600; color: var(--crm-text); }
.crm-editor-card-sub { font-size: .72rem; color: var(--crm-text-muted); }

.crm-editor-grip { cursor: grab; }
.crm-editor-grip:active { cursor: grabbing; }

.crm-editor-menu-btn { padding: 0 .35rem; }

/* Marqueur de condition : la carte doit dire qu'elle ne s'affiche pas partout, sinon on la
   cherche en vain sur une fiche où la condition ne passe pas. */
.crm-editor-cond {
    flex: 0 0 auto;
    margin-right: .35rem;
    padding: .05rem .35rem;
    font-size: .68rem;
    color: var(--crm-info);
    background: var(--crm-info-soft);
    border-radius: var(--crm-radius-sm);
    white-space: nowrap;
}

.crm-editor-rule {
    padding: .6rem .55rem .5rem;
    border-top: 1px dashed var(--crm-border);
    background: var(--crm-bg);
    border-radius: 0 0 var(--crm-radius) var(--crm-radius);
}

/*
 * Une ligne de condition : jonction, champ, sens, valeurs, retrait.
 *
 * Cinq contrôles sur une ligne dans une colonne de 300 px n'y tiendraient pas : la grille les
 * range sur deux rangs, la jonction et le champ d'abord, le sens et les valeurs ensuite. Une
 * seule rangée, à la manière des indicateurs de liste, aurait donné cinq contrôles de 50 px où
 * aucun libellé n'est lisible.
 */
.crm-editor-rule-row {
    display: grid;
    grid-template-columns: 3.2rem minmax(0, 1fr) 1.4rem;
    /*
     * Trois rangs et non deux : le sens de la condition occupe toute la largeur.
     *
     * Placé dans la colonne de la jonction, large de 3,2 rem, « est l'un de » se lisait
     * « est » et « n'est aucun de » se lisait « n'e… » : les deux seules valeurs du menu
     * devenaient indiscernables, ce qui est la pire troncature possible sur un contrôle à deux
     * choix opposés.
     */
    grid-template-areas:
        'join field drop'
        'sense sense sense'
        'values values values';
    gap: .3rem;
    padding: .4rem;
    margin-bottom: .4rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
}
.crm-editor-rule-row:last-child { margin-bottom: .45rem; }

.crm-editor-rule-join { grid-area: join; display: flex; align-items: center; }
.crm-editor-rule-row [data-crm-rule-field] { grid-area: field; }
.crm-editor-rule-row [name$="[negate]"] { grid-area: sense; }
.crm-editor-rule-row [data-crm-rule-values] { grid-area: values; }
.crm-editor-rule-drop { grid-area: drop; }

/* « Si » remplace le menu de jonction sur la première ligne : elle ouvre le premier groupe. */
.crm-editor-rule-first {
    font-size: .7rem;
    font-weight: 700;
    color: var(--crm-text-faint);
    text-transform: uppercase;
}

.crm-editor-rule-row select { height: 1.9rem; padding: 0 .3rem; font-size: .78rem; }
.crm-editor-rule-row select[multiple] { height: auto; min-height: 3.4rem; padding: .15rem .3rem; }

/* Une croix grise qui ne rougit qu'au survol : on ne retire presque rien ici. */
.crm-editor-rule-drop {
    align-self: center;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--crm-text-faint);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}
.crm-editor-rule-drop:hover { color: var(--crm-danger); }

.crm-editor-cond-count {
    margin-left: .2rem;
    font-size: .65rem;
    font-weight: 700;
    line-height: 1;
}

.crm-editor-rule-add {
    padding: .1rem 0;
    border: 0;
    background: transparent;
    color: var(--crm-primary-dark);
    font-size: .75rem;
    cursor: pointer;
}
.crm-editor-rule-add:hover { text-decoration: underline; }

/* Bande d'onglets, au-dessus des encarts du centre comme sur la fiche. */
.crm-editor-tabstrip {
    padding: .5rem;
    margin-bottom: .6rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
}
.crm-editor-tabstrip-label {
    display: flex;
    align-items: baseline;
    gap: .4rem;
    margin-bottom: .35rem;
    font-size: .78rem;
    font-weight: 600;
    color: var(--crm-text-muted);
}
.crm-editor-tabstrip-label small { font-weight: 400; color: var(--crm-text-faint); }

.crm-editor-tabs { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: .4rem; min-height: 2rem; }
.crm-editor-tab {
    display: flex;
    align-items: center;
    padding: .2rem .4rem;
    font-size: .8rem;
    background: var(--crm-primary-soft);
    color: var(--crm-primary-dark);
    border-radius: var(--crm-radius-sm);
}
.crm-editor-tab .close { font-size: 1rem; line-height: 1; }

.crm-editor-add .dropdown-menu { max-height: 20rem; overflow-y: auto; }

.crm-editor-settings-toggle { font-weight: 600; }

/* Un encart composé et son formulaire : la ligne entière est la cible de l'ancre du crayon, d'où
   le fond qui la distingue de ses voisines. */
.crm-editor-composed {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    padding: .5rem;
    margin-bottom: .5rem;
    background: var(--crm-bg);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
}
.crm-editor-composed > form:first-child { flex: 1 1 auto; min-width: 0; }
.crm-editor-composed:target { border-color: var(--crm-primary); box-shadow: var(--crm-ring); }

/* Repère de dépôt : il prend la place de la carte déplacée, sinon la colonne se réorganise sous
   le curseur et on ne sait plus où l'on va lâcher. */
.crm-editor-card-placeholder {
    height: 2.6rem;
    margin-bottom: .4rem;
    background: var(--crm-primary-soft);
    border: 1px dashed var(--crm-primary);
    border-radius: var(--crm-radius);
}
.crm-editor-tab-placeholder {
    width: 6rem;
    height: 1.7rem;
    background: var(--crm-primary-soft);
    border: 1px dashed var(--crm-primary);
    border-radius: var(--crm-radius-sm);
}

/*
 * Les menus de l'éditeur se positionnent sur leur carte, pas sur la page.
 *
 * `.dropdown` ne porte pas `position: relative` dans cette feuille, et Popper ne reprend pas la
 * main ici : le menu d'une carte s'affichait donc **en bas du document**, à mille cinq cents
 * pixels de la carte qui l'avait ouvert, et le menu « Ajouter » prenait toute la largeur de la
 * page. Ancrer le parent suffit.
 */
.crm-editor-card .dropdown,
.crm-editor-add { position: relative; }
.crm-editor-add .dropdown-menu { min-width: 100%; max-width: 22rem; }

/* =============================================================================================
 * Cartes composées : galerie de types, configurateur, et les deux nouveaux types d'encart
 * ============================================================================================= */

/* Galerie « Créer une carte » : une tuile par type, avec ce qu'il affiche. Le type était une
   liste déroulante sans explication, et on découvrait ce qu'il montrait après l'avoir créé. */
.crm-card-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .75rem;
}

.crm-card-tile {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    padding: .75rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    box-shadow: var(--crm-shadow-sm);
}

.crm-card-tile-head { display: flex; align-items: center; gap: .5rem; }

.crm-card-tile-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    color: var(--crm-primary);
    background: var(--crm-primary-soft);
    border-radius: var(--crm-radius);
}

/*
 * Configurateur : réglages à gauche, aperçu à droite, les proportions du portail.
 *
 * L'aperçu reste visible en réglant : c'est tout l'intérêt. Sous 900 px il passe dessous, un
 * aperçu de 200 px de large ne montrant plus rien d'utile.
 */
.crm-card-config-grid {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    /*
     * Une gouttière de 16 px laissait les deux panneaux se toucher presque : l'aperçu porte un
     * fond et une bordure, la liste de champs n'en a pas, et à cette distance le regard les lit
     * comme un seul bloc dont la moitié droite serait grisée. 28 px les séparent assez pour
     * qu'on comprenne qu'on règle à gauche et qu'on juge à droite.
     */
    gap: 1.75rem;
    align-items: start;
}

@media (max-width: 900px) {
    .crm-card-config-grid { grid-template-columns: minmax(0, 1fr); }
}

.crm-card-config-preview {
    position: sticky;
    top: 0;
    /* L'aperçu est un encart : il respire comme un encart, pas comme une cellule. */
    padding: 1rem;
    background: var(--crm-bg);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
}

.crm-card-config-actions {
    display: flex;
    justify-content: flex-end;
    gap: .5rem;
    margin-top: 1rem;
    padding-top: .75rem;
    border-top: 1px solid var(--crm-border);
}

/*
 * En fenêtre centrée : le contenu défile, la barre d'actions ne défile pas.
 *
 * Sans cela, sur un bloc de quinze champs, « Enregistrer » tombait sous le bas de la fenêtre, et
 * un formulaire dont on ne voit pas le bouton passe pour un formulaire qu'on ne peut pas
 * enregistrer. C'est la leçon déjà tirée de l'éditeur d'e-mail, appliquée ici.
 */
.crm-drawer.is-modal .crm-card-config {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
.crm-drawer.is-modal .crm-card-config-grid,
.crm-drawer.is-modal .crm-card-config > .crm-card-config-form {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /*
     * `overflow-x: hidden`, et c'est une correction et non une précaution.
     *
     * La zone défilait aussi horizontalement : une barre grise traversait le bas de la fenêtre
     * pour deux pixels de débordement, ceux du rembourrage réservé à l'ascenseur vertical. Une
     * barre de défilement qui n'a rien à faire défiler donne à un formulaire de réglage l'air
     * d'être trop grand pour sa fenêtre.
     */
    overflow-x: hidden;
    /*
     * Aucun retrait ici : il vient du corps de la fenêtre.
     *
     * En ajouter un décalait les lignes de 8 px de plus que la barre d'actions, qui est hors
     * de la zone qui défile : les deux bords droits ne s'alignaient plus, et c'est le genre
     * d'écart qu'on voit sans savoir le nommer.
     */
    padding-right: 0;
}

/*
 * La barre d'actions respire, et se détache de ce qui défile au-dessus.
 *
 * « Annuler » et « Enregistrer » étaient à quelques pixels de la dernière ligne et du bord bas :
 * le geste le plus important de l'écran était le plus serré.
 */
.crm-drawer.is-modal .crm-card-config-actions {
    flex: 0 0 auto;
    margin-top: 0;
    padding: .9rem 0 0;
}

/* Une action de la carte en cours de réglage : poignée, type, corbeille, la rangée du portail. */
.crm-card-action-row {
    display: flex;
    align-items: flex-end;
    gap: .5rem;
    padding: .5rem;
    margin-bottom: .5rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-left: 3px solid var(--crm-primary);
    border-radius: var(--crm-radius);
}
.crm-card-action-grip { color: var(--crm-text-faint); padding-bottom: .5rem; }

/* Une condition de table : trois contrôles sur une ligne, la corbeille au bout. */
.crm-card-filter {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 8.5rem minmax(0, 1fr) 2rem;
    gap: .35rem;
    align-items: start;
    margin-bottom: .4rem;
}

/* Actions rapides sur la fiche : des boutons pleine largeur, comme dans le portail, une rangée
   de petits boutons dans une colonne de 200 px se lit mal et se clique moins bien. */
.crm-card-actions { display: flex; flex-direction: column; gap: .35rem; }

.crm-card-action {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .4rem .6rem;
    color: var(--crm-text);
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    transition: background var(--crm-ease), border-color var(--crm-ease);
}
.crm-card-action:hover {
    color: var(--crm-primary-dark);
    background: var(--crm-primary-soft);
    border-color: var(--crm-primary);
    text-decoration: none;
}
.crm-card-action i { width: 1rem; text-align: center; color: var(--crm-text-muted); }
.crm-card-action:hover i { color: var(--crm-primary); }

/* Flux d'activités dans un encart : la frise, resserrée pour tenir dans une colonne. */
.crm-timeline-compact .crm-timeline-item { padding-bottom: .5rem; }

/* La carte visée par l'engrenage d'une fiche, à l'arrivée sur le plan : sans repère, on
   retrouvait l'écran d'agencement sans savoir laquelle des vingt cartes on venait de désigner. */
.crm-editor-card.is-focused {
    border-color: var(--crm-primary);
    box-shadow: var(--crm-ring);
}

/* =============================================================================================
 * Éditeur d'agencement : reprise du plan du portail
 *
 * Les colonnes ne portent plus de fond gris : dans le portail les cartes flottent sur du blanc,
 * séparées par un filet vertical. Le fond gris faisait lire les colonnes comme trois panneaux de
 * réglage, alors que ce sont les trois colonnes de la fiche.
 * ============================================================================================= */

.crm-editor-tabs {
    display: flex;
    justify-content: center;
    gap: 1.5rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--crm-border);
}

.crm-editor-tab {
    padding: .5rem .25rem;
    font-size: .9rem;
    font-weight: 600;
    color: var(--crm-text-muted);
    background: none;
    border: 0;
    border-bottom: 2px solid transparent;
}
.crm-editor-tab:hover { color: var(--crm-text); }
.crm-editor-tab.is-active { color: var(--crm-text); border-bottom-color: var(--crm-slate-900); }

.crm-editor-col {
    background: var(--crm-surface);
    border: 0;
    border-radius: 0;
    padding: 0 .6rem;
}
.crm-editor-canvas {
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius-lg);
    padding: .75rem .25rem;
}
/* Le filet qui sépare les colonnes, comme dans le portail : il dit où s'arrête la colonne
   d'identité, ce que trois zones posées sur du blanc ne montraient plus. */
.crm-editor-col + .crm-editor-col { border-left: 1px solid var(--crm-border-soft); }

/* En-tête d'identité : le repère qui manquait en tête de colonne. Ce n'est pas une carte
   déplaçable : nom, avatar et actions sont écrits dans le gabarit de la fiche. */
.crm-editor-identity {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .6rem;
    margin-bottom: .5rem;
    background: var(--crm-bg);
    border: 1px dashed var(--crm-border);
    border-radius: var(--crm-radius);
    color: var(--crm-text-muted);
    font-size: .85rem;
}
.crm-editor-identity-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    color: var(--crm-text-muted);
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
}
.crm-editor-identity-lines { display: flex; gap: .25rem; margin-top: .35rem; }
.crm-editor-identity-lines span {
    display: block;
    width: 1.4rem;
    height: .35rem;
    background: var(--crm-border);
    border-radius: var(--crm-radius-sm);
}

/*
 * Une carte conditionnée est estompée, et porte une icône de branche.
 *
 * La pastille « logique conditionnelle » mangeait la largeur d'une colonne de 190 px : le titre
 * passait sur deux lignes, et la carte devenait plus haute que celles qui n'ont pas de condition
 *, l'inverse de ce qu'on veut voir en parcourant le plan.
 */
.crm-editor-card.is-conditional { background: var(--crm-bg); }
.crm-editor-card.is-conditional .crm-editor-card-title { color: var(--crm-text-muted); }

.crm-editor-cond {
    flex: 0 0 auto;
    margin-right: .15rem;
    padding: 0;
    font-size: .75rem;
    color: var(--crm-info);
    background: none;
}

/* Un titre trop long est tronqué, comme dans le portail : sans cela « Informations contrat
   Holenek Consultants » passait sur deux lignes et sa carte devenait deux fois plus haute que
   ses voisines, ce qui fait lire une hiérarchie qui n'existe pas. */
.crm-editor-card-title,
.crm-editor-card-sub {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.crm-editor-card-name { max-width: 100%; }

/* Le compte de champs, à côté du titre de section : « 7 sur 18 » se lit sans compter les lignes. */
.crm-field-count {
    display: inline-block;
    min-width: 1.4rem;
    padding: 0 .3rem;
    font-size: .78rem;
    font-weight: 600;
    text-align: center;
    color: var(--crm-text);
    background: var(--crm-border-soft);
    border-radius: var(--crm-radius-sm);
}

/* =============================================================================================
 * Lignes de réglage : un champ, une action, une condition
 *
 * C'étaient des boîtes de 66 px de haut, bordées, posées sur un fond de la même couleur : quinze
 * champs faisaient un kilomètre de formulaire pour quinze listes déroulantes, et le bouton
 * d'enregistrement partait sous la ligne de flottaison. Serrées à hauteur de contrôle, les mêmes
 * quinze lignes tiennent dans un écran.
 * ============================================================================================= */

/* La liste ne défile plus pour son compte : la fenêtre s'en charge, et les boutons restent
   visibles parce qu'ils sont hors de la zone qui défile. Trois zones de défilement se disputaient
   la molette, et l'aperçu se coupait au milieu d'un champ. */
.crm-field-rows { margin-bottom: .75rem; }

/*
 * Une ligne de réglage tient en 32 px de contrôle.
 *
 * Elle en faisait 44 : le menu portait la hauteur d'un champ de formulaire, faite pour une
 * saisie au clavier, alors qu'on ne fait ici que choisir dans une liste. Six lignes coûtaient
 * donc 264 px, et la barre d'actions partait sous le bas de la fenêtre. Le reproche était
 * « des champs moins grands », et c'est exactement la même correction que celle déjà faite sur
 * les champs retenus par un bloc : serrer à hauteur de contrôle.
 *
 * La gouttière entre les lignes, elle, **augmente** : c'est ce qui distingue une liste de
 * lignes d'un pavé de bordures collées, et c'est l'autre moitié du reproche, « plus de marge ».
 */
.crm-field-row {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .15rem .3rem;
    margin-bottom: .4rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    transition: border-color var(--crm-ease), background var(--crm-ease);
}
.crm-field-row select.form-control-sm { height: 2rem; padding-top: 0; padding-bottom: 0; }
.crm-field-row:hover { border-color: var(--crm-slate-300, var(--crm-text-faint)); background: var(--crm-bg); }
.crm-field-row-control { flex: 1 1 auto; min-width: 0; }
.crm-field-row select { border-color: transparent; background-color: transparent; box-shadow: none; }
.crm-field-row:hover select,
.crm-field-row select:focus { border-color: var(--crm-border); background-color: var(--crm-surface); }

/*
 * Ligne de réglage d'un indicateur de tête de liste.
 *
 * Quatre réglages sur une seule ligne (nom, champ, opérateur, valeur) parce qu'un indicateur
 * se lit comme une phrase : « Jamais contacté = dernière activité est vide ». Empilés, les
 * quatre auraient fait une carte de 200 px, et six indicateurs un formulaire qu'on ne voit pas
 * en entier.
 *
 * Les largeurs sont données en `flex` et non en colonnes de grille : la cellule de valeur change
 * de contrôle selon l'opérateur (rien, un champ, un menu multiple) et une grille figée aurait
 * laissé un vide de la taille du plus grand des trois.
 */
.crm-indicator-row { flex-wrap: wrap; }
.crm-indicator-name { flex: 2 1 9rem; min-width: 0; }
.crm-indicator-field { flex: 2 1 8rem; min-width: 0; }
.crm-indicator-operator { flex: 1.6 1 7rem; min-width: 0; }
.crm-indicator-value { flex: 2 1 7rem; min-width: 0; }
.crm-indicator-row select,
.crm-indicator-row input[type="text"] { border-color: transparent; background-color: transparent; box-shadow: none; }
.crm-indicator-row:hover select,
.crm-indicator-row:hover input[type="text"],
.crm-indicator-row select:focus,
.crm-indicator-row input[type="text"]:focus { border-color: var(--crm-border); background-color: var(--crm-surface); }

/* La case d'affichage garde sa place quand la cellule de valeur disparaît : sans largeur fixe,
   décocher « est vide » faisait sauter la case d'une ligne à l'autre. */
.crm-indicator-active { flex: 0 0 1.4rem; text-align: center; }

/* Une ligne refusée se montre là où on la corrige, pas seulement en tête de formulaire. */
.crm-indicator-row-invalid { border-color: var(--crm-danger); }
.crm-indicator-error {
    margin: -.1rem 0 .35rem 1.5rem;
    font-size: .78rem;
    color: var(--crm-danger);
}

/*
 * L'aperçu du bandeau : en haut, sur toute la largeur, et collant.
 *
 * Placé en colonne comme celui d'un encart, il tombait dans 350 px : la grille du bandeau
 * (`minmax(11rem, 1fr)`) y retombait à une seule colonne et empilait les quatre compteurs à la
 * verticale. L'aperçu montrait alors une disposition que la liste n'affiche jamais : c'est-à-dire
 * exactement ce qu'un aperçu ne doit pas faire.
 *
 * Collant plutôt que fixe : il reste visible pendant qu'on règle la sixième ligne, sans occuper
 * la place quand on remonte. Le `z-index` le passe au-dessus des lignes qui défilent dessous,
 * mais reste sous la barre de navigation d'AdminLTE.
 */
.crm-indicator-preview {
    position: sticky;
    top: 0;
    z-index: 5;
}
.crm-indicator-preview .crm-insights { border-bottom: 0; }

/*
 * L'en-tête des colonnes de réglage.
 *
 * Quatre contrôles nus sur une ligne ne disent pas ce qu'ils règlent : on lisait « Sans e-mail /
 * E-mail / est vide » sans savoir que le premier était un nom libre. Les mêmes largeurs que les
 * lignes, d'où les classes partagées.
 */
.crm-indicator-head {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: 0 .35rem .25rem;
    /* Les deux marges alignent l'en-tête sur les contrôles : la poignée à gauche (1,5 rem) et la
       croix de retrait à droite (2 rem, gouttière comprise) ne portent pas d'en-tête. */
    margin: 0 2rem .25rem 1.5rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.crm-indicator-head + .crm-field-rows { margin-top: 0; }

/* =============================================================================================
 * Listes déroulantes cherchables
 *
 * Toute liste assez longue pour qu'on doive y chercher reçoit une boîte de recherche
 * (`enhanceSelects`). Le thème de Select2 rend une boîte à la taille d'un `form-control`, quelle
 * que soit la source : dans une rangée de filtres ou une ligne de réglage, où tout est en petit
 * format, elle dépassait ses voisines de huit pixels et cassait l'alignement de la rangée. Le
 * script pose donc `crm-select-sm` quand la liste d'origine portait `form-control-sm`.
 * ============================================================================================= */
/*
 * 2 rem, en dur, et non `calc(1.5em + .5rem + 2px)` comme le fait Bootstrap.
 *
 * L'`em` s'y résout sur la police de l'élément, que le thème de Select2 fixe de son côté : la
 * formule rendait 40 px là où le `form-control-sm` voisin en mesure 32. C'est cette mesure-là
 * qu'on vise, la hauteur réelle des listes natives de la même rangée, et l'écrire telle
 * quelle est plus honnête qu'une formule qui donne autre chose.
 */
/*
 * `!important` est ici obligatoire, et c'est la seule raison acceptable d'en écrire un : la
 * feuille du thème pose `height: calc(1.5em + 2px + .75rem) !important` sur cette même boîte.
 * Une règle plus spécifique n'y suffit pas : un `!important` ne se bat qu'avec un `!important`.
 */
.select2-container--bootstrap4.crm-select-sm { font-size: .875rem; }
.select2-container--bootstrap4.crm-select-sm .select2-selection--single {
    height: 2rem !important;
    min-height: 2rem;
}
.select2-container--bootstrap4.crm-select-sm .select2-selection--single .select2-selection__rendered {
    padding-left: .5rem;
    line-height: calc(2rem - 2px);
}
.select2-container--bootstrap4.crm-select-sm .select2-selection--single .select2-selection__arrow {
    height: calc(2rem - 2px);
}
.select2-container--bootstrap4.crm-select-sm .select2-selection--multiple { min-height: 2rem; }

/*
 * La liste déroulante elle-même passe **au-dessus** d'une fenêtre.
 *
 * Elle est accrochée à la fenêtre quand il y en a une, sinon, posée sur le `<body>` en position
 * absolue, elle se décalait dès que la page défilait derrière une fenêtre, qui est en position
 * fixe. Restait à ce qu'elle ne passe pas sous la barre d'envoi collante.
 */
.select2-container--open { z-index: 1100; }

/* Poignée commune aux trois sortes de lignes : discrète, mais elle dit qu'on peut déplacer. */
.crm-row-grip {
    flex: 0 0 auto;
    padding: 0 .1rem;
    color: var(--crm-text-faint);
    cursor: grab;
}
.crm-row-grip:active { cursor: grabbing; }

/*
 * La croix ne rougit qu'au survol.
 *
 * Une corbeille rouge par ligne faisait quinze taches rouges dans un formulaire où l'on ne
 * supprime presque rien : le regard allait au danger, pas au contenu.
 */
.crm-row-remove {
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    font-size: .8rem;
    color: var(--crm-text-faint);
    background: none;
    border: 0;
    border-radius: var(--crm-radius-sm);
}
.crm-row-remove:hover { color: var(--crm-danger); background: var(--crm-danger-soft); }

/* Une rangée d'action garde son libellé et son liseré : elle porte un réglage, pas un choix
   dans une liste de quinze. */
.crm-card-action-row { padding: .4rem .5rem; margin-bottom: .35rem; align-items: center; }
.crm-card-action-row label { margin-bottom: .15rem; }

/*
 * L'aperçu reste en vis-à-vis de ce qu'on règle.
 *
 * `sticky` dans la zone qui défile : on fait glisser la liste des champs et la carte reste sous
 * les yeux. Sans lui, régler le dixième champ d'un bloc se faisait sans plus rien voir du
 * résultat, et il ne défile pas pour son compte, deux zones de défilement côte à côte rendant la
 * molette imprévisible.
 */
.crm-card-config-preview { align-self: start; position: sticky; top: 0; }

/* Une ligne d'encart livré : le nom en lien, puis les colonnes choisies en paires libellé-valeur.
   Les trois encarts affichaient chacun sa propre mise en forme (titre, ligne grise, pastille)
   et rien ne pouvait s'y ajouter sans toucher au gabarit. */
.crm-object-row { padding: .3rem 0; border-bottom: 1px solid var(--crm-border-soft); }
.crm-object-row:last-of-type { border-bottom: 0; }
/* Le nom tient sur une ligne : « Aperçu Sonde visuelle, Développeur Java » en prenait deux dans
   une colonne de 235 px, et la ligne devenait plus haute que ses trois champs réunis. */
.crm-object-row-name {
    display: block;
    font-size: .85rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.crm-object-row-fields { margin-top: .1rem; }

/*
 * Libellé et valeur sur la même ligne, tous deux tronqués.
 *
 * Empilés, ils donnaient six lignes de texte par objet dans une colonne de 235 px : trois
 * positionnements faisaient une carte de 736 px, là où l'encart écrit à la main en tenait trois
 * en 150. Une ligne par colonne affichée, et l'encart redevient parcourable.
 */
.crm-object-field {
    display: flex;
    align-items: baseline;
    gap: .35rem;
    font-size: .75rem;
    line-height: 1.35;
}
.crm-object-field-label {
    flex: 0 0 auto;
    max-width: 45%;
    color: var(--crm-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.crm-object-field-value {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* La valeur est rendue par le gabarit de la fiche : il faut lui retirer sa hauteur de cible de
   clic, qui n'a pas de sens ici puisque l'encart n'édite pas. */
.crm-object-field-value .crm-block-value,
.crm-object-field-value .crm-editable {
    display: inline;
    padding: 0;
    min-height: 0;
    font-size: inherit;
}

/* =============================================================================================
 * Valeurs longues dans un encart
 *
 * Une étiquette de liste à choix multiples est un `badge` Bootstrap, donc `white-space: nowrap` :
 * une compétence de soixante caractères sortait de la carte par la droite. Elles passent
 * maintenant à la ligne, et une chaîne sans espace (une URL, une référence) se coupe plutôt que
 * de pousser la carte.
 * ============================================================================================= */

.crm-block-value .badge,
.crm-block-value .crm-option-badge,
.crm-object-field-value .badge {
    white-space: normal;
    text-align: left;
    max-width: 100%;
    overflow-wrap: anywhere;
}

/* Les étiquettes d'une même valeur respirent quand elles passent à la ligne : collées, deux
   lignes d'étiquettes se lisaient comme une seule phrase. */
.crm-block-value { overflow-wrap: anywhere; }
.crm-block-value .badge { margin-bottom: .15rem; }
/* La portée des compteurs, dite à l'écran : ils comptaient le module entier alors que la liste
   était filtrée, et rien ne permettait de s'en apercevoir. */
.crm-insights-scope {
    align-self: center;
    padding: 0 .75rem;
    font-size: .72rem;
    font-style: italic;
    color: var(--crm-text-muted);
}

/* ==========================================================================
   Grille des droits (/admin/droits)
   ========================================================================== */

/*
   Une trentaine de fonctionnalités, quatre listes déroulantes chacune : la grille tient
   dans un écran seulement si ses lignes sont serrées à hauteur de contrôle. La leçon vient
   des champs retenus par un bloc de fiche, où quinze lignes en boîtes de 66 px faisaient un
   kilomètre de formulaire et envoyaient le bouton d'enregistrement sous la ligne de
   flottaison. Ici il y en aurait eu trente.
*/
.crm-permission-grid td,
.crm-permission-grid th {
    padding: .4rem .5rem;
    vertical-align: middle;
}

/* La colonne des libellés porte deux lignes (nom et aide) : elle seule s'aligne en haut. */
.crm-permission-grid td:first-child {
    vertical-align: top;
    padding-top: .55rem;
}

.crm-permission-grid select {
    width: 100%;
}

/*
   Un droit réglable dont aucun écran ne demande encore la permission. Estompé et non
   désactivé : le réglage s'enregistre pour de bon, et le jour où l'écran arrive il agit
   sans qu'on ait à repasser. Un contrôle grisé aurait dit le contraire, « inutile d'y
   toucher », alors que c'est justement ce qu'on veut avoir réglé d'avance.
*/
.crm-permission-grid select.crm-scope-pending {
    border-style: dashed;
    color: var(--crm-text-muted);
}

/* ---- Bulle d'explication (templates/_info_bubble.html.twig) ----
   En CSS pur : le CRM n'initialise pas les infobulles Bootstrap, et un composant monté au
   chargement de la page ne le serait jamais dans une fenêtre injectée. Le texte s'ouvre au
   survol **et** à la mise au point, sans quoi elle serait inatteignable au clavier. */
.crm-bulle {
    position: relative;
    display: inline-block;
    margin-left: .25rem;
    color: var(--crm-text-muted, #6c757d);
    cursor: help;
    line-height: 1;
}
.crm-bulle:hover, .crm-bulle:focus { color: var(--crm-primary, #4c6ef5); outline: none; }
.crm-bulle-texte {
    position: absolute;
    z-index: 1080;
    left: 50%;
    bottom: calc(100% + .5rem);
    transform: translateX(-50%);
    width: 22rem;
    max-width: 70vw;
    padding: .625rem .75rem;
    background: #212529;
    color: #f8f9fa;
    border-radius: var(--crm-radius, 8px);
    box-shadow: 0 6px 18px rgba(16, 24, 40, .28);
    font-size: .75rem;
    font-weight: 400;
    line-height: 1.45;
    text-align: left;
    white-space: normal;
    /* `visibility` en plus de l'opacité : sans elle, la bulle reste cliquable et attrape le
       survol de ce qui est dessous, y compris quand elle est invisible. */
    visibility: hidden;
    opacity: 0;
    transition: opacity .12s ease;
    pointer-events: none;
}
.crm-bulle:hover .crm-bulle-texte,
.crm-bulle:focus .crm-bulle-texte { visibility: visible; opacity: 1; }
.crm-bulle-p { display: block; }
.crm-bulle-p + .crm-bulle-p { margin-top: .5rem; }
/* Près du bord droit, la bulle centrée sortirait de l'écran : la classe la cale à droite. */
.crm-bulle.is-right .crm-bulle-texte { left: auto; right: 0; transform: none; }

/* La case « réponse obligatoire » du panneau de réglage : une ligne, pas un champ empilé. */
.crm-doc-field-editor .crm-doc-fe-check {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-weight: 400;
    margin: 0 0 8px;
}
.crm-doc-field-editor .crm-doc-fe-check input { width: auto; margin: 0; }
.crm-doc-field-editor select {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid #cfd6e0;
    border-radius: 6px;
    padding: 4px 7px;
    font-size: 12px;
    margin-bottom: 8px;
}

/* Les lignes d'options d'un bouton radio ou d'une liste, dans le panneau de réglage : une
   ligne par choix, à hauteur de contrôle, la croix grise et rouge au survol seulement. */
.crm-doc-fe-option { display: flex; align-items: center; gap: .3rem; margin-bottom: .3rem; }
.crm-doc-fe-option input { margin: 0 !important; }
.crm-doc-fe-option-del {
    border: 0;
    background: none;
    color: var(--crm-text-muted, #adb5bd);
    font-size: 15px;
    line-height: 1;
    padding: 0 .25rem;
    cursor: pointer;
}
.crm-doc-fe-option-del:hover { color: var(--crm-danger, #dc3545); }
.crm-doc-fe-add {
    border: 1px dashed #cfd6e0;
    background: none;
    border-radius: 6px;
    width: 100%;
    padding: .25rem 0;
    font-size: 11.5px;
    color: var(--crm-text-muted, #6c757d);
    cursor: pointer;
    margin-bottom: 8px;
}
.crm-doc-fe-add:hover { border-color: var(--crm-primary, #4c6ef5); color: var(--crm-primary, #4c6ef5); }
/* Le panneau grandit avec ses réglages : au-delà, il défile plutôt que de sortir de l'écran. */
.crm-doc-field-editor { max-height: 26rem; overflow-y: auto; }

/* Le bouton d'insertion de PDF, dans une gouttière de page et à la fin du document : discret
   au repos, il ne doit pas concurrencer le contenu, et se signale au survol de la zone. */
/*
 * Deux boutons par gouttière : une page vide, un PDF. Ils partagent tout leur dessin, un
 * second jeu de règles aurait divergé au premier réglage. Le PDF garde le bord droit, la
 * page vide se pose à sa gauche : l'ordre suit celui du menu Insérer.
 */
.crm-doc-gutter-pdf, .crm-doc-gutter-page, .crm-doc-tail button {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    border: 1px solid var(--crm-border, #dee2e6);
    background: var(--crm-surface, #fff);
    color: var(--crm-text-muted, #6c757d);
    border-radius: var(--crm-radius, 8px);
    width: 26px;
    height: 26px;
    line-height: 1;
    font-size: 12px;
    cursor: pointer;
    opacity: .45;
    transition: opacity .12s ease;
    pointer-events: auto;
}
.crm-doc-gutter-page,
.crm-doc-tail .crm-doc-gutter-page { right: 32px; }

.crm-doc-gutter:hover .crm-doc-gutter-pdf,
.crm-doc-gutter:hover .crm-doc-gutter-page,
.crm-doc-tail:hover button { opacity: 1; }
.crm-doc-gutter-pdf:hover, .crm-doc-gutter-page:hover, .crm-doc-tail button:hover {
    border-color: var(--crm-primary, #4c6ef5);
    color: var(--crm-primary, #4c6ef5);
}
/* La bande de fin : elle n'a pas de fond, seul son bouton se voit. */
.crm-doc-tail { position: absolute; height: 26px; pointer-events: none; }

/* Le repère d'insertion pendant qu'on glisse un jeton : un trait fin à l'endroit exact où il
   se posera. Sans lui, on lâche à l'aveugle et on découvre la position après coup. */
.crm-doc-caret-mark {
    position: fixed;
    z-index: 1090;
    width: 2px;
    background: var(--crm-primary, #4c6ef5);
    pointer-events: none;
    display: none;
}
/* La palette de jetons dit qu'elle se prend, comme les pastilles de champ. */
[data-crm-doc-token] { cursor: grab; }
[data-crm-doc-token]:active { cursor: grabbing; }

/* ------------------------------------------------ Ajouter un rôle, sur place */

/* Une ligne de saisie posée dans le rail, à la place de l'invite du navigateur : même largeur,
   même vocabulaire, même couleur que le reste de l'écran. */
.crm-doc-role-new {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin-top: .5rem;
}

.crm-doc-role-new input {
    flex: 1 1 auto;
    min-width: 0;
}

.crm-doc-role-new .btn {
    flex: 0 0 auto;
    padding-left: .5rem;
    padding-right: .5rem;
}

/* ------------------------------------------------ Comparaison de deux versions */

.crm-doc-diff-pick {
    display: flex;
    align-items: flex-end;
    gap: .6rem;
    flex-wrap: wrap;
    padding-bottom: .85rem;
    border-bottom: 1px solid var(--crm-border);
}

.crm-doc-diff-pick .form-group {
    flex: 1 1 16rem;
    min-width: 0;
}

.crm-doc-diff-pick label {
    display: block;
    margin-bottom: .2rem;
    font-size: .78rem;
    color: var(--crm-text-muted);
}

.crm-doc-diff-arrow {
    padding-bottom: .55rem;
    color: var(--crm-text-faint);
}

.crm-doc-diff-sum {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin: .85rem 0;
}

.crm-doc-diff-tag {
    padding: .15rem .5rem;
    border-radius: var(--crm-radius-sm);
    font-size: .78rem;
    font-weight: 600;
}

.crm-doc-diff-tag.is-modif   { background: var(--crm-warning-soft); color: var(--crm-warning); }
.crm-doc-diff-tag.is-ajout   { background: var(--crm-success-soft); color: var(--crm-success); }
.crm-doc-diff-tag.is-retrait { background: var(--crm-danger-soft);  color: var(--crm-danger); }
.crm-doc-diff-tag.is-egal    { background: var(--crm-slate-100);    color: var(--crm-text-muted); }

.crm-doc-diff-none {
    color: var(--crm-text-muted);
    font-size: .85rem;
}

.crm-doc-diff-head {
    margin-bottom: .85rem;
    padding: .5rem .65rem;
    background: var(--crm-slate-50);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
}

.crm-doc-diff-headline {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .35rem;
    font-size: .85rem;
}

.crm-doc-diff-headline + .crm-doc-diff-headline {
    margin-top: .3rem;
}

.crm-doc-diff-headfield {
    min-width: 8rem;
    color: var(--crm-text-muted);
}

/* Le texte comparé porte la typographie du document, pas celle du CRM : c'est un contrat qu'on
   relit, et le lire dans une autre police que celle du PDF fait douter de ce qu'on voit. */
.crm-doc-diff {
    max-height: 60vh;
    overflow-y: auto;
    padding: .5rem .75rem;
    background: var(--crm-surface);
    border: 1px solid var(--crm-border);
    border-radius: var(--crm-radius);
    font-family: "Times New Roman", Times, serif;
    font-size: 15px;
    line-height: 1.35;
}

.crm-doc-diff-line {
    padding: .2rem .4rem;
    border-left: 3px solid transparent;
}

.crm-doc-diff-line.is-egal    { color: var(--crm-text-muted); }
.crm-doc-diff-line.is-modif   { border-left-color: var(--crm-warning); background: rgba(150, 96, 26, .04); }
.crm-doc-diff-line.is-ajout   { border-left-color: var(--crm-success); background: rgba(18, 133, 95, .05); }
.crm-doc-diff-line.is-retrait { border-left-color: var(--crm-danger);  background: rgba(207, 48, 64, .04); }

.crm-doc-diff-ins {
    background: var(--crm-success-soft);
    color: var(--crm-success);
    text-decoration: none;
    border-radius: var(--crm-radius-sm);
    padding: 0 .12rem;
}

.crm-doc-diff-del {
    background: var(--crm-danger-soft);
    color: var(--crm-danger);
    text-decoration: line-through;
    border-radius: var(--crm-radius-sm);
    padding: 0 .12rem;
}

/* Ce qui n'est pas montré est dit : un passage identique se compte, il ne disparaît pas. */
.crm-doc-diff-skip {
    margin: .3rem 0;
    padding: .15rem .4rem;
    font-family: var(--crm-font);
    font-size: .75rem;
    color: var(--crm-text-faint);
    text-align: center;
    border-top: 1px dashed var(--crm-border);
    border-bottom: 1px dashed var(--crm-border);
}
