:root {
    --grad: linear-gradient(90deg, #C6187A, #F2811F, #F5C518, #14B8C6, #17171B);
    --ink: #17171B;
    --muted: #65656E;
    --border: #E3E3E7;
    --bg: #F5F5F7;
    --card: #ffffff;
    --danger: #d92d20;
    --success: #067647;
    --accent: #C6187A;
    --accent-dark: #9c1362;
    --font-body: 'Inter', -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-title: 'Space Grotesk', -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: var(--font-body);
    font-weight: 400;
    background: var(--bg);
    color: var(--ink);
}

h1, .app-name { font-family: var(--font-title); font-weight: 600; }

/* Numéros de téléphone : un clic COPIE le numéro dans le presse-papier
   (kvbCopyPhone, base.html) — plus aucun lien tel:/appel direct. Le bouton
   ressemble à du texte normal (pas de chrome de bouton) ; retour visuel
   « Copié ✓ » transitoire via .tel-copied. */
.tel-copy-btn {
    background: none; border: 0; padding: 0; margin: 0; font: inherit;
    color: inherit; text-align: left; cursor: pointer;
}
.tel-copy-btn:hover { text-decoration: underline; }
.tel-copy-btn.tel-copied { color: var(--accent); font-weight: 600; text-decoration: none; cursor: default; }
.tel-field-row { display: flex; align-items: center; gap: 6px; }
.tel-field-row input { flex: 1; min-width: 0; }

/* Date de RDV + Heure de RDV (chantier 2026-09-16) : deux champs côte à
   côte sous un seul libellé, comme .tel-field-row. */
.rdv-field-row { display: flex; align-items: center; gap: 6px; }
.rdv-field-row input[type="date"] { flex: 1.4; min-width: 0; }
.rdv-field-row input[type="time"] { flex: 1; min-width: 0; }

/* Heure de RDV (chantier 2026-09-16) affichée à côté de la date, dans les
   tableaux (/, /relances, bloc "RDV à venir" de /suivi). */
.heure-rdv { color: var(--muted); }
/* Variante « bouton encadré » (fiche prospect, à côté du champ Téléphone). */
.tel-copy-icon-btn {
    flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
    min-width: 36px; height: 36px; padding: 0 8px; border: 1px solid var(--border);
    border-radius: 8px; font-size: 1rem; background: white; cursor: pointer; font-family: inherit;
}
.tel-copy-icon-btn:hover { background: #fbe4ef; border-color: var(--accent); }
.tel-copy-icon-btn.tel-copied { color: var(--accent); border-color: var(--accent); font-size: 0.8rem; }

/* Les <input type="date"> ne suivent pas `font-family` par héritage dans
   les navigateurs (police de formulaire par défaut du système, ex. Arial
   ou monospace) : on la force explicitement partout sur le site (panneau
   Filtres avancés, popover de relance, formulaire prospect). */
input[type="date"] { font-family: var(--font-body); }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 24px;
    background: var(--card);
    border-bottom: 3px solid transparent;
    border-image: var(--grad) 1;
    flex-wrap: wrap;
    gap: 12px;
}
/* Logo + nom de l'appli : lien vers la page d'accueil (/suivi). */
.topbar-left { display: flex; align-items: center; gap: 10px; text-decoration: none; color: inherit; }
.topbar-left:hover { text-decoration: none; }
.logo { height: 36px; width: 36px; border-radius: 50%; }
.app-name { font-size: 1.05rem; }
.topbar-nav { display: flex; align-items: center; gap: 18px; }
.topbar-nav a {
    color: var(--ink);
    font-weight: 600;
    padding-bottom: 8px;
    position: relative;
}
.topbar-nav a.active::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    border-radius: 2px;
    background: var(--grad);
}
.topbar-right { display: flex; align-items: center; gap: 14px; font-size: 0.9rem; color: var(--muted); }

/* Bouton burger (chantier J, 2026-09-04) : masqué en desktop, la nav reste
   la ligne .topbar-nav ci-dessus, inchangée. */
.topbar-burger {
    display: none;
    background: none; border: none; cursor: pointer; padding: 6px;
    border-radius: 8px; color: var(--ink); line-height: 0;
}
.topbar-burger:hover { background: var(--bg); }
@media (max-width: 767px) {
    .topbar { position: relative; }
    .topbar-burger { display: inline-flex; align-items: center; justify-content: center; }
    /* Panneau déroulant sous la barre, même largeur, même carte que le
       menu compte (.account-menu) pour rester cohérent visuellement.
       Cadré .open (comme .account-menu.open) plutôt qu'un style inline. */
    .topbar-nav {
        display: none;
        position: absolute; top: 100%; left: 12px; right: 12px; z-index: 30;
        flex-direction: column; align-items: stretch; gap: 0;
        background: var(--card); border: 1px solid var(--border); border-radius: 10px;
        margin-top: 8px; padding: 6px;
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    }
    .topbar-nav.open { display: flex; }
    .topbar-nav a {
        padding: 12px 10px; border-radius: 8px;
    }
    .topbar-nav a:hover { background: var(--bg); text-decoration: none; }
    /* Le soulignement en dégradé (::after, positionné pour la ligne
       horizontale desktop) n'a pas de sens dans une liste verticale :
       l'entrée active est plutôt signalée par un fond, comme les entrées
       de .account-menu. */
    .topbar-nav a.active::after { display: none; }
    .topbar-nav a.active { background: #fbe4ef; color: var(--accent); }
}
.role-badge { padding: 2px 8px; border-radius: 999px; font-size: 0.75rem; text-transform: uppercase; font-weight: 700; }
.role-admin { background: #fbe4ef; color: var(--accent); }
.role-user { background: #e1f6f8; color: #0e7c8c; }

/* Menu déroulant du compte (topbar, en haut à droite) */
.account-menu-wrap { position: relative; }
.account-menu-trigger {
    background: none; border: none; cursor: pointer; font: inherit; color: var(--muted);
    display: flex; align-items: center; gap: 6px; padding: 4px 2px;
}
.account-menu {
    display: none; position: absolute; top: 100%; right: 0; z-index: 30; margin-top: 8px;
    min-width: 170px; background: var(--card); border: 1px solid var(--border); border-radius: 10px;
    padding: 6px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.account-menu.open { display: block; }
.account-menu a {
    display: block; padding: 8px 10px; border-radius: 6px; color: var(--ink);
    font-size: 0.88rem; font-weight: 500; text-decoration: none;
}
.account-menu a:hover { background: var(--bg); text-decoration: none; }

/* Plus de plafond global (cf. décision Mehdi 2026-08-31) : le tableau
   Prospects, la carte et les filtres utilisent toute la largeur de
   l'écran. Les pages « formulaire » (fiche prospect, admin, mon compte,
   login…) posent leur propre plafond local plus bas pour ne pas s'étirer
   sur un grand moniteur. */
.content { margin: 0 auto; padding: 24px; }

.dashboard-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; flex-wrap: wrap; gap: 10px; }
.actions { display: flex; gap: 10px; }

.btn-primary, .btn-secondary, .btn-danger, .btn-link {
    display: inline-block;
    padding: 9px 16px;
    border-radius: 8px;
    font-weight: 600;
    font-size: 0.9rem;
    border: none;
    cursor: pointer;
}
.btn-primary { background: var(--accent); color: white; }
.btn-primary:hover { background: var(--accent-dark); text-decoration: none; }
.btn-secondary { background: white; color: var(--ink); border: 1px solid var(--border); }
.btn-danger { background: white; color: var(--danger); border: 1px solid var(--danger); }
.btn-link { background: none; color: var(--muted); padding: 9px 6px; }

/* Le formulaire de filtres prend toute la largeur ; le bouton « Colonnes ▾ »
   est posé en absolu dans le coin haut-droit. Avant, il était un frère
   flex du formulaire : il réservait une bande verticale d'environ 147px
   sur toute la hauteur de la barre, ce qui empêchait le panneau de
   filtres avancés déplié d'utiliser toute la largeur (retour Mehdi
   2026-08-31). Seule la ligne de recherche garde une réserve à droite
   pour ne pas passer sous le bouton. */
.filter-toolbar { position: relative; margin-bottom: 18px; }
.filter-toolbar .filter-bar { min-width: 0; margin-bottom: 0; }
.filter-toolbar .column-selector-wrap { position: absolute; top: 0; right: 0; }
.filter-toolbar .filter-search-row { padding-right: 150px; }
@media (max-width: 767px) {
    /* le bouton « Colonnes ▾ » repasse dans le flux, sous la barre de
       recherche (pas la place de le poser en absolu), au lieu de
       comprimer le formulaire à ~moitié de largeur. */
    .filter-toolbar .column-selector-wrap { position: relative; margin-top: 10px; }
    .filter-toolbar .filter-search-row { padding-right: 0; }
}

.filter-bar { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 16px; margin-bottom: 18px; }

/* Sélecteur de colonnes (page Prospects) : bouton + menu à cocher, hors du
   <form> de filtres (cf. commentaire dans dashboard.html). */
.column-selector-wrap { position: relative; flex-shrink: 0; }
.column-menu {
    display: none; position: absolute; top: 100%; right: 0; z-index: 20; margin-top: 6px;
    width: 260px; max-height: 360px; overflow-y: auto;
    background: var(--card); border: 1px solid var(--border); border-radius: 10px;
    padding: 10px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.column-menu.open { display: block; }
.column-menu-item { display: flex; align-items: center; gap: 8px; padding: 5px 4px; font-size: 0.85rem; cursor: pointer; }
.column-menu-item input { margin: 0; }

/* Cellules Commentaire / Nouveau commentaire : tronquées pour ne pas
   distendre les lignes du tableau, texte complet visible au survol via le
   title. 260 -> 400px (chantier J, 2026-09-04) : à 260px la colonne
   coupait le texte bien avant les 160 caractères déjà tronqués côté
   serveur (row.html) — le tableau défile déjà horizontalement au besoin
   (.table-scroll), l'élargir ne casse rien. */
.cell-truncate { max-width: 400px; overflow: hidden; text-overflow: ellipsis; }

.filter-search-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.filter-main-wrap { position: relative; flex: 1; min-width: 220px; }
.filter-main-input { width: 100%; padding: 9px 32px 9px 12px; border: 1px solid var(--border); border-radius: 8px; font-size: 0.9rem; font-family: inherit; }
.filter-main-clear {
    position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
    background: none; border: none; color: var(--muted); cursor: pointer;
    font-size: 0.85rem; padding: 4px; line-height: 1;
}
.filter-main-clear:hover { color: var(--ink); }

.filter-chips { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 12px; }
.filter-chip {
    display: inline-flex; align-items: center; gap: 6px;
    background: #fbe4ef; color: var(--accent-dark);
    border-radius: 999px; padding: 4px 6px 4px 12px;
    font-size: 0.8rem; font-weight: 500;
}
.filter-chip strong { font-weight: 600; }
.filter-chip-remove {
    background: none; border: none; cursor: pointer; color: inherit;
    font-size: 0.7rem; width: 18px; height: 18px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center; padding: 0;
}
.filter-chip-remove:hover { background: rgba(0, 0, 0, 0.08); }

.filter-advanced { display: none; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.filter-advanced.open { display: block; }
/* 3 lignes explicites (cf. retour des 2026-08-31 / 09-01) au lieu d'une
   grille auto-fill : chaque .filter-row répartit toute la largeur du
   panneau entre SES champs, donc aucune ligne ne laisse de vide à droite,
   quel que soit son nombre de champs.
   IMPORTANT : `flex: 1 1 0%` (base en %) et NON `flex: 1 1 0` — la valeur
   unitless 0 comme flex-basis n'est pas honorée par tous les moteurs
   (certains Safari / anciens Chromium la rejettent et retombent sur
   `flex: 0 1 auto`, ce qui redimensionne alors chaque champ sur son
   contenu : les <input> gardent leur largeur `size` par défaut, le
   <select> Statut se réduit à son plus long libellé -> vide à droite +
   Statut visiblement plus étroit. Le `%` corrige les deux d'un coup). */
.filter-grid { display: flex; flex-direction: column; gap: 12px; }
.filter-row { display: flex; gap: 12px; }
.filter-row > .filter-field { flex: 1 1 0%; min-width: 0; }
/* Les plages de dates (label + 2 <input type="date"> + flèche) ont besoin
   d'environ 2x la largeur d'un champ simple pour ne pas tronquer
   "jj/mm/aaaa". */
.filter-row > .filter-date { flex: 2 1 0%; }
@media (max-width: 767px) {
    /* mobile : empilement vertical, un champ par ligne (comme avant). */
    .filter-row { flex-direction: column; }
}
.filter-field { display: flex; flex-direction: column; min-width: 0; font-size: 0.78rem; color: var(--muted); font-weight: 600; gap: 4px; }
/* <select> (filtre Statut) : width:100% + min-width:0 -> occupe toute la
   part de largeur que flex alloue à son .filter-field, exactement comme un
   <input>. box-sizing déjà border-box (cf. `*`). */
.filter-field input, .filter-field select { width: 100%; min-width: 0; padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; font-family: inherit; }
.filter-date .date-range { display: flex; align-items: center; gap: 6px; }
.filter-date .date-range input { flex: 1 1 0%; }

.results-meta { color: var(--muted); font-size: 0.85rem; margin-bottom: 8px; }
/* Barre de défilement horizontal jumelle en haut du tableau (synchronisée
   avec celle du bas, cf. script dans partials/table.html) : visible et
   utilisable sans avoir à scroller toute la page jusqu'en bas quand
   beaucoup de colonnes sont sélectionnées. */
.table-scroll-top { overflow-x: auto; overflow-y: hidden; height: 14px; margin-bottom: 6px; }
.table-scroll-top-inner { height: 1px; }

.table-scroll { overflow-x: auto; background: var(--card); border: 1px solid var(--border); border-radius: 12px; }
.prospect-table { width: 100%; border-collapse: collapse; font-size: 0.83rem; }
.prospect-table th, .prospect-table td { padding: 5px 10px; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
.prospect-table th { background: #fafafa; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em; font-weight: 700; color: var(--muted); padding-top: 7px; padding-bottom: 7px; }
.prospect-table th.sortable-th { padding: 0; }
.prospect-table th.sortable-th .sort-link {
    display: block; padding: 7px 10px 7px 10px;
    color: inherit; font: inherit; text-transform: inherit; letter-spacing: inherit;
    text-decoration: none; cursor: pointer; user-select: none;
}
.prospect-table th.sortable-th .sort-link:hover { color: var(--ink); background: #f0f0f0; }
.prospect-table th.sortable-th.sorted .sort-link { color: var(--accent-dark); }
.prospect-table .sort-arrow { display: inline-block; width: 0.9em; font-size: 0.85em; }

/* Colonnes redimensionnables à la souris (chantier J, 2026-09-04), portée
   à .resizable-table uniquement (posée par partials/table.html -> / et
   /relances seulement, jamais les tableaux d'admin qui réutilisent la
   classe .prospect-table pour le seul style, sans ce comportement).
   table-layout:fixed : la largeur de chaque <col> (posée en JS, cf.
   script en bas de partials/table.html) gouverne la colonne entière.
   overflow:hidden + ellipsis généralisé à toutes les cellules (avant :
   seul .cell-truncate/Commentaire l'avait) -> une colonne rétrécie
   tronque proprement au lieu de déborder sur sa voisine ; exclue de
   .date-rappel-cell, qui héberge un popover (.relance-popover) devant
   pouvoir déborder de la cellule pour s'afficher. */
.resizable-table { table-layout: fixed; }
/* Colonnes non redimensionnables (case à cocher, action "Modifier") :
   largeur de repli raisonnable, cohérente avec .select-all-page-cell/
   .col-checkbox (56px, chantier A) qui la resserre encore davantage
   >=1024px via une règle plus spécifique -> pas de conflit. */
.resizable-table .col-checkbox-col { width: 56px; }
.resizable-table .col-actions-col { width: 90px; }
.resizable-table td:not(.date-rappel-cell) { overflow: hidden; text-overflow: ellipsis; }
.resizable-table th { position: relative; }
.col-resize-handle {
    /* right:0 (jamais négatif) : chaque <th> est déjà position:sticky avec
       son propre contexte d'empilement (chantier A, A1) -> une poignée qui
       déborderait ne serait-ce que de quelques px À L'EXTÉRIEUR de son
       <th> se retrouverait sous le <th> suivant (contexte d'empilement
       distinct, plus tardif dans le DOM = peint par-dessus), donc
       impossible à cliquer. Restée STRICTEMENT à l'intérieur -> fiable. */
    position: absolute; top: 0; right: 0; bottom: 0; width: 8px;
    cursor: col-resize; z-index: 4; touch-action: none;
}
.col-resize-handle:hover, .col-resize-handle.resizing { background: rgba(198, 24, 122, .25); }
/* Pendant le glisser : verrouille le curseur col-resize même si la souris
   sort momentanément de la poignée (déplacement rapide), et désactive la
   sélection de texte parasite sur toute la page. */
body.kvb-col-resizing { cursor: col-resize !important; user-select: none; }
body.kvb-col-resizing * { cursor: col-resize !important; }
/* Sous 768px la table desktop entière est masquée (.desktop-table-view,
   cf. plus bas) -> les poignées n'ont jamais besoin d'être visibles ni
   interactives là ; règle de repli explicite si jamais réutilisé ailleurs. */
@media (max-width: 767px) {
    .col-resize-handle { display: none; }
}
.prospect-table tbody tr:hover { background: #F5F5F7; }
/* Ligne / carte cliquable (ouvre la fiche, cf. kvbRowClickBound base.html). */
.prospect-table tbody tr[data-row-href], .prospect-card[data-row-href] { cursor: pointer; }
.prospect-table .empty { text-align: center; color: var(--muted); padding: 30px; }
.row-actions { display: flex; gap: 12px; align-items: center; }
.row-actions a { font-weight: 600; }
.row-actions form { margin: 0; }
/* Cellule à action unique (lien "Modifier" seul) : on évite display:flex sur
   le <td> pour un alignement vertical fiable — mélanger le modèle flex et le
   modèle de layout des tables peut désynchroniser la hauteur calculée de la
   ligne selon les navigateurs, ce qui décale visuellement le lien. */
.row-actions--single { display: table-cell; vertical-align: middle; }

/* Colonne "Modifier" figée à droite du tableau Prospects (uniquement,
   cf. .row-actions--single/.row-actions-th, jamais ajoutées aux pages
   admin qui réutilisent .prospect-table) : reste visible même après un
   défilement horizontal complet, quand beaucoup de colonnes sont
   cochées. Fond opaque obligatoire (var(--card)/#fafafa, pas
   transparent) pour ne pas superposer illisiblement le texte des
   colonnes qui défilent en dessous ; ombre portée à gauche pour
   distinguer visuellement la limite figée du reste du tableau.
   tr:hover doit reprendre la même couleur de survol sur cette cellule,
   sinon elle resterait blanche alors que le reste de la ligne surligne. */
.row-actions--single, .row-actions-th {
    position: sticky;
    right: 0;
    box-shadow: -6px 0 8px -6px rgba(0, 0, 0, 0.18);
}
.row-actions--single { background: var(--card); }
.row-actions-th { background: #fafafa; }
.prospect-table tbody tr:hover .row-actions--single { background: #F5F5F7; }

.badge-annotation { padding: 2px 10px; border-radius: 6px; font-size: 0.78rem; font-weight: 600; white-space: nowrap; }
.badge-overdue { background: #fde2e1; color: #b42318; }
.badge-today { background: #fde3cb; color: #a85610; }

/* Pastille du statut commercial (chantier D, 2026-08-30). Même gabarit que
   .badge-annotation ; une couleur par valeur de crud.STATUT_VALUES. Aucune
   dépendance, juste des fonds/textes fixes. */
.badge-statut { padding: 2px 10px; border-radius: 6px; font-size: 0.78rem; font-weight: 600; white-space: nowrap; }
.badge-statut-prospect { background: #ececf1; color: #45454f; }
.badge-statut-rdv { background: #e0edff; color: #1d4ed8; }
.badge-statut-nego { background: #fef0c7; color: #92600a; }
.badge-statut-client { background: #d1fae5; color: #067647; }
.badge-statut-perdu { background: #fee2e2; color: #b42318; }
/* Chantier I (2026-09-04) : R1/R2/R3 = un dégradé de violet (progression de
   relance) ; « À suivre » = teal, distinct des 5 précédents. Mêmes pastels
   Tailwind que l'existant. */
.badge-statut-r1 { background: #ede9fe; color: #6d28d9; }
.badge-statut-r2 { background: #ddd6fe; color: #5b21b6; }
.badge-statut-r3 { background: #c4b5fd; color: #4c1d95; }
.badge-statut-asuivre { background: #ccfbf1; color: #0f766e; }

.pagination { display: flex; align-items: center; gap: 10px; margin-top: 14px; flex-wrap: wrap; }
.pagination-btn {
    padding: 6px 12px; border: 1px solid var(--border); border-radius: 6px;
    color: var(--ink); font-size: 0.85rem; font-weight: 600; text-decoration: none;
}
.pagination-btn:hover { background: #fbe4ef; border-color: var(--accent); color: var(--accent); text-decoration: none; }
.pagination-btn.disabled { color: var(--muted); background: none; cursor: default; opacity: 0.5; }
.pagination-status { font-size: 0.85rem; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.pagination-jump-input { width: 56px; padding: 5px 6px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; text-align: center; }

.login-wrap { display: flex; justify-content: center; align-items: center; min-height: 80vh; }
.login-card { background: var(--card); border: 1px solid var(--border); border-radius: 16px; padding: 40px; width: 340px; text-align: center; box-shadow: 0 10px 30px rgba(0,0,0,0.05); }
.login-logo { height: 80px; width: 80px; border-radius: 50%; margin-bottom: 12px; }
.login-card h1 { font-size: 1.2rem; margin: 0 0 20px; }
.login-card form { display: flex; flex-direction: column; gap: 14px; text-align: left; }
.login-card label { font-size: 0.85rem; font-weight: 600; color: var(--muted); display: flex; flex-direction: column; gap: 5px; }
.login-card input { padding: 10px; border: 1px solid var(--border); border-radius: 8px; font-size: 0.95rem; }
.login-card .btn-primary { margin-top: 6px; width: 100%; }
/* Bornée en largeur pour rester lisible sur grand écran (sans plafond
   global sur .content depuis le 2026-08-31). Purement prose partout. */
.hint { color: var(--muted); font-size: 0.82rem; margin-top: 14px; max-width: 70ch; }

.error { color: var(--danger); font-weight: 600; background: #fef2f2; border: 1px solid #fecaca; padding: 10px 14px; border-radius: 8px; }
.success { color: var(--success); font-weight: 600; background: #ecfdf3; border: 1px solid #abefc6; padding: 10px 14px; border-radius: 8px; }

/* Case « tout cocher » : la case et le mot « page » sur la même ligne. */
.select-all-page-box { display: inline-flex; align-items: center; gap: 3px; }

/* Alerte de doublon (formulaire de création prospect) : avertissement,
   pas un blocage — n'utilise pas la couleur rouge de .error. */
.duplicate-warning {
    margin-top: 14px; padding: 12px 16px; border-radius: 10px;
    background: #fff8e6; border: 1px solid #f5d78a; color: #7a5b00;
    font-size: 0.88rem;
}
.duplicate-warning ul { margin: 8px 0; padding-left: 20px; }
.duplicate-warning li { margin-bottom: 4px; }
.duplicate-warning .btn-secondary { margin-top: 4px; }

.prospect-history { margin-top: 14px; color: var(--muted); font-size: 0.82rem; }

/* Page Doublons potentiels (/admin/duplicates) */
.dup-group {
    background: var(--card); border: 1px solid var(--border); border-radius: 12px;
    padding: 16px; margin-bottom: 18px;
}
.dup-group-header { font-size: 0.95rem; margin-bottom: 12px; }
.dup-group-count { color: var(--muted); font-size: 0.82rem; margin-left: 8px; }
.dup-cards { display: flex; gap: 14px; flex-wrap: wrap; }
.dup-card {
    flex: 1 1 260px; min-width: 240px; border: 1px solid var(--border); border-radius: 10px;
    padding: 12px; background: var(--bg);
}
.dup-card-radio { display: flex; align-items: center; gap: 6px; font-weight: 600; font-size: 0.85rem; margin-bottom: 8px; }
.dup-card-title { font-weight: 700; margin-bottom: 6px; }
.dup-card dl { margin: 0; font-size: 0.82rem; }
.dup-card dt { color: var(--muted); font-weight: 600; margin-top: 6px; }
.dup-card dd { margin: 0; }
.dup-card-meta { color: var(--muted); font-size: 0.75rem; margin-top: 8px; }
.dup-card a { display: inline-block; margin-top: 6px; font-size: 0.82rem; }
.dup-group-actions { margin-top: 14px; }
.dup-ignore-form { margin-top: 8px; }

/* ================================================================
   Suivi (/suivi) — chantier G, 2026-09-01. TOUT est scopé sous
   body.page-suivi (hook {% block body_attrs %} dans dashboard_stats.html) :
   aucune de ces règles ne peut toucher une autre page. Aucune retouche des
   classes partagées (.content, .prospect-table, .badge-statut*,
   .badge-annotation, .dashboard-header, .hint, style global de h1).
   ================================================================ */

/* Largeur max centrée — wrapper local, JAMAIS sur .content (régression 31/08). */
body.page-suivi .suivi-page { max-width: 1180px; margin: 0 auto; }

/* En-tête « Bonjour X » + date du jour (nouvelle classe, pas .dashboard-header). */
body.page-suivi .suivi-hero { margin: 4px 0 26px; }
body.page-suivi .suivi-hello { margin: 0; font-size: 1.7rem; }
body.page-suivi .suivi-date { margin: 3px 0 0; color: var(--muted); font-size: 0.9rem; }

body.page-suivi h2 { font-size: 1.1rem; margin: 26px 0 12px; }

/* Cartes de chiffres : contenu centré, padding réduit, cliquables si > 0. */
body.page-suivi .stat-cards { display: flex; gap: 14px; flex-wrap: wrap; margin: 0 0 26px; }
body.page-suivi .stat-card {
    flex: 1 1 180px; text-align: center;
    background: var(--card); border: 1px solid var(--border); border-radius: 12px;
    padding: 16px 18px;
}
body.page-suivi .stat-value { font-family: var(--font-title); font-size: 1.9rem; font-weight: 600; }
body.page-suivi .stat-label { color: var(--muted); font-size: 0.82rem; margin-top: 4px; }
body.page-suivi .stat-card-warning .stat-value { color: var(--danger); }
body.page-suivi .stat-card-info .stat-value { color: var(--accent); }
/* Variante cliquable (compteur > 0) = <a>. Survol discret (bordure + ombre),
   pas de déplacement de la carte. */
body.page-suivi a.stat-card { display: block; color: inherit; text-decoration: none; transition: border-color .12s, box-shadow .12s; }
body.page-suivi a.stat-card:hover { border-color: var(--accent); box-shadow: 0 2px 12px rgba(0, 0, 0, .07); text-decoration: none; }
/* Compteur à 0 = <div> (pas de lien) -> aucun curseur main, aucun survol.
   Chiffre grisé pour l'atténuer. */
body.page-suivi .stat-card-empty .stat-value { color: var(--muted); }

/* Répartition par statut : titre + tuiles centrés, tuiles cliquables. */
body.page-suivi .suivi-statuts { text-align: center; margin-bottom: 6px; }
body.page-suivi .statut-tiles { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-bottom: 26px; }
body.page-suivi .statut-tile {
    display: inline-flex; flex-direction: column; align-items: center; gap: 2px;
    min-width: 118px; padding: 12px 16px; border-radius: 10px;
    border: 1px solid var(--border); text-decoration: none; color: var(--ink);
}
body.page-suivi a.statut-tile { transition: border-color .12s, box-shadow .12s; }
body.page-suivi a.statut-tile:hover { border-color: var(--accent); box-shadow: 0 2px 12px rgba(0, 0, 0, .07); text-decoration: none; }
body.page-suivi .statut-tile-count { font-family: var(--font-title); font-weight: 600; font-size: 1.35rem; }
body.page-suivi .statut-tile-label { font-size: 0.8rem; }
/* Réutilise les pastels de .badge-statut-* — MÊMES valeurs, non modifiées. */
body.page-suivi .statut-tile-prospect { background: #ececf1; }
body.page-suivi .statut-tile-rdv      { background: #e0edff; }
body.page-suivi .statut-tile-nego     { background: #fef0c7; }
body.page-suivi .statut-tile-client   { background: #d1fae5; }
body.page-suivi .statut-tile-perdu    { background: #fee2e2; }
body.page-suivi .statut-tile-r1       { background: #ede9fe; }
body.page-suivi .statut-tile-r2       { background: #ddd6fe; }
body.page-suivi .statut-tile-r3       { background: #c4b5fd; }
body.page-suivi .statut-tile-asuivre  { background: #ccfbf1; }
body.page-suivi .statut-tile-empty { background: var(--card); opacity: .5; }

/* Tableaux enveloppés dans une carte — classe INDÉPENDANTE (.suivi-table),
   ne touche pas .prospect-table. */
body.page-suivi .suivi-two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }
body.page-suivi .suivi-table-card {
    background: var(--card); border: 1px solid var(--border); border-radius: 12px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .04); overflow: hidden; margin-bottom: 22px;
}
body.page-suivi .suivi-table-scroll { overflow-x: auto; }
body.page-suivi .suivi-table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }
body.page-suivi .suivi-table th {
    text-align: left; padding: 10px 14px; border-bottom: 1px solid var(--border); background: #fafafa;
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: .03em; font-weight: 700; color: var(--muted);
}
body.page-suivi .suivi-table td { padding: 10px 14px; border-bottom: 1px solid var(--border); white-space: nowrap; }
body.page-suivi .suivi-table tbody tr:last-child td { border-bottom: 0; }
body.page-suivi .suivi-table tbody tr:nth-child(even) { background: #fbfbfc; }
body.page-suivi .suivi-table tbody tr[data-row-href] { cursor: pointer; }
body.page-suivi .suivi-table tbody tr[data-row-href]:hover { background: #f2f2f5; }
body.page-suivi .suivi-chevron { width: 1.4em; text-align: right; color: var(--muted); }

/* États vides travaillés (variante commerciale). */
body.page-suivi .suivi-empty {
    background: var(--card); border: 1px solid var(--border); border-radius: 12px;
    padding: 28px 22px; text-align: center; margin-bottom: 22px;
}
body.page-suivi .suivi-empty p { margin: 0 0 14px; color: var(--muted); }
body.page-suivi .suivi-empty p:last-child { margin-bottom: 0; }
body.page-suivi .suivi-empty-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

body.page-suivi .suivi-muted { color: var(--muted); }

@media (max-width: 900px) {
    body.page-suivi .suivi-two-col { grid-template-columns: 1fr; }
}

/* Page d'erreur lisible (403 / 404), cf. main.py + templates/error.html. */
.error-page { max-width: 460px; margin: 8vh auto 0; text-align: center; }
.error-page-code { font-family: var(--font-title); font-size: 3rem; font-weight: 600; color: var(--muted); margin: 0; }
.error-page h1 { margin: 6px 0 12px; }
.error-page .btn-primary { display: inline-block; margin-top: 12px; }

.carte-map { height: 70vh; min-height: 420px; border-radius: 12px; overflow: hidden; border: 1px solid var(--border); margin-top: 16px; }
.carte-map .leaflet-popup-content a { font-weight: 600; }
.cluster-assign-popup { display: flex; flex-direction: column; gap: 8px; min-width: 200px; }
.cluster-assign-popup select, .cluster-assign-popup input[type="text"] {
    padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; font-family: inherit;
}
.cluster-assign-popup .btn-primary { padding: 6px 12px; font-size: 0.85rem; }
.cluster-assign-popup .success, .cluster-assign-popup .error { padding: 6px 8px; font-size: 0.8rem; margin: 0; }

.field-hint { display: block; font-size: 0.75rem; font-weight: 400; color: var(--muted); margin-top: 3px; }

/* Vue mobile (< 768px) : fiches empilées à la place du tableau dense.
   Les deux vues sont toujours rendues côté serveur (mêmes prospects),
   seul ce media query décide laquelle est visible - aucun JS impliqué,
   fonctionne à l'identique après chaque swap HTMX. */
.mobile-card-view { display: none; }
@media (max-width: 767px) {
    .desktop-table-view { display: none; }
    .mobile-card-view { display: block; }
}
.prospect-card {
    background: var(--card); border: 1px solid var(--border); border-radius: 12px;
    padding: 14px; margin-bottom: 12px;
}
.prospect-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.prospect-card-name { font-weight: 700; font-size: 1rem; }
.prospect-card-tel { display: block; font-size: 0.95rem; margin-bottom: 4px; }
.prospect-card-ville { color: var(--muted); font-size: 0.85rem; margin-bottom: 10px; }
.prospect-card-rappel {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    border-top: 1px solid var(--border); padding-top: 10px; margin-top: 4px;
}
.prospect-card-rappel .relance-trigger-btn { padding: 6px 10px; }
.prospect-card-link { display: block; text-align: center; margin-top: 12px; }

/* Plafond LOCAL des pages « formulaire » (fiche prospect, import, gestion
   utilisateur/liste) : sans plafond global sur .content depuis le
   2026-08-31, un formulaire s'étirerait sur tout un grand moniteur
   (champs « Nom », « Téléphone » larges de 1200px, texte illisible).
   Aligné à gauche comme le titre de la page. /mon-compte garde son
   propre 560px (règle .account-form plus bas). */
.prospect-form { max-width: 1000px; }
.prospect-form .form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 20px; }
.prospect-form label { display: flex; flex-direction: column; gap: 5px; font-size: 0.82rem; font-weight: 600; color: var(--muted); }
.prospect-form input, .prospect-form select, .prospect-form textarea { padding: 9px; border: 1px solid var(--border); border-radius: 8px; font-size: 0.9rem; font-family: inherit; }
.prospect-form textarea { resize: vertical; }

/* Commentaire verrouillé (chantier 2026-09-16) : un <div class="span-2"> à
   la place du <label> habituel (pas de contrôle de formulaire dedans),
   même typographie de libellé reproduite à la main. */
.prospect-form .commentaire-field { display: flex; flex-direction: column; gap: 5px; font-size: 0.82rem; font-weight: 600; color: var(--muted); }
.commentaire-historique {
    padding: 9px; border: 1px solid var(--border); border-radius: 8px;
    background: #f7f7f9; color: var(--ink); font-size: 0.9rem; font-family: inherit;
    font-weight: 400; white-space: pre-wrap; word-break: break-word;
    max-height: 220px; overflow-y: auto; cursor: text; user-select: text;
}
.prospect-form .span-2 { grid-column: span 2; }
.form-actions { margin-top: 16px; display: flex; align-items: center; gap: 12px; }
.inline-delete { margin-left: auto; }
.checkbox-field { flex-direction: row !important; align-items: center; gap: 8px !important; font-weight: 500 !important; }
.liste-picker { border: 1px solid var(--border); border-radius: 10px; padding: 14px; display: flex; flex-wrap: wrap; gap: 12px; }
.liste-picker legend { font-size: 0.8rem; color: var(--muted); font-weight: 600; padding: 0 6px; }

/* Mon compte (/mon-compte) : même gabarit que .prospect-form (cf.
   prospect_form.html — carte, champs, bouton identiques, rien réinventé),
   juste une seule colonne au lieu de plusieurs (.form-grid est en
   repeat(auto-fill, minmax(220px, 1fr)) par défaut, adapté à un
   formulaire avec beaucoup de petits champs prospect ; ici chaque champ
   doit occuper sa propre ligne, cf. décision du 2026-08-30) et une
   largeur de carte plus étroite, cohérente avec un formulaire à un seul
   champ par ligne. */
.account-form { max-width: 560px; }
.account-form .form-grid { grid-template-columns: 1fr; }
.account-password-section {
    border: 1px solid var(--border); border-radius: 10px; padding: 16px;
    display: flex; flex-direction: column; gap: 14px; margin-top: 4px;
}
.account-password-section legend { font-size: 0.85rem; font-weight: 700; color: var(--ink); padding: 0 6px; }
.account-password-section .hint { margin: 0 0 4px; }

.inline-form { display: flex; gap: 10px; margin-bottom: 18px; }
.inline-form input { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; }

.bulk-toolbar, .bulk-banner {
    display: none;
    align-items: center;
    gap: 10px;
    border-radius: 10px;
    padding: 10px 14px;
    margin-bottom: 10px;
    font-size: 0.85rem;
    flex-wrap: wrap;
}
/* Fond rosé pâle cohérent avec la palette (magenta de marque) pour toute
   la barre de sélection en masse. Les deux actions ("Sélectionner tout le
   filtré" dans .bulk-banner et "Ajouter à la liste" dans .bulk-toolbar)
   gardent le même poids visuel (.btn-primary) - ne pas régresser dessus
   (cf. décision du 2026-08-28 - impossible de croire avoir tout
   sélectionné en ne cochant que la page). */
.bulk-toolbar, .bulk-banner { background: #fbe4ef; border: 1px solid #f3c3dc; }
.bulk-toolbar.active, .bulk-banner.active { display: flex; }
.bulk-toolbar select, .bulk-toolbar input[type="text"] { padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; }
#bulk-count-label { font-weight: 600; color: var(--accent-dark); }
#bulk-banner-text { font-weight: 600; color: var(--accent-dark); }

.select-all-page-cell { text-align: center; }
/* « page » sur la même ligne que la case à cocher (chantier A, A5/D5) :
   plus de margin-top, c'est un élément inline-flex dans .select-all-page-box. */
.select-all-page-hint { font-size: 0.6rem; color: var(--muted); text-transform: none; font-weight: 600; }

.date-rappel-cell { white-space: nowrap; display: flex; align-items: center; gap: 6px; }
.date-rappel-value { font-weight: 600; }
.quick-relance { display: flex; flex-wrap: wrap; gap: 4px; }
.quick-relance-btn {
    font-size: 0.72rem;
    padding: 3px 8px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: white;
    color: var(--ink);
    cursor: pointer;
    white-space: nowrap;
}
.quick-relance-btn:hover { background: #fbe4ef; border-color: var(--accent); color: var(--accent); }
.prospect-form .quick-relance { margin-top: 6px; align-items: center; }

/* Popover compact "Fixer une date de rappel" dans le tableau (remplace les
   5 boutons empilés qui prenaient plusieurs lignes de hauteur) : un seul
   déclencheur, le contenu (raccourcis + date libre) ne s'affiche qu'au clic
   (cf. décision du 2026-08-28). */
.relance-popover-wrap { position: relative; display: inline-flex; }
.relance-trigger-btn {
    border: 1px solid var(--border);
    background: white;
    border-radius: 6px;
    padding: 3px 7px;
    font-size: 0.85rem;
    line-height: 1;
    cursor: pointer;
}
.relance-trigger-btn:hover { background: #fbe4ef; border-color: var(--accent); }
/* Icône calendrier (chantier J, 2026-09-04) : remplace l'emoji 📅, même
   gabarit visuel dans le bouton. currentColor -> suit la couleur du texte
   (y compris au survol rose ci-dessus). */
.kvb-icon-calendar { vertical-align: -2px; margin-right: 1px; }
.relance-popover {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    margin-top: 4px;
    width: 220px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.relance-popover.open { display: block; }
.relance-popover .field-hint { margin: 0 0 8px; }
.relance-popover-shortcuts { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px; }
.relance-popover-date-row { display: flex; gap: 6px; border-top: 1px solid var(--border); padding-top: 8px; }
.relance-popover-date-row input[type="date"] { flex: 1; min-width: 0; padding: 5px 6px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.82rem; }

/* Mobile : sur les fiches (< 768px) le déclencheur « 📅 Rappel rapide » est
   collé au bord droit de la fiche ; ancré à left:0 avec une largeur fixe de
   220px, le popover débordait de l'écran. On l'ancre donc à droite du
   déclencheur et on remplace la largeur fixe par une max-width bornée à la
   fenêtre (même principe que les bulles d'aide mobiles). Les raccourcis
   passent déjà à la ligne (flex-wrap) et restent cliquables. */
@media (max-width: 767px) {
    .relance-popover {
        left: auto;
        right: 0;
        width: auto;
        min-width: 180px;
        max-width: min(260px, calc(100vw - 28px));
    }
}

/* ================================================================
   Chantier A — lisibilité du tableau Prospects (page / uniquement)
   ----------------------------------------------------------------
   TOUT est préfixé `body.page-prospects` (classe posée seulement par
   dashboard.html, via le flag serveur `prospects_page` de _render_dashboard)
   et borné en media queries. /relances, /suivi et les pages admin
   réutilisent .prospect-table / partials sans ce contexte : aucun de leurs
   styles calculés ne change.
   Aucune couleur nouvelle : #fafafa = fond .prospect-table th existant,
   #F5F5F7 = survol de ligne existant, var(--card)/var(--border) = jetons.
   ================================================================ */

@media (min-width: 768px) {
    /* D2 — mise en page pleine hauteur : le <body> devient une colonne flex,
       le bandeau garde sa hauteur naturelle, tout le reste se répartit ;
       .table-scroll absorbe l'espace restant et devient la SEULE zone qui
       défile. Aucun nombre codé en dur -> l'ouverture du panneau « Filtres
       avancés » redimensionne le tableau toute seule. */
    body.page-prospects { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
    /* width:100% + min-width:0 : sans ça, `margin:0 auto` sur .content
       neutralise l'étirement (align stretch) et .content prend la largeur
       de contenu du tableau -> débordement horizontal quand celui-ci est
       plus large que la fenêtre. min-width:0 propagé dans toute la chaîne
       pour que .table-scroll puisse être plus étroit que sa table. */
    body.page-prospects > .content {
        flex: 1 1 0%; min-height: 0; min-width: 0; width: 100%;
        display: flex; flex-direction: column;
    }
    body.page-prospects .prospects-page { flex: 1 1 0%; min-height: 0; min-width: 0; display: flex; flex-direction: column; }
    body.page-prospects #table-wrap { flex: 1 1 0%; min-height: 0; min-width: 0; display: flex; flex-direction: column; }
    body.page-prospects #table-wrap > .filter-chips,
    body.page-prospects #table-wrap > .results-meta,
    body.page-prospects #table-wrap > .success,
    body.page-prospects #table-wrap > .error { flex: none; }
    body.page-prospects #bulk-form { flex: 1 1 0%; min-height: 0; min-width: 0; display: flex; flex-direction: column; }
    body.page-prospects #bulk-form > .bulk-banner,
    body.page-prospects #bulk-form > .bulk-toolbar,
    body.page-prospects #table-wrap > .pagination,
    body.page-prospects #bulk-form > .pagination { flex: none; }
    /* A6 — pagination du haut masquée en desktop (celle du bas reste visible
       en permanence, le tableau défile en interne). Conservée en vue mobile
       cartes, cf. .pagination--top dans partials/table.html. Étendu à
       /relances (chantier J, 2026-09-04) : même gain, page plus courte,
       aucun changement de mise en page par ailleurs. */
    body.page-prospects .pagination--top,
    body.page-relances .pagination--top { display: none; }
    body.page-prospects .desktop-table-view { flex: 1 1 0%; min-height: 0; min-width: 0; display: flex; flex-direction: column; }
    body.page-prospects .table-scroll { flex: 1 1 0%; min-height: 0; min-width: 0; overflow: auto; }

    /* A1 — en-tête figé au défilement vertical (dans .table-scroll borné
       ci-dessus, page Prospects). Fond opaque = valeur existante #fafafa
       (P2). Étendu à /relances (chantier J, 2026-09-04) : sans la colonne
       pleine hauteur du chantier A, .table-scroll ne serait pas borné et
       le sticky n'aurait aucune amplitude où s'accrocher (overflow-x:auto
       calcule overflow-y à `auto` aussi, cf. spec CSS Overflow -> .table-
       scroll est déjà un conteneur de défilement, juste jamais borné en
       hauteur) -> on le borne explicitement à 65vh (défilement interne
       propre, sans toucher au reste de la mise en page de /relances). */
    body.page-relances .table-scroll { max-height: 65vh; overflow-y: auto; }
    body.page-prospects .table-scroll .prospect-table thead th,
    body.page-relances .table-scroll .prospect-table thead th {
        position: sticky; top: 0; z-index: 3; background: #fafafa;
    }
    /* Coins (intersection en-tête × colonne figée / colonne Modifier) au-dessus. */
    body.page-prospects .table-scroll .prospect-table thead th.col-frozen,
    body.page-prospects .table-scroll .prospect-table thead th.select-all-page-cell,
    body.page-prospects .table-scroll .prospect-table thead th.row-actions-th { z-index: 5; }

    /* A5 — libellés d'en-tête alignés en bas : combiné à la case « tout
       cocher » remise sur une seule ligne, le <thead> retrouve une hauteur
       de ligne simple (plus de bande grise vide en dessous). Étendu à
       /relances (chantier J, 2026-09-04). */
    body.page-prospects .prospect-table thead th,
    body.page-relances .prospect-table thead th { vertical-align: bottom; }
}

@media (min-width: 1024px) {
    /* A2 / D3 — figer la case à cocher (largeur fixe -> left déterministe)
       + la 1ʳᵉ colonne de données visible (.col-frozen, marquée côté serveur).
       > 1024px seulement : en dessous, deux colonnes gelées mangeraient trop
       de largeur. Séparation par box-shadow (P1 : .prospect-table est en
       border-collapse:collapse, une bordure sur cellule sticky ne se peint
       pas de façon fiable — même parti pris que .row-actions--single).

       Empilement (z-index) :
         en-tête courant .......... 3   (bloc A1 ci-dessus)
         cellules figées du corps .. 2   (sous l'en-tête au défilement vertical)
         coins en-tête × figé ...... 5   (bloc A1 ci-dessus : au-dessus des deux) */
    body.page-prospects .prospect-table th.select-all-page-cell,
    body.page-prospects .prospect-table td.col-checkbox {
        position: sticky; left: 0;
        width: 56px; min-width: 56px; max-width: 56px;
        padding-left: 4px; padding-right: 4px;
    }
    body.page-prospects .prospect-table td.col-checkbox { background: var(--card); z-index: 2; }
    body.page-prospects .prospect-table th.select-all-page-cell { background: #fafafa; }

    body.page-prospects .prospect-table td.col-frozen {
        position: sticky; left: 0; z-index: 2;
        background: var(--card);
        box-shadow: inset -1px 0 0 var(--border);
    }
    body.page-prospects .prospect-table th.col-frozen {
        position: sticky; left: 0;
        background: #fafafa;
        box-shadow: inset -1px 0 0 var(--border);
    }
    /* décalée de la largeur de la case à cocher quand celle-ci est présente */
    body.page-prospects .has-checkboxes .prospect-table td.col-frozen,
    body.page-prospects .has-checkboxes .prospect-table th.col-frozen { left: 56px; }

    /* P2 — fond opaque conservé au survol de ligne (le tableau n'a pas de
       lignes alternées). Même technique que .row-actions--single. */
    body.page-prospects .prospect-table tbody tr:hover td.col-checkbox,
    body.page-prospects .prospect-table tbody tr:hover td.col-frozen { background: #F5F5F7; }
}

/* ================================================================
   Chantier B — hiérarchie et placement des actions (page / uniquement,
   sauf mention contraire). Scopé body.page-prospects comme le chantier A.
   Ne touche pas : --accent, .btn-*, le bouton « Filtrer ».
   ================================================================ */

/* D1 — les 3 zones d'action regroupées dans un seul cadre pour se lire
   comme une barre d'outils unique. Rythme vertical constant, .filter-bar
   dé-cartée à l'intérieur (le cadre externe porte la carte). flex:none
   pour rester compatible avec la colonne pleine hauteur du chantier A
   (seul .table-scroll absorbe l'espace restant). */
body.page-prospects .prospects-toolbar {
    display: flex; flex-direction: column; gap: 14px;
    background: var(--card); border: 1px solid var(--border);
    border-radius: 12px; padding: 16px;
    margin-bottom: 14px;   /* espace jusqu'au tableau, dans les deux mises en page */
}
body.page-prospects .dashboard-header,
body.page-prospects .filter-toolbar { margin-bottom: 0; }
body.page-prospects .filter-bar {
    background: none; border: 0; border-radius: 0; padding: 0; margin-bottom: 0;
}
@media (min-width: 768px) {
    /* dans la colonne flex du chantier A : le cadre garde sa hauteur
       naturelle, il ne grandit ni ne rétrécit. */
    body.page-prospects .prospects-page > .prospects-toolbar { flex: none; }
}

/* D3 — lien « Modifier » du tableau : couleur de texte normale par défaut,
   rose + souligné seulement au survol / focus. Scopé strictement : sur
   /relances (pas de body.page-prospects) le lien reste rose comme avant. */
body.page-prospects .prospect-table td.row-actions--single a { color: var(--ink); }
body.page-prospects .prospect-table td.row-actions--single a:hover,
body.page-prospects .prospect-table td.row-actions--single a:focus {
    color: var(--accent); text-decoration: underline;
}

/* ================================================================
   Chantier C — fiche prospect (prospect_form.html)
   ----------------------------------------------------------------
   Scopé .prospect-edit-form (classe ajoutée sur le <form> de la fiche).
   /mon-compte, /admin/users/*, /admin/listes/*/users, /admin/import
   réutilisent .prospect-form / .form-grid / .form-actions et NE doivent
   pas bouger -> aucune de ces règles n'est sans le préfixe .prospect-edit-form
   (sauf .prospect-back-link, hors du <form>, nom sans collision).
   ================================================================ */

.prospect-back-link {
    display: inline-block; margin-bottom: 10px;
    color: var(--muted); font-weight: 600; font-size: 0.9rem;
}

/* Pleine largeur (chantier 2026-09-22-ter) : .prospect-form garde son
   plafond 1000px (ligne ~704) pour les AUTRES pages qui le partagent
   (mon-compte, import, gestion utilisateur/liste — leurs grilles ne sont
   pas conçues pour s'étirer). Mais .prospect-edit-form (fiche société
   uniquement) n'a plus besoin d'être bridée : ses grilles ci-dessous
   définissent elles-mêmes un nombre de colonnes borné (2-3, jamais plus),
   donc l'étirer sur tout l'écran ne rend plus les champs illisibles comme
   le ferait .form-grid seul seul — cohérent avec les autres pages du site
   qui n'ont plus de plafond global depuis le 2026-08-31. */
.prospect-edit-form { max-width: none; }

/* D2 — bloc principal : grille 2 colonnes FIXES (jamais de case vide au wrap,
   contrairement au repeat(auto-fill,...) de .form-grid qui laissait des trous
   à 3+ colonnes avec les champs pleine largeur). align-items:start : un champ
   court à côté d'un champ plus haut n'est plus étiré. 1 colonne sous 640px.
   3 colonnes à partir de 1280px (chantier 2026-09-22-ter, pleine largeur) :
   les 6 champs simples du bloc (Nom, Téléphone, Statut, Client, Date de
   rappel, Date de RDV) tombent pile sur 2 lignes de 3, toujours sans case
   vide. Classe dédiée (pas .form-grid) pour ne rien devoir surcharger. */
.prospect-edit-form .prospect-main-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
    background: var(--card); border: 1px solid var(--border);
    border-radius: 12px; padding: 20px;
}
.prospect-edit-form .prospect-main-grid > .span-2 { grid-column: 1 / -1; }
@media (min-width: 1280px) {
    .prospect-edit-form .prospect-main-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .prospect-edit-form .prospect-main-grid { grid-template-columns: 1fr; }
}

/* D2 — bloc secondaire dans un <details> natif (zéro JS). Le <details> porte
   la carte ; la grille interne n'a donc ni fond ni bordure. */
.prospect-edit-form .secondary-fields {
    margin-top: 16px;
    background: var(--card); border: 1px solid var(--border);
    border-radius: 12px; padding: 0 20px;
}
.prospect-edit-form .secondary-fields > summary {
    padding: 15px 0; cursor: pointer;
    font-size: 0.9rem; font-weight: 700; color: var(--ink);
    list-style: none;
}
.prospect-edit-form .secondary-fields > summary::-webkit-details-marker { display: none; }
.prospect-edit-form .secondary-fields > summary::before {
    content: "\25B8"; display: inline-block; width: 1.2em; color: var(--muted);
}
.prospect-edit-form .secondary-fields[open] > summary::before { content: "\25BE"; }
/* Même palier que le bloc principal (2 colonnes par défaut, 3 à partir de
   1280px, 1 sous 640px) plutôt que l'ancien auto-fill(minmax(200px,1fr)) :
   celui-ci aurait donné un nombre de colonnes croissant sans limite sur un
   grand écran (7 champs sur 5-6 colonnes minuscules) une fois le plafond
   1000px retiré — exactement le risque de surcharge visuelle à éviter. */
.prospect-edit-form .prospect-secondary-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
    padding: 0 0 20px;
}
@media (min-width: 1280px) {
    .prospect-edit-form .prospect-secondary-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .prospect-edit-form .prospect-secondary-grid { grid-template-columns: 1fr; }
}

/* Ville stricte (chantier 2026-09-07) : autocomplétion sur la liste
   officielle des communes. Le label ancre la liste de suggestions
   (position:absolute) juste sous le champ. */
.prospect-form label.ville-field { position: relative; }
/* Filtre Ville de la page Sociétés (chantier 2026-09-22) : même liste de
   suggestions, mais sans validation stricte (filtre "contient", pas une
   saisie de donnée) — .ville-suggestions est déjà générique. */
.filter-field.ville-filter-field { position: relative; }
.ville-suggestions {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 30;
    margin: 2px 0 0; padding: 4px; list-style: none;
    background: var(--card); border: 1px solid var(--border); border-radius: 8px;
    box-shadow: 0 8px 20px rgba(0,0,0,0.08);
    max-height: 220px; overflow-y: auto;
}
.ville-suggestions li {
    padding: 7px 9px; border-radius: 6px; cursor: pointer;
    font-size: 0.85rem; font-weight: 400; color: var(--ink);
}
.ville-suggestions li:hover, .ville-suggestions li.active { background: #f2f2f7; }
.field-error {
    color: var(--danger); font-weight: 600; font-size: 0.78rem;
    margin: 2px 0 0;
}
.prospect-form input.field-invalid { border-color: var(--danger); }

/* D5 — actions secondaires (nav précédent/suivant, carte, suppression) hors
   de .form-actions. */
.prospect-edit-form .prospect-actions-extra {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    margin-top: 16px;
}
.prospect-edit-form .prospect-actions-extra .prospect-delete-btn { margin-left: auto; }
.prospect-edit-form .prospect-nav { display: inline-flex; gap: 8px; }
.prospect-edit-form .prospect-nav-off { opacity: 0.4; cursor: default; }

/* D6 — « Enregistrer » (+ Annuler) collant en bas d'écran, UNIQUEMENT sous
   768px. .form-actions y est réduite à ces deux boutons -> une seule ligne.
   Fond opaque var(--bg) : le contenu défile derrière sans transparence.
   Au-dessus de 768px : inchangé, dans le flux. */
@media (max-width: 767px) {
    .prospect-edit-form .form-actions {
        position: sticky; bottom: 0; z-index: 20;
        background: var(--bg);
        /* pleine largeur : annule les 24px de padding de .content */
        margin: 10px -24px 0; padding: 10px 24px;
        border-top: 1px solid var(--border);
        gap: 10px;
    }
    .prospect-edit-form .form-actions .btn-primary { flex: 1 1 auto; }
}
/* Clavier virtuel ouvert -> viewport court : on désactive le collage pour ne
   jamais recouvrir le champ en cours de saisie (cf. contrainte D6). La barre
   repasse dans le flux, sous le formulaire. */
@media (max-width: 767px) and (max-height: 450px) {
    .prospect-edit-form .form-actions {
        position: static; margin: 12px 0 0; padding: 0; border-top: 0;
    }
}

/* Chantier "Ventes" (2026-10-01) : section réservée admin, HORS de
   #prospect-form (cf. commentaire dans prospect_form.html) -> pas sous
   .prospect-edit-form, carte indépendante avec le même habillage que
   .secondary-fields juste au-dessus (cohérence visuelle). */
.ventes-section {
    margin-top: 16px; background: var(--card); border: 1px solid var(--border);
    border-radius: 12px; padding: 20px;
}
.ventes-section h2 { margin: 0 0 12px; font-size: 1rem; }
.ventes-table-wrap { overflow-x: auto; }
.ventes-table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }
.ventes-table th {
    text-align: left; padding: 8px 12px; font-size: 0.72rem; text-transform: uppercase;
    letter-spacing: 0.02em; color: var(--muted); border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.ventes-table td { padding: 10px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.ventes-table tbody tr:last-child td { border-bottom: 0; }
/* Modifier + Supprimer (chantier 2026-10-02) : sur la même ligne, un
   <form> (Supprimer) et un <a> (Modifier) côte à côte -> flex plutôt que
   inline-block, pour un espacement cohérent indépendant du type d'élément. */
.ventes-row-actions { display: flex; align-items: center; gap: 12px; }
.vente-delete-form { display: inline; margin: 0; }
.vente-delete-btn { color: var(--danger); padding: 0; }
.vente-add-details { margin-top: 16px; }
.vente-add-details > summary {
    cursor: pointer; font-size: 0.9rem; font-weight: 700; color: var(--ink);
    list-style: none;
}
.vente-add-details > summary::-webkit-details-marker { display: none; }
.vente-add-form {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px;
    align-items: end; margin-top: 14px;
}
.vente-add-form label {
    display: flex; flex-direction: column; gap: 5px; font-size: 0.82rem;
    font-weight: 600; color: var(--muted);
}
.vente-add-form input {
    padding: 9px; border: 1px solid var(--border); border-radius: 8px;
    font-size: 0.9rem; font-family: inherit;
}
.vente-add-form .btn-primary { height: fit-content; }
/* "Annuler" (chantier 2026-10-02, mode édition uniquement) : à côté du
   bouton Enregistrer, centré verticalement plutôt qu'étiré par le grid. */
.vente-add-form .btn-link { align-self: center; }
@media (max-width: 767px) {
    .vente-add-form { grid-template-columns: 1fr; }
}

/* Installation PWA (chantier 2026-09-22) : bannière discrète (pas un
   pop-up bloquant, cf. règles décidées) collée en bas de l'écran, + une
   modale simple pour les instructions à la demande (lien du menu
   compte). z-index au-dessus de tout le reste de l'UI (formulaires
   collants inclus, cf. .prospect-edit-form .form-actions ci-dessus à 20). */
/* [hidden] seul suffit à masquer .pwa-install-modal (aucun display
   explicite dessus), mais PAS .pwa-install-banner : son display:flex
   (règle d'auteur) l'emporterait sinon sur le display:none du [hidden]
   par défaut du navigateur (feuille user-agent, toujours moins
   prioritaire qu'une règle d'auteur, quelle que soit la spécificité) —
   d'où cette règle explicite. */
.pwa-install-banner[hidden] { display: none; }
.pwa-install-banner {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 1500;
    display: flex; align-items: center; gap: 12px;
    background: var(--card); border-top: 1px solid var(--border);
    box-shadow: 0 -4px 16px rgba(0,0,0,0.08);
    padding: 12px 16px; font-size: 0.85rem; color: var(--ink);
}
.pwa-install-banner strong { color: var(--accent); }
.pwa-install-banner span { flex: 1; }
.pwa-install-banner-close {
    flex: none; background: none; border: 0; cursor: pointer;
    font-size: 1rem; line-height: 1; color: var(--muted); padding: 6px;
}
.pwa-install-banner-close:hover { color: var(--ink); }

.pwa-install-modal { position: fixed; inset: 0; z-index: 2000; }
.pwa-install-modal-backdrop { position: absolute; inset: 0; background: rgba(23,23,27,0.45); }
.pwa-install-modal-box {
    position: relative; z-index: 1; margin: 15vh auto 0; max-width: 380px;
    background: var(--card); border-radius: 14px; padding: 24px;
    box-shadow: 0 20px 50px rgba(0,0,0,0.25);
}
.pwa-install-modal-box h2 { margin: 0 0 12px; font-size: 1.05rem; padding-right: 20px; }
.pwa-install-modal-box p { margin: 0; color: var(--ink); line-height: 1.5; font-size: 0.9rem; }
.pwa-install-modal-close {
    position: absolute; top: 14px; right: 14px; background: none; border: 0;
    cursor: pointer; font-size: 1.1rem; line-height: 1; color: var(--muted);
}
.pwa-install-modal-close:hover { color: var(--ink); }
@media (max-width: 480px) {
    .pwa-install-modal-box { margin: 20vh 16px 0; }
}
