/* ============================================================
   Boutons, tableaux, cartes, formulaires
   components.css · lignes 82-207 du fichier d'origine
   ============================================================ */
/* ============ COMPONENTS ============ */
/* line-height fixe : sans elle, un pictogramme rendu comme emoji (plus haut
   que le texte) agrandit tout le bouton, qui dépasse alors ses voisins — la
   barre d'actions étant alignée par le bas, il monte au-dessus des autres.
   font-variant-emoji demande la forme TEXTE des symboles ambigus (☎ ✉ ⏱),
   ceux qui ont les deux. Sans effet sur les vrais emoji, qui n'en ont qu'une. */
.btn{display:inline-flex;align-items:center;justify-content:center;                                                                            font-variant-emoji:text;}
.btn.call{justify-content:center}
.btn.mail{justify-content:center}
/* boutons d'action principaux (Nouveau lead / devis / facture…) mis en évidence — desktop & mobile */
/* système d'actions cohérent : send = envoi (bleu), ok = valider (vert), draft = brouillon (sable) */
.btn.send{justify-content:center}
.btn.ok{justify-content:center}
.btn.draft{justify-content:center}
.btn.danger{justify-content:center}
.btn.sms{justify-content:center}
.btn.portal{justify-content:center}

.cards{display:grid;}
.kpi{background:var(--surface);}
.kpi .foot{color:var(--ink-soft);}
.kpi .foot .up{color:var(--ok);}
.kpi .foot .down{color:var(--bad);}

.panel{background:var(--surface);                                                                                  overflow:hidden;}
.panel-head{display:flex;align-items:center;}
.panel-head .spacer{flex:1}
/* ⚠️ LES ACTIONS D'UN EN-TÊTE VOYAGENT ENSEMBLE. Posées à plat après le
   `.spacer`, elles se séparent dès que la rangée se replie : sur un
   téléphone, « ＋ Intervention » restait en haut À DROITE et « ＋ Contrat »
   passait à la ligne tout À GAUCHE, en diagonale l'un de l'autre (capture du
   21/09/2026). Un groupe se replie d'un bloc. */
.panel-head .ph-act{display:flex;align-items:center;gap:8px;margin-left:auto;flex-wrap:wrap}
.grid-2{display:grid;grid-template-columns:1fr 1fr;}
@media(max-width:1000px){.grid-2{grid-template-columns:1fr}}

.toolbar{display:flex;         align-items:center;flex-wrap:wrap;}
.tabsrow{display:flex;         flex-wrap:wrap}
.toolbar .spacer{flex:1}
/* Champ date affiché en jj/mm/aaaa quelle que soit la langue du navigateur.
   Le <input type=date> natif est conservé (valeur ISO + sélecteur système) mais rendu
   transparent et superposé : on n'affiche que notre libellé français. Il redevient
   visible pendant la saisie au clavier, pour ne pas taper à l'aveugle. */
.datefr{position:relative;display:inline-flex;align-items:center;justify-content:space-between;gap:8px;                    border:1px solid var(--line);                  background:var(--surface);                                  font-variant-numeric:tabular-nums;                cursor:pointer}
.datefr::after{content:'📅';font-size:11px;           flex:0 0 auto}
.datefr-lab{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.datefr.vide .datefr-lab{color:var(--ink-faint);font-weight:400}
.datefr > input[type=date][data-dfr]{position:absolute;inset:0;width:100%;height:100%;opacity:0;
  min-height:0;margin:0;border:0;border-radius:inherit;background:none;font:inherit;
  color:var(--ink);padding:0 26px 0 11px;cursor:pointer}
.datefr:focus-within{background:var(--surface)}
.datefr:focus-within > input[type=date]{opacity:1}
.datefr:focus-within > .datefr-lab{opacity:0}
/* le champ doit occuper toute la largeur là où l'input le faisait */
.field .datefr,.lc-grid .datefr,.jform .datefr{display:flex;width:100%}
.field .datefr{padding:10px 12px;border-radius:10px;background:var(--surface-2);font-size:inherit;font-weight:400}
.field .datefr > input[type=date][data-dfr]{padding:0 30px 0 12px}
.lc-grid .datefr{padding:10px 11px;font-size:16px}
.lc-grid .datefr > input[type=date][data-dfr]{font-size:16px}
@media(max-width:720px){
  .field .datefr{padding:12px 13px;font-size:16px}
  .tache-form .datefr{display:flex;width:100%;font-size:16px}
  .jform .datefr{font-size:16px;padding:11px 12px}
}

/* facturation : la période et le filtre « créées du » restent des blocs cohérents */
.fac-range,.fac-created{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}

.pt-nav,.cal-navhead{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.pt-nav input,.cal-navhead input{text-align:center}
.pt-nav .tag{justify-content:center}

table{width:100%;border-collapse:collapse}
.table-wrap{overflow:hidden;}
thead th{text-align:left;                                     text-transform:uppercase;}
th.sortable{cursor:pointer;user-select:none;white-space:nowrap}
th.sortable:hover{color:var(--ink)}
th.sortable .ar{opacity:.4;              margin-left:2px}
th.sortable.act .ar{opacity:1;color:var(--accent)}
tbody td{vertical-align:middle}
tbody tr:last-child td{border-bottom:none}
tbody tr{transition:.1s}
td .ref{color:var(--ink-soft);}
.muted{color:var(--ink-faint)}
.right{text-align:right}
.avatar{display:inline-grid;place-items:center;                                                vertical-align:middle}

.tag{display:inline-flex;align-items:center;}
.tag::before{content:"";                     border-radius:50%;background:currentColor}
.tag.ok{background:var(--ok-bg);color:var(--ok)}
.tag.warn{background:var(--warn-bg);color:var(--warn)}
.tag.bad{background:var(--bad-bg);color:var(--bad)}
.tag.info{background:var(--info-bg);color:var(--info)}
/* Sélecteur de statut coloré (pastille cliquable) */
.statut-select{border:1.5px solid transparent;                                                                    cursor:pointer;line-height:1.2}
.statut-select option{color:var(--ink);background:var(--surface);font-weight:600}
.statut-select.st-ok{background:var(--ok-bg);color:var(--ok);border-color:color-mix(in srgb,var(--ok) 45%,transparent)}
.statut-select.st-warn{background:var(--warn-bg);color:var(--warn);border-color:color-mix(in srgb,var(--warn) 45%,transparent)}
.statut-select.st-info{background:var(--info-bg);color:var(--info);border-color:color-mix(in srgb,var(--info) 45%,transparent)}
.statut-select.st-mute{background:var(--surface-2);color:var(--ink-soft);border-color:var(--line)}

.row-act{display:flex;        justify-content:flex-end}

.empty{padding:48px 20px;text-align:center;color:var(--ink-faint)}
.empty .big{font-size:30px;margin-bottom:8px}

/* progress */
.bar{overflow:hidden;min-width:80px}
.bar>i{display:block;height:100%;}


/* Le « ✎ » d'affectation dans la grille du planning d'équipe : discret au
   repos, il ne doit pas concurrencer la référence du chantier — mais il doit
   rester atteignable au doigt, d'où la zone de 22 px. */
.pcell{position:relative}
.pcell-edit{position:absolute;top:2px;right:2px;width:22px;height:22px;line-height:1;
  border:0;border-radius:6px;background:transparent;color:inherit;opacity:.35;
  cursor:pointer;font-size:11px;padding:0}
.pcell:hover .pcell-edit{opacity:.9;background:rgba(255,255,255,.55)}
.pcell-edit:focus-visible{opacity:1;outline:2px solid var(--accent);outline-offset:1px}
@media(hover:none){ .pcell-edit{opacity:.6} }

/* Une tâche terminée tient sur une ligne : elle n'appelle plus de décision,
   elle ne doit plus occuper la place d'une carte. `min-width:0` sur le titre
   est ce qui autorise l'ellipse — sans lui, un titre long pousse la ligne et
   fait déborder la colonne. */
.tfait{display:flex;align-items:center;gap:7px;padding:5px 7px;border-radius:7px;
  background:var(--surface-2);border:1px solid var(--line-soft);margin-bottom:4px;font-size:12.5px}
.tfait-t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--ink-faint);text-decoration:line-through;text-decoration-color:var(--line)}
.tfait-q{flex:none;font-size:10.5px;font-weight:800;color:var(--ink-faint);
  background:var(--surface);border:1px solid var(--line);border-radius:5px;padding:1px 4px}
.tfait-d{flex:none;font-size:11px;color:var(--ink-faint);white-space:nowrap}
.tfait .mini{flex:none;padding:2px 6px}

/* Origine & avenants : un tableau sans en-tête, pour que les trois lignes de
   la même famille (le devis, puis ses avenants) s'alignent colonne par
   colonne. ⚠️ C'est un tableau et non une pile de `flex` PARCE QUE l'alignement
   est le sujet : six `flex` indépendants se décalent dès qu'un titre est plus
   long que l'autre. Voir la note dans facture-detail.js. */
.org-table{width:100%}
.org-table th{padding:8px 10px}
.org-table td{padding:9px 10px;border-bottom:1px solid var(--line);vertical-align:middle}
.org-table tr:last-child td{border-bottom:none}
.org-table td:first-child{width:1%;white-space:nowrap}
/* ⚠️ `width:1%` SANS `nowrap` FAIT L'INVERSE DE CE QU'ON VEUT : la colonne se
   réduit au minimum et le texte de l'étiquette se casse en cinq lignes.
   Les deux vont ensemble — « prends ta largeur naturelle, pas plus ». */
.org-table td:nth-child(2){width:1%;white-space:nowrap}   /* le type */
.org-table td:nth-child(4){width:1%;white-space:nowrap}   /* le suivi */
.org-table td:nth-child(5){width:1%;white-space:nowrap;font-variant-numeric:tabular-nums;text-align:right}
/* Les deux suivis l'un sous l'autre, alignés à gauche de leur colonne. */
.org-suivi{display:flex;flex-direction:column;align-items:flex-start;gap:4px}
.org-table td:last-child{width:1%;white-space:nowrap}
/* ⚠️ LA COLONNE D'ACTIONS A UNE LARGEUR RÉSERVÉE. Le devis porte deux
   boutons, les avenants un seul : sans largeur fixe, le 🖨 du devis tombait
   à gauche de celui des avenants, et la dernière colonne tremblait. */
.org-table td:last-child .row-act{display:flex;gap:6px;justify-content:flex-start;min-width:74px}

/* ------------------------------------------------------------
   La frise des échéances d'un chantier (fiche chantier).
   Deux lignes par échéance : le numéro et le montant, puis la date et le
   statut. ⚠️ LE MONTANT ET LE STATUT SONT ANCRÉS À DROITE, chacun sur sa
   ligne — sinon la longueur du libellé décide de leur position, et l'œil ne
   peut plus descendre la colonne sans lire.
   ⚠️ `.spacer` n'est pas une règle globale : chaque conteneur déclare la
   sienne, d'où les deux sélecteurs ci-dessous. */
.fil-l1,.fil-l2{display:flex;align-items:center;gap:8px}
.fil-l1 .spacer,.fil-l2 .spacer{flex:1}
.fil-l1{margin-bottom:3px}
.fil-lab{min-width:0;overflow-wrap:anywhere}
.fil-l1 .strong{font-variant-numeric:tabular-nums;white-space:nowrap}
/* La pastille prend la couleur du statut : payé, en retard, émis, à venir. */
.fil-fac li.ok::before{background:var(--ok)}
.fil-fac li.warn::before{background:var(--warn)}
.fil-fac li.bad::before{background:var(--bad)}
.fil-fac li.nc::before{background:var(--accent-ink)}
.fil-fac li.todo::before{background:var(--surface);border-color:var(--line)}
/* Une rangée de boutons qui ne s'étire pas : `.mc-act` met `flex:1` sur
   chacun — parfait sur un téléphone, deux barres pleine largeur sur un
   écran de bureau. ⚠️ Sous 720 px, on retrouve le comportement mobile. */
.act-rang{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
/* Des boutons empilés, chacun sur toute la largeur : l'ordre vertical dit
   l'ordre des gestes — l'action d'abord, le passage ensuite. */
.act-pile{display:grid;gap:8px}
.act-pile .btn{width:100%;justify-content:center}
@media(max-width:720px){.act-rang .btn{flex:1;min-width:110px;justify-content:center}}

/* ------------------------------------------------------------
   Le « i » d'explication, et sa bulle.
   ⚠️ La bulle est en `position:fixed` sur `document.body` : `.panel` porte
   `overflow:hidden`, une bulle interne serait coupée. Voir ui/tags.js.
   ------------------------------------------------------------ */
.aide{display:inline-flex;align-items:center;justify-content:center;
  width:17px;height:17px;flex:0 0 auto;margin-left:6px;padding:0;
  border:1px solid var(--line);border-radius:50%;background:var(--surface-2);
  color:var(--ink-faint);font:italic 700 11px/1 Georgia,'Times New Roman',serif;
  cursor:help;vertical-align:middle;transition:color .12s,border-color .12s,background .12s}
.aide:hover,.aide:focus-visible{border-color:var(--accent);color:var(--accent);
  background:var(--accent-wash);outline:none}
.aide-bulle{position:fixed;z-index:120;display:none;max-width:340px;
  background:var(--surface);color:var(--ink);border:1px solid var(--line);
  border-radius:10px;padding:11px 14px;font-size:12.5px;line-height:1.6;
  box-shadow:0 10px 30px rgba(0,0,0,.14);pointer-events:none;white-space:pre-line}
.aide-bulle.on{display:block}
/* Au doigt, une cible de 17 px ne se touche pas : on l'agrandit sans grossir
   le dessin, par une zone transparente autour. */
@media(max-width:720px){
  .aide{width:26px;height:26px;font-size:13px;margin-left:4px}
  .aide-bulle{font-size:13.5px}
}

/* ------------------------------------------------------------
   La liste des chantiers : un tableau, comme Facturation et Devis.
   ⚠️ C'ÉTAIT UNE PILE DE CARTES où chaque ligne répétait ses libellés
   — « ÉQUIPE », « PÉRIODE », « AVANCEMENT » quatre fois de suite — et où
   rien ne s'alignait : la période d'un chantier au titre long tombait vingt
   pixels à droite de celle du suivant.
   ------------------------------------------------------------ */
.ch-table{width:100%}
.ch-table tbody tr{cursor:pointer}
/* Le statut reste une couleur sur la tranche gauche : on parcourt la colonne
   du regard sans lire les étiquettes. */
.ch-table tbody td:first-child{box-shadow:inset 3px 0 0 var(--ch-bord,var(--accent))}
.ch-table td{vertical-align:middle}
.ch-presta{font-size:12.5px;font-weight:400;margin-top:3px}
.ch-sous{font-size:11px;font-weight:400;margin-top:3px}
.ch-prog{min-width:180px}
.ch-prog-l{display:flex;align-items:center;gap:9px}
.ch-prog-l .bar{flex:1;min-width:70px}
.ch-prog-l .strong{font-size:12.5px;font-variant-numeric:tabular-nums;white-space:nowrap}

/* ------------------------------------------------------------
   LE SQUELETTE D'ATTENTE (page des signalements)
   ------------------------------------------------------------
   ⚠️ IL REMPLACE DES ZÉROS, PAS UN ÉCRAN VIDE. Un « 0 » est un chiffre :
   il se lit comme une réponse, pas comme une attente. Voir `tkSquelette()`.
   La lueur s'arrête pour qui a demandé moins d'animations — les barres
   restent, et disent la même chose. */
.tk-sq{background:var(--surface-2);border-radius:5px;margin-bottom:9px;
  background-image:linear-gradient(90deg,transparent 0%,
    color-mix(in srgb,var(--ink-faint) 14%,transparent) 50%,transparent 100%);
  background-size:220% 100%;animation:tk-lueur 1.25s ease-in-out infinite}
.tk-sq:last-child{margin-bottom:0}
@keyframes tk-lueur{from{background-position:120% 0}to{background-position:-120% 0}}
@media (prefers-reduced-motion:reduce){ .tk-sq{animation:none} }

/* ------------------------------------------------------------
   LE SOMMAIRE DES RÉGLAGES
   ------------------------------------------------------------
   ⚠️ UNE CARTE PAR SUJET, ET CHACUNE DIT DÉJÀ CE QUI EST RÉGLÉ. La ligne
   `.sc-etat` porte la valeur courante — TVA 21 %, 0,095 € le SMS, position
   au pointage et au dépointage : on vérifie un réglage sans entrer dedans.
   Un sommaire qui ne porte que des titres déplace le problème d'un cran.

   ⚠️ C'EST UN <button>, PAS UNE CARTE CLIQUABLE. Le clavier l'atteint, la
   touche Entrée l'ouvre, et les lecteurs d'écran l'annoncent pour ce qu'il
   est. Le `text-align:left` et le `font:inherit` défont ce que le navigateur
   impose aux boutons — sans eux, tout le texte se centre en 13 px gris.
   ------------------------------------------------------------ */
.set-sommaire{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
.set-carte{display:flex;gap:13px;align-items:flex-start;text-align:left;font:inherit;color:inherit;
  width:100%;padding:15px 16px;border:1px solid var(--line);border-radius:12px;
  background:var(--surface);box-shadow:var(--shadow);cursor:pointer;transition:.12s}
.set-carte:hover{border-color:var(--accent);transform:translateY(-1px)}
.set-carte:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.sc-ico{flex:0 0 auto;width:34px;height:34px;border-radius:10px;background:var(--surface-2);
  border:1px solid var(--line-soft);display:grid;place-items:center;font-size:16px;line-height:1}
.sc-txt{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
.sc-titre{font-weight:700;font-size:14px;letter-spacing:-.2px}
.sc-quoi{font-size:12.5px;line-height:1.5;color:var(--ink-soft)}
.sc-etat{font-size:11.5px;color:var(--ink-faint);font-variant-numeric:tabular-nums;
  overflow-wrap:anywhere;margin-top:2px}

/* ---- la liste des messages, dans les réglages ---- */
.msg-l{display:flex;gap:12px;align-items:flex-start;padding:11px 0;border-top:1px solid var(--line-soft)}
.msg-l:first-of-type{border-top:none}
.msg-l.off .msg-titre,.msg-l.off .msg-quand{opacity:.55}
.msg-t{min-width:0;flex:1}
.msg-titre{font-weight:600;font-size:13.5px}
.msg-quand{font-size:12px;color:var(--ink-soft);margin-top:1px}
.msg-perte{font-size:11.5px;color:var(--ink-faint);line-height:1.5;margin-top:3px}
/* ⚠️ UN VRAI <button role="switch"> : le clavier l'atteint, Entrée le bascule,
   et un lecteur d'écran annonce « activé / désactivé » au lieu de « bouton ». */
.msw{flex:0 0 auto;width:40px;height:23px;border-radius:23px;border:1px solid var(--line);
  background:var(--surface-2);position:relative;cursor:pointer;transition:.15s;margin-top:1px}
.msw i{position:absolute;top:2px;left:2px;width:17px;height:17px;border-radius:50%;
  background:var(--ink-faint);transition:.15s}
.msw.on{background:var(--accent-wash);border-color:var(--accent)}
.msw.on i{left:20px;background:var(--accent)}
.msw:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Qui écrit, et dans quelle boîte on cesse de recevoir si on coupe. */
.msg-qui{font-size:11.5px;color:var(--ink-soft);margin-top:2px;font-variant-numeric:tabular-nums}
.msg-qui b{color:var(--ink);font-weight:600}
.msg-l.off .msg-qui{opacity:.55}

/* ---- le catalogue des teintes, dans les réglages ---- */
.tt-marque{padding:11px 0;border-top:1px solid var(--line-soft)}
.tt-marque:first-of-type{border-top:none}
.tt-m-tete{display:flex;align-items:center;gap:9px;margin-bottom:7px}
/* ⚠️ La croix vit DANS la puce : posée à côté, elle se décalait d'une ligne à
   l'autre selon la longueur de la référence, et on visait à côté au doigt. */
.tt-x{border:none;background:none;cursor:pointer;color:var(--ink-faint);
  font-size:11px;line-height:1;padding:0 0 0 5px}
.tt-x:hover{color:var(--bad)}
.chip .tt-x{margin-left:2px}

/* ---- le catalogue des teintes : un tableau par marque ---- */
.tt-m-tete{display:flex;align-items:center;gap:10px;margin-bottom:6px}
/* ⚠️ Le nom de la marque EST un champ : on le corrige là où on le lit,
   plutôt que derrière un bouton « éditer » qu'il faudrait deviner. */
.tt-m-nom{flex:1;min-width:0;font-weight:700;font-size:14px;border-color:transparent;
  background:transparent;padding:4px 7px}
.tt-m-nom:hover{border-color:var(--line)}
.tt-m-nom:focus{background:var(--surface);border-color:var(--accent)}
/* ⚠️ LARGEURS IMPOSÉES. Un <input> revendique une vingtaine de caractères :
   trois par ligne, et le tableau réclame 500 px qu'un téléphone n'a pas — la
   colonne ✕ sortait du panneau, qui la coupait (`.table-wrap` masque). En
   largeurs fixes, les colonnes se partagent ce qu'il y a. */
.tt-table{width:100%;font-size:13px;table-layout:fixed}
.tt-table th:nth-child(1){width:40%}
.tt-table th:nth-child(2){width:29%}
.tt-table th:nth-child(3){width:29%}
.tt-table th{font-size:10.5px;padding-bottom:5px}
.tt-table td{padding:3px 6px 3px 0;vertical-align:middle}
.tt-table input{width:100%;min-width:0;padding:5px 8px;font-size:13px}
.tt-table th:last-child, .tt-table td:last-child{width:34px;padding-right:0}
.tt-marque{padding:9px 0;border-top:1px solid var(--line-soft)}
.tt-marque:first-of-type{border-top:none}
.tt-marque.on{background:var(--surface-2);border-radius:11px;padding:11px 12px;margin:6px 0}
/* Repliée, la marque EST le bouton qui l'ouvre : on ne vise pas un chevron. */
.tt-m-ouvre{flex:1;min-width:0;display:flex;align-items:baseline;gap:9px;text-align:left;
  font:inherit;color:inherit;background:none;border:none;cursor:pointer;padding:4px 0}
.tt-m-ouvre:hover b{color:var(--accent)}
.tt-chev{color:var(--ink-faint);font-size:15px;line-height:1}
.tt-apercu{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:12px;color:var(--ink-faint);font-weight:400}

/* ============================================================
   LA PAGE D'UN SUJET DE RÉGLAGES
   ============================================================
   ⚠️ UN PANNEAU SEUL PREND TOUTE LA LARGEUR. Demandé le 20/09/2026 :
   « dans la vue desktop il faudrait une page entière et pas une page
   mobile, elle doit remplir la page. »
   ============================================================ */
.set-page{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
.set-page > :only-child{grid-column:1 / -1}
@media(max-width:1000px){.set-page{grid-template-columns:1fr}}

/* ⚠️ UNE LARGEUR PLEINE NE VEUT PAS DIRE DES CHAMPS DE 1 500 px. Un champ
   aussi large ne se lit pas, et empiler trois champs à gauche d'un panneau
   large ne fait que déplacer le vide à l'intérieur. Sur grand écran, seuls
   les CHAMPS se rangent en colonnes ; tout le reste — notes, listes, barres
   d'outils, tableaux — garde la largeur entière. */
@media(min-width:1001px){
  .set-page > .panel:only-child > .panel-body{
    display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));
    column-gap:20px;align-items:start}
  .set-page > .panel:only-child > .panel-body > :not(.field){grid-column:1 / -1}
  /* Un champ qui en contient déjà deux (Téléphone / E-mail) prend deux places. */
  .set-page > .panel:only-child > .panel-body > .field.row{grid-column:span 2}
}

/* ============================================================
   LA CLOCHE DES NOTIFICATIONS
   ============================================================ */
.cloche-h{position:relative;display:flex}
.notif-b{position:relative}
/* ⚠️ La pastille déborde du bouton : elle doit rester lisible quand la
   cloche est le seul point de l'écran qui change. */
.notif-pt{position:absolute;top:-2px;right:-3px;min-width:16px;height:16px;padding:0 4px;
  display:flex;align-items:center;justify-content:center;
  background:var(--danger,#b3261e);color:#fff;border-radius:9px;
  font-size:10px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums}
/* Le fond ferme le panneau quand on clique ailleurs — sans lui, on reste
   enfermé dans la cloche jusqu'à recliquer précisément dessus. */
.notif-fond{position:fixed;inset:0;z-index:40}
.notif-p{position:absolute;top:calc(100% + 8px);right:0;z-index:41;
  width:min(400px,calc(100vw - 24px));max-height:min(70vh,560px);
  display:flex;flex-direction:column;overflow:hidden;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;
  box-shadow:0 12px 32px rgba(0,0,0,.18)}
.notif-h{display:flex;align-items:center;gap:8px;padding:9px 12px;
  border-bottom:1px solid var(--line-soft);font-size:13px}
.notif-h .spacer{flex:1}
.notif-liste{overflow-y:auto}
.notif-l{display:flex;gap:10px;width:100%;text-align:left;padding:10px 12px;
  background:none;border:none;border-top:1px solid var(--line-soft);cursor:pointer;
  font:inherit;color:inherit}
.notif-l:first-child{border-top:none}
.notif-l:hover{background:var(--surface-2)}
/* ⚠️ Le non-lu se voit AUSSI autrement que par la couleur : un liseré à
   gauche. Une pastille rouge seule ne se distingue pas pour tout le monde. */
.notif-l.neuf{box-shadow:inset 3px 0 0 var(--accent)}
.notif-l.neuf .notif-t{font-weight:600}
.notif-i{flex:0 0 22px;font-size:14px;line-height:1.5;text-align:center}
.notif-c{min-width:0;display:flex;flex-direction:column;gap:2px}
.notif-t{font-size:12.5px;line-height:1.45}
.notif-x{font-size:11.5px;color:var(--ink-faint);line-height:1.4;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.notif-q{font-size:10.5px;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.2px}
/* Sur téléphone, le panneau prend la largeur sous le bandeau : ancré à
   droite d'un bouton de 34 px, il sortirait de l'écran. */
@media(max-width:560px){
  .notif-p{position:fixed;top:52px;left:12px;right:12px;width:auto;max-height:72vh}
}

/* Les intertitres de la liste des e-mails : ils disent OÙ l'on en est dans
   la vie d'un dossier. Discrets — ce sont des repères, pas des sections. */
.msg-phase{margin:16px 0 6px;padding-top:12px;border-top:1px solid var(--line-soft);
  font-size:10.5px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;
  color:var(--ink-faint)}
.msg-phase:first-of-type{margin-top:8px;padding-top:0;border-top:none}

/* ============================================================
   L'ÉTAT DU RENDEZ-VOUS DANS L'AGENDA
   ============================================================
   ⚠️ C'est la réponse à la seule question qu'on se pose à cet endroit —
   est-ce que c'est dans l'agenda, oui ou non ? Écrite en petit gris sous
   le champ, elle ne se voyait pas : « je vois bien que c'est signalé, mais
   ça ne se voit pas vraiment » (21/09/2026). Une pastille colorée répond
   avant qu'on ait lu la phrase. */
.agd{display:flex;align-items:flex-start;gap:10px;margin-top:10px;
  padding:10px 12px;border-radius:11px;
  background:var(--surface-2);border:1px solid var(--line-soft)}
.agd-ico{flex:0 0 22px;height:22px;display:flex;align-items:center;justify-content:center;
  border-radius:50%;font-size:12px;font-weight:700;line-height:1}
.agd-t{min-width:0;display:flex;flex-direction:column;gap:3px;line-height:1.5}
.agd-t b{font-size:13px;font-weight:650}
.agd-t span{font-size:11.5px;color:var(--ink-faint)}
.agd.ok{background:var(--ok-bg);border-color:transparent}
.agd.ok .agd-ico{background:var(--ok);color:#fff}
.agd.ok .agd-t b{color:var(--ok)}
.agd.warn{background:var(--warn-bg);border-color:transparent}
.agd.warn .agd-ico{background:var(--warn);color:#fff}
.agd.warn .agd-t b{color:var(--warn)}
.agd.attente .agd-ico{background:color-mix(in srgb,var(--ink) 9%,transparent);color:var(--ink-soft)}
/* Le repli des notifications déjà lues : discret, en pied de panneau — ce
   n'est pas une action, c'est une porte vers l'historique. */
.notif-plus{width:100%;padding:9px 12px;border:none;border-top:1px solid var(--line-soft);
  background:var(--surface-2);color:var(--ink-faint);font:inherit;font-size:11.5px;
  font-weight:500;cursor:pointer;text-align:center}
.notif-plus:hover{color:var(--ink)}

/* ============================================================
   LE CATALOGUE — prestations et matériaux
   ============================================================ */
.cat-table{width:100%;font-size:13px;table-layout:fixed}
.cat-table th{font-size:10.5px;padding-bottom:5px}
.cat-table td{padding:3px 6px 3px 0;vertical-align:middle}
.cat-table input{width:100%;min-width:0;padding:5px 8px;font-size:13px}
.cat-table th:nth-child(1){width:auto}
.cat-table th.cat-mini,.cat-table td:has(.cat-mini){width:84px}
.cat-table th:last-child,.cat-table td:last-child{width:34px;padding-right:0}
/* ⚠️ Largeurs imposées, comme pour les teintes : trois <input> par ligne
   réclament 500 px qu'un téléphone n'a pas, et la colonne ✕ sortait du
   panneau — que `.table-wrap` masque, sans rien dire. */
.cat-table th:nth-child(n+2):not(:last-child){width:86px}

/* Le sélecteur, depuis un devis */
.cat-ong{display:flex;gap:6px}
.cat-ong button{flex:1;padding:8px 10px;border:1px solid var(--line);border-radius:10px;
  background:var(--surface);color:var(--ink-soft);font:inherit;font-size:13px;font-weight:500;
  cursor:pointer}
.cat-ong button.on{background:var(--accent);border-color:var(--accent);color:#fff}
.cat-liste{max-height:min(46vh,380px);overflow-y:auto;border:1px solid var(--line-soft);
  border-radius:10px}
.cat-c{display:flex;align-items:center;gap:10px;width:100%;text-align:left;padding:9px 11px;
  background:none;border:none;border-top:1px solid var(--line-soft);cursor:pointer;
  font:inherit;color:inherit}
.cat-c:first-child{border-top:none}
.cat-c:hover{background:var(--surface-2)}
.cat-c.on{background:var(--ok-bg)}
.cat-case{flex:0 0 19px;height:19px;border:1.5px solid var(--line);border-radius:5px;
  display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;
  color:transparent}
.cat-c.on .cat-case{background:var(--ok);border-color:var(--ok);color:#fff}
.cat-n{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
.cat-n b{font-size:13px;font-weight:600}
.cat-n span{font-size:11.5px;color:var(--ink-faint);overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.cat-p{flex:0 0 auto;font-size:12.5px;font-weight:600;font-variant-numeric:tabular-nums;
  white-space:nowrap}

/* La recette d'un ouvrage, sous sa prestation */
.rec{background:var(--surface-2);border:1px solid var(--line-soft);border-radius:11px;
  padding:11px 13px;margin-top:2px}
.rec-t{font-size:11px;font-weight:600;letter-spacing:.4px;text-transform:uppercase;
  color:var(--ink-faint);margin-bottom:8px}
/* Le coût d'une unité, puis l'icône qui ouvre son détail.
   ⚠️ `nowrap` : un libellé qui se replie dans une colonne étroite gonfle
   chaque rangée du tableau — c'est le défaut qu'on corrige. */
.cat-det{display:inline-flex;align-items:center;justify-content:flex-end;gap:8px;
  white-space:nowrap;font-size:12.5px;color:var(--ink-soft);
  font-variant-numeric:tabular-nums}
.cat-det b{color:var(--ink);font-weight:600}
.cat-ico{display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:26px;padding:0;border:1px solid transparent;border-radius:7px;
  background:none;color:var(--ink-faint);cursor:pointer}
.cat-ico:hover{border-color:var(--line);background:var(--surface-2);color:var(--ink)}
.cat-ico.on{border-color:var(--accent);color:var(--accent);background:var(--surface-2)}
.cat-ico .gsi{width:15px;height:15px}

/* « Matière » et « Main d'œuvre » : deux sous-titres dans le même panneau,
   parce que c'est UNE seule question — ce que coûte une unité. */
.rec-st{font-size:11px;font-weight:600;letter-spacing:.3px;color:var(--ink-soft);
  margin:10px 0 6px}
.rec-st:first-of-type{margin-top:2px}
.rec-l{display:flex;align-items:center;gap:8px;margin-bottom:6px}
/* La ligne des heures n'a pas de sélecteur : son champ prend la place que le
   sélecteur occupe au-dessus, pour que les montants restent alignés. */
.rec-mo input{flex:0 0 88px}
.rec-l select{flex:1 1 160px;min-width:0}
.rec-l input{flex:0 0 88px}
.rec-u{flex:0 0 auto;font-size:11.5px;white-space:nowrap}
.rec-s{flex:0 0 86px;text-align:right;font-size:12.5px;font-weight:600;
  font-variant-numeric:tabular-nums}
/* ⚠️ DEUX COLONNES DE MONTANTS : ce que ça COÛTE, puis ce que ça VAUT. La
   seconde est celle qu'on lit en dernier, elle porte donc la couleur. */
.rec-v{color:var(--ok)}
.rec-l > select{margin-right:auto}
/* La ligne des heures n'a pas de sélecteur : c'est son unité qui pousse, pour
   que ses deux montants tombent sous ceux de la matière. Sans ça, ils flottent
   au milieu et les colonnes « coûte » / « vaut » ne veulent plus rien dire. */
.rec-mo .rec-u{margin-right:auto}
.rec-head{display:flex;align-items:center;gap:8px}
.rec-head > span:first-child{margin-right:auto}
.rec-head .rec-s{font-weight:500;font-size:11px;text-transform:lowercase}
.rec-vide{flex:0 0 28px}
.rec-bilan{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px;margin-top:11px;padding-top:9px;
  border-top:1px solid var(--line-soft);font-size:12.5px;color:var(--ink-soft)}
.rec-bilan b{color:var(--ink);font-variant-numeric:tabular-nums}
.rec-bilan .rec-m b{color:var(--ok)}
.rec-manque{margin:9px 0 0;padding:8px 10px;border-radius:8px;background:var(--warn-bg);
  color:var(--warn);font-size:11.5px;line-height:1.55}
.mini.on{background:var(--accent-wash,var(--surface-2));color:var(--accent);border-color:var(--accent)}
/* ⚠️ Le bilan du devis : pour nous, jamais sur le PDF ni dans l'espace client. */
.dev-bilan{margin:12px 2px 0;padding:9px 12px;border-radius:9px;background:var(--surface-2);
  font-size:12.5px;line-height:1.6}
.dev-bilan b{font-variant-numeric:tabular-nums}

/* ============================================================
   LA FRISE D'UN CLIENT
   ============================================================
   ⚠️ LES COLONNES DOIVENT S'ALIGNER D'UNE LIGNE À L'AUTRE, et deux
   tentatives l'ont manqué — la leçon vaut d'être gardée :

     1. `flex:0 0 96px` sur la date : « 21 sept. 2026 · 04:36 » débordait de
        sa case et venait se coller au libellé, pendant que les lignes sans
        heure gardaient leur marge.
     2. `display:grid` sur le `li` : chaque ligne devenait SA PROPRE grille,
        et des colonnes « auto » ne se partagent pas entre grilles
        différentes. Les libellés repartaient donc à des abscisses
        différentes selon qu'une heure était connue ou non — exactement le
        défaut qu'on croyait corriger. (Une grille partagée aurait demandé
        `subgrid` sur le `ul` ; c'est plus fragile qu'une largeur fixe pour
        un contenu dont le format est borné.)

   La réponse : UN SEUL BLOC à gauche, de largeur fixe, qui porte la date ET
   l'heure. Ce qui suit commence toujours au même endroit, sans rien devoir
   aux lignes voisines.
   ============================================================ */
.frise{list-style:none;margin:0;padding:0}
.frise li{display:flex;align-items:flex-start;gap:10px;padding:7px 4px;border-radius:8px;
  font-size:13px;line-height:1.45}
.frise li:hover{background:var(--surface-2)}
.fr-ico{flex:0 0 20px;text-align:center;color:var(--ink-faint);font-size:13px;line-height:1.45}
.fr-ico .gsi{width:14px;height:14px}
/* 152 px : « 21 sept. 2026 » (le plus long de ce format) + l'heure + leur
   écart. Le format est BORNÉ — il vient de `fdate`, pas d'une saisie. */
.fr-t{flex:0 0 152px;display:flex;align-items:baseline;gap:8px;white-space:nowrap}
.fr-d{color:var(--ink-soft);font-size:12px;line-height:1.55}
/* L'heure est poussée à DROITE du bloc : les heures s'alignent entre elles, et
   une ligne qui n'en a pas laisse un blanc — ce blanc dit lui-même qu'on ne
   la connaît pas. */
.fr-h{margin-left:auto;color:var(--ink-faint);font-size:11.5px;line-height:1.6;
  font-variant-numeric:tabular-nums}
/* ⚠️ LA DESCRIPTION EST DÉCALÉE, et séparée par un filet. Daté à gauche,
   raconté à droite : deux zones, et l'œil descend la colonne des dates sans
   lire. Le filet est le plus discret des séparateurs — une couleur de fond
   aurait fait un tableau zébré. */
.fr-q{flex:1 1 auto;min-width:0;padding-left:14px;border-left:1px solid var(--line-soft)}
.fr-q b{font-weight:600}
@media(max-width:720px){
  /* Sur téléphone : l'icône et le LIBELLÉ sur la première ligne, la date
     dessous. À 152 px de bloc fixe, il ne resterait rien pour le texte ; et
     le filet disparaît avec les deux zones, il n'aurait plus rien à séparer.

     ⚠️ `flex:1 1 0` SUR LE LIBELLÉ, PAS `1 1 100%`. À 100 %, il réclamait
     toute la largeur et passait à la ligne : l'icône restait SEULE sur la
     première ligne, et chaque événement tenait sur trois lignes au lieu de
     deux. C'est la date qui doit occuper une ligne entière (`1 1 100%`,
     placée en dernier), pas le libellé. Constaté le 21/09/2026. */
  .frise li{flex-wrap:wrap;row-gap:2px}
  .fr-q{order:2;flex:1 1 0;min-width:0;padding-left:0;border-left:none}
  .fr-t{order:3;flex:1 1 100%;margin-left:30px;gap:10px}
}

/* ============================================================
   LA JOURNÉE D'INTERVENTIONS (module)
   ============================================================
   ⚠️ CE N'EST PAS LE PLANNING DES CHANTIERS. Là-bas, des jours entiers ; ici,
   une journée découpée en créneaux, une colonne par technicien. Les fondre
   dans un même calendrier aurait mis une barre de sept jours à côté d'un
   créneau de quarante-cinq minutes.
   ============================================================ */
.iv-jour{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.iv-col{background:var(--surface-2);border:1px solid var(--line-soft);border-radius:11px;padding:10px 11px}
.iv-col-t{font-size:11.5px;font-weight:600;letter-spacing:.3px;color:var(--ink-soft);
  margin-bottom:8px;text-transform:uppercase}
.iv-creneau{background:var(--surface);border:1px solid var(--line);border-radius:9px;
  padding:8px 10px;margin-bottom:7px;cursor:pointer;font-size:13px}
.iv-creneau:hover{border-color:var(--accent)}
/* Une visite faite s'efface : ce qu'on cherche dans une journée, c'est ce
   qui reste à faire. */
.iv-creneau.faite{opacity:.55}
.iv-h{font-size:12px;color:var(--ink-soft);font-variant-numeric:tabular-nums}
.iv-m{font-weight:600;line-height:1.35;margin-top:1px}
.iv-c{font-size:12px;line-height:1.35}
/* Le compte rendu, dans l'espace du client. */
.pdoc-st{font-size:11px;font-weight:600;letter-spacing:.4px;text-transform:uppercase;
  color:var(--ink-faint);margin:12px 0 6px}
.pdoc-rap{font-size:12.5px;line-height:1.55;color:var(--ink-soft);margin-top:3px;
  padding-left:10px;border-left:2px solid var(--line-soft)}

/* ============================================================
   L'ÉCRAN DES MODULES
   ============================================================
   ⚠️ UNE LISTE, PAS UNE GRILLE DE CARTES. Première version : des
   `class="field"`, qui se rangeaient en colonnes de 330 px sur grand écran
   (voir `.set-page > .panel:only-child > .panel-body`) — tassées, le texte
   replié sur trois lignes, et la dernière carte hors écran. Ici, une simple
   `div` : la règle voisine `> :not(.field)` lui donne toute la largeur, et
   les lignes s'empilent, identiques sur ordinateur et sur téléphone.
   ============================================================ */
.mods{display:flex;flex-direction:column;gap:9px;max-width:760px}
.mod{display:flex;align-items:flex-start;gap:18px;padding:13px 15px;
  border:1px solid var(--line-soft);border-radius:12px;background:var(--surface);
  cursor:pointer;transition:border-color .12s,background .12s}
.mod:hover{border-color:var(--line)}
/* Éteint : la ligne s'efface, sans disparaître. On doit pouvoir la relire
   pour savoir ce qu'on a coupé. */
.mod.off{background:transparent}
.mod.off .mod-nom{color:var(--ink-soft)}
.mod-txt{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:3px}
.mod-nom{font-size:14px;font-weight:600;line-height:1.35}
.mod-q{font-size:12.5px;line-height:1.5;color:var(--ink-soft)}
/* Ce qu'on perd en éteignant : la phrase la plus utile de l'écran, et la
   plus discrète — on ne la lit qu'au moment d'hésiter. */
.mod-sans{font-size:11.5px;line-height:1.45;color:var(--ink-faint)}

/* ⚠️ UN INTERRUPTEUR, PAS UNE CASE À COCHER : une case sélectionne un élément
   dans une liste, un interrupteur dit allumé ou éteint. C'est une vraie
   `input[type=checkbox]` — seul son dessin change — pour garder le clavier,
   le focus et les lecteurs d'écran. La peau générale des champs est posée en
   `:where()`, de spécificité nulle : ces règles-ci l'emportent sans `!important`. */
.mod-sw{appearance:none;-webkit-appearance:none;flex:0 0 auto;margin:2px 0 0;
  width:42px;height:24px;border-radius:13px;border:none;padding:0;
  background:var(--line);position:relative;cursor:pointer;transition:background .15s}
.mod-sw::after{content:'';position:absolute;top:3px;left:3px;width:18px;height:18px;
  border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.28);
  transition:transform .15s}
.mod-sw:checked{background:var(--accent)}
.mod-sw:checked::after{transform:translateX(18px)}
.mod-sw:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

@media(max-width:720px){
  /* Même composant, resserré : la liste occupe déjà toute la largeur. */
  .mod{gap:12px;padding:12px 13px}
  .mods{gap:8px}
}

/* ------------------------------------------------------------
   La facturation d'un chantier, vue depuis la fiche du client
   ------------------------------------------------------------
   ⚠️ TROIS CHIFFRES SUR UNE LIGNE, et une barre en dessous. Un tableau de
   six colonnes aurait forcé un défilement latéral sur téléphone pour trois
   montants — or c'est exactement ce qu'on vient lire. Les chiffres passent
   à la ligne d'eux-mêmes quand la place manque.
   ------------------------------------------------------------ */
.fch{padding:12px 0;border-top:1px solid var(--line-soft);cursor:pointer}
.fch:first-child{border-top:0;padding-top:2px}
.fch-t{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.fch-n{display:flex;gap:22px;flex-wrap:wrap;margin-bottom:8px}
.fch-n span{display:flex;flex-direction:column;min-width:96px}
.fch-n b{font-size:15px;font-variant-numeric:tabular-nums}
.fch-n i{font-style:normal;font-size:11px;color:var(--ink-soft);text-transform:uppercase;letter-spacing:.04em}
@media(max-width:560px){ .fch-n{gap:14px} .fch-n span{min-width:84px} .fch-n b{font-size:14px} }

/* Les postes à prévoir d'une intervention — une liste qu'on coche. */
.postes{list-style:none;margin:0;padding:0}
.postes li{display:flex;align-items:center;gap:10px;padding:7px 0;border-top:1px solid var(--line-soft)}
.postes li:first-child{border-top:0}
.postes label{display:flex;align-items:center;gap:10px;flex:1;cursor:pointer;margin:0}
.postes input[type=checkbox]{width:18px;height:18px;flex:0 0 auto}
.postes .fait{text-decoration:line-through;color:var(--ink-soft)}

/* ------------------------------------------------------------
   Le rapport d'intervention — un champ de rédaction, pas une case
   ------------------------------------------------------------
   ⚠️ C'EST LE SEUL TEXTE DE LA FICHE QUE LE CLIENT LIRA, et souvent le
   seul souvenir de la visite dans deux ans. Dans la peau d'un champ
   ordinaire — quatre lignes, 13 px — on n'y écrivait pas trois phrases.
   ⚠️ 16 px MINIMUM : en dessous, iOS zoome la page à la mise au point et
   il faut dézoomer après chaque frappe. C'est la règle de tous les champs
   de l'application, et elle compte double ici — on écrit ce texte debout,
   sur un téléphone.
   ⚠️ `resize:vertical` ET PAS `both` : s'élargir casserait la colonne.
   ------------------------------------------------------------ */
textarea.rapport{width:100%;min-height:220px;resize:vertical;
  font-size:16px;line-height:1.7;padding:14px 16px;border-radius:12px;
  background:var(--surface);border:1px solid var(--line)}
textarea.rapport:focus{border-color:var(--accent);outline:none;
  box-shadow:0 0 0 3px var(--accent-wash)}
textarea.rapport::placeholder{color:var(--ink-faint);line-height:1.7}

/* ------------------------------------------------------------
   Le planning d'une journée d'interventions — une grille d'heures
   ------------------------------------------------------------
   ⚠️ UNE LISTE DE CARTES NE DIT PAS OÙ EST LE TROU. Trois visites empilées
   dans une colonne, on lisait les heures une par une pour deviner si un
   dépannage de 14 h tenait. Sur une grille, le VIDE se voit — et c'est
   exactement ce qu'on vient chercher en planifiant.
   ⚠️ LA GRILLE DÉFILE LATÉRALEMENT DANS SA PROPRE BOÎTE, jamais la page :
   à six techniciens, les colonnes deviendraient illisibles autrement.
   ------------------------------------------------------------ */
.ivp{display:flex;gap:0;overflow-x:auto;border:1px solid var(--line);
  border-radius:12px;background:var(--surface);box-shadow:var(--shadow)}
.ivp-axe{flex:0 0 58px;border-right:1px solid var(--line)}
.ivp-col{flex:1 0 190px;min-width:0;border-right:1px solid var(--line-soft)}
.ivp-col:last-child{border-right:0}
.ivp-tete{height:34px;display:flex;align-items:center;gap:6px;padding:0 10px;
  font-size:12.5px;font-weight:800;border-bottom:1px solid var(--line);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ivp-piste{position:relative}
.ivp-ligne{position:absolute;left:0;right:0;height:0;border-top:1px solid var(--line-soft)}
.ivp-h{position:absolute;left:0;right:6px;transform:translateY(-50%);
  text-align:right;font-size:11px;color:var(--ink-faint);
  font-variant-numeric:tabular-nums}
/* Une visite sans heure : elle n'a pas de place sur l'axe, mais elle existe.
   ⚠️ LA BANDE A LA MÊME HAUTEUR DANS TOUTES LES COLONNES, l'axe compris —
   rendue seulement là où il y a quelque chose, elle pousse la piste de cette
   colonne vers le bas et les traits d'heures cessent de coïncider. */
.ivp-sans{display:flex;flex-direction:column;gap:4px;padding:6px 6px 0;
  box-sizing:border-box;overflow:hidden}
/* ⚠️ PLEINE LARGEUR, comme une visite datée : elle tenait dans une pastille de
   la largeur de son texte, tronquée au premier nom un peu long — or c'est
   justement la visite qu'on cherche à caser. */
.ivp-nh{border:1px dashed var(--warn);background:var(--warn-bg);color:var(--ink);
  border-radius:8px;padding:4px 7px;font-size:11.5px;line-height:1.3;cursor:grab;
  overflow:hidden;min-height:0}
.ivp-nh b{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.04em;
  color:var(--warn)}
.ivp-nh span{font-weight:700;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivp-nh i{display:block;font-style:normal;color:var(--ink-soft);font-size:10.5px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivp-ev{position:absolute;overflow:hidden;cursor:pointer;
  border-radius:8px;padding:4px 7px;font-size:11.5px;line-height:1.35;
  background:var(--accent-wash);border-left:3px solid var(--accent);color:var(--ink)}
.ivp-ev b{font-variant-numeric:tabular-nums;margin-right:4px}
.ivp-ev i{display:block;font-style:normal;color:var(--ink-soft);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivp-ev.faite{background:var(--ok-bg);border-left-color:var(--ok);opacity:.8}
.ivp-ev.repasser{background:var(--warn-bg);border-left-color:var(--warn)}
/* ⚠️ LE CLIENT EST LA LIGNE QU'ON LIT — « chez qui je vais » est la question
   du planning. Il était en gris, en troisième position, et se coupait. */
.ivp-ev .ivp-cli{font-weight:700;display:inline}
.ivp-ev u{display:block;text-decoration:none;font-size:10.5px;color:var(--ink-faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivp-ev.mobile{cursor:grab}
.ivp-ev.mobile:active{cursor:grabbing}
/* La colonne qui recevra le dépôt se signale — sans quoi on lâche à l'aveugle. */
.ivp-col.survol{background:var(--accent-wash)}
.ivp-col.survol .ivp-tete{color:var(--accent)}

/* ------------------------------------------------------------
   La semaine — sept jours, tous les entretiens
   ------------------------------------------------------------
   ⚠️ ELLE NE SE DÉCOUPE PAS PAR PERSONNE : sept colonnes de techniciens sur
   sept jours donneraient quarante-neuf cases illisibles. La semaine répond à
   « quand », la journée répond à « qui ».
   ------------------------------------------------------------ */
.ivp-sem{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:12px;
  overflow:hidden;box-shadow:var(--shadow)}
.ivp-jr{background:var(--surface);min-height:150px;display:flex;flex-direction:column}
.ivp-jr.auj{background:var(--accent-wash)}
.ivp-jr.survol{background:var(--accent-wash);outline:2px solid var(--accent);outline-offset:-2px}
.ivp-jt{padding:7px 9px;font-size:12px;font-weight:800;cursor:pointer;
  border-bottom:1px solid var(--line-soft);display:flex;gap:6px;align-items:center;
  text-transform:capitalize}
.ivp-jt:hover{color:var(--accent)}
.ivp-jl{padding:6px;display:flex;flex-direction:column;gap:5px;flex:1}
.ivp-jc{border-radius:8px;padding:5px 7px;font-size:11px;line-height:1.35;cursor:pointer;
  background:var(--accent-wash);border-left:3px solid var(--accent);color:var(--ink)}
.ivp-jc.faite{background:var(--ok-bg);border-left-color:var(--ok);opacity:.85}
.ivp-jc b{font-variant-numeric:tabular-nums;margin-right:4px}
.ivp-jc span{font-weight:700;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivp-jc em{display:block;font-style:normal;font-size:10.5px;color:var(--ink-soft);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ivp-jc u{display:block;text-decoration:none;font-size:10px;color:var(--ink-faint)}
.ivp-jc u.sans{color:var(--warn)}
.ivp-vide{margin:0;color:var(--ink-faint);font-size:11px;text-align:center;padding:6px 0}

/* ------------------------------------------------------------
   UNE LISTE DE JOURS — la forme commune aux deux plannings
   ------------------------------------------------------------
   ⚠️ UNE SEULE FAMILLE POUR LA SEMAINE DES INTERVENTIONS ET CELLE DU
   PEINTRE. *Deux écrans qui répondent à la même question et ne se
   ressemblent pas obligent à réapprendre le second* — et la semaine de
   « Mon planning » coulait justement sans séparation, chaque jour se
   confondant avec le précédent.
   ⚠️ SEPT COLONNES DANS 390 px FONT CINQUANTE PIXELS PAR JOUR : « Cl… »,
   « En… », et le nom du technicien qui déborde sur le jour voisin. Sixième
   retour du même défaut — des colonnes ne tiennent pas dans un téléphone.
   ⚠️ LES JOURS VIDES RESTENT, en une ligne : le vide est ce qu'on vient
   chercher sur un planning.
   ------------------------------------------------------------ */
.dayl{display:flex;flex-direction:column;gap:10px}
.dayl-j{border:1px solid var(--line);border-radius:12px;background:var(--surface);
  overflow:hidden;box-shadow:var(--shadow)}
.dayl-j.auj{border-color:var(--accent)}
.dayl-t{display:flex;align-items:center;gap:8px;padding:10px 12px;cursor:pointer;
  font-size:13.5px;text-transform:capitalize}
.dayl-j.auj .dayl-t{background:var(--accent-wash)}
.dayl-t b{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dayl-c{border-top:1px solid var(--line-soft);padding:10px 12px;cursor:pointer;
  border-left:3px solid var(--accent)}
.dayl-c.faite{border-left-color:var(--ok);background:var(--ok-bg)}
.dayl-ch{display:flex;align-items:center;gap:8px;font-size:12px;
  font-variant-numeric:tabular-nums;color:var(--ink-soft)}
.dayl-ch .spacer{flex:1}
.dayl-cc{font-weight:800;font-size:14px;margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dayl-cm{font-size:12.5px;color:var(--ink-soft);margin-top:1px}
.dayl-ct{display:flex;align-items:center;gap:8px;font-size:12px;
  color:var(--ink-faint);margin-top:7px}
.dayl-ct.sans{color:var(--warn);font-weight:700}

/* ⚠️ LE MOIS SUR TÉLÉPHONE SE PARCOURT, IL NE SE LIT PAS : à cinquante
   pixels de large, une référence devient « TAVER… ». Des points de couleur
   répondent à « quand suis-je pris », et la légende dit le reste. */
.mp-pts{display:flex;gap:3px;flex-wrap:wrap;justify-content:center;margin-top:3px}
.mp-pts span{width:7px;height:7px;border-radius:50%;flex:0 0 auto}

/* Le journal des corrections d'un pointage — replié, mais présent.
   ⚠️ REPLIÉ ET NON CACHÉ : on ne le lit qu'en cas de doute, mais il doit se
   trouver sans le chercher, sur la ligne même de la journée concernée. */
.pt-jrn{margin-top:6px;font-size:11.5px}
.pt-jrn summary{cursor:pointer;color:var(--warn);font-weight:700}
.pt-jl{display:flex;flex-wrap:wrap;gap:8px;padding:6px 0;border-top:1px solid var(--line-soft)}
.pt-jl i{font-style:normal;color:var(--ink-faint)}

/* Le client d'une intervention : la liste prend la place, le bouton la sienne.
   ⚠️ PAS UNE `.row` : sous 560 px elle passe en une colonne, et le bouton
   s'étalait sous le sélecteur comme un second champ. */
.iv-cli{display:flex;gap:8px;align-items:stretch}
.iv-cli select{flex:1;min-width:0}
.iv-cli .btn{flex:0 0 auto;white-space:nowrap}

/* Le choix de la barre du bas : le rang à gauche, la flèche à droite. */
.mb-l{display:flex;align-items:center;gap:6px}
.mb-l .btn{gap:8px}

/* Les pastilles de personne, sur téléphone */
.ivp-chips{display:flex;gap:6px;overflow-x:auto;padding-bottom:8px;margin-bottom:8px}
.ivp-chip{flex:0 0 auto;border:1px solid var(--line);background:var(--surface);
  color:var(--ink);border-radius:999px;padding:7px 12px;font-size:12.5px;
  font-family:inherit;cursor:pointer;display:flex;gap:6px;align-items:center;min-height:36px}
.ivp-chip.act{background:var(--accent);border-color:var(--accent);color:#fff}
.ivp-chip span{font-size:11px;opacity:.8}

/* ------------------------------------------------------------
   Une galerie de vignettes — les photos d'une intervention
   ------------------------------------------------------------
   ⚠️ `auto-fill` ET PAS `auto-fit` : avec une seule photo, `auto-fit`
   étire la vignette sur toute la largeur du panneau, et une photo de
   filtre à 900 px de large se lit comme une illustration de magazine.
   ------------------------------------------------------------ */
.gal{display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:10px}
.gal-v{margin:0;border:1px solid var(--line);border-radius:10px;overflow:hidden;
  background:var(--surface-2)}
.gal-v img{display:block;width:100%;height:110px;object-fit:cover;cursor:zoom-in}
.gal-v figcaption{display:flex;align-items:center;gap:6px;padding:5px 7px;font-size:11px}
.gal-v figcaption .muted{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ------------------------------------------------------------
   Les visites dans les plannings
   ------------------------------------------------------------
   ⚠️ ELLES S'AJOUTENT À LA CASE, elles ne la remplacent pas : on peut
   passer une heure chez quelqu'un le matin et être sur un chantier
   l'après-midi. Une case vide se lit comme du temps libre — c'est le
   défaut qu'on corrige, pas un détail d'affichage.
   ------------------------------------------------------------ */
.pcell-iv{display:flex;flex-wrap:wrap;gap:3px;margin-top:3px}
.pcell-ivp{border:1px solid var(--accent);background:var(--accent-wash);
  color:var(--accent-ink,var(--accent));border-radius:7px;padding:1px 5px;
  font-size:10.5px;font-weight:700;font-family:inherit;cursor:pointer;
  font-variant-numeric:tabular-nums;line-height:1.5}
.pcell-ivp.fait{border-color:var(--ok);background:var(--ok-bg);color:var(--ok)}
.pcell.libre-iv{min-height:6px;background:transparent;border:0}
.mp-iv{list-style:none;margin:4px 0 0;padding:0;display:flex;flex-direction:column;gap:3px}
.mp-iv li{display:flex;gap:7px;align-items:baseline;font-size:12.5px;cursor:pointer;
  padding:3px 7px;border-radius:7px;background:var(--accent-wash)}
.mp-iv b{font-variant-numeric:tabular-nums;min-width:38px}
.mp-iv .muted{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ⚠️ LA MÊME CARTE, DEUX LARGEURS, UNE SEULE RÈGLE. `auto-fit` à 150 px
   donne deux colonnes à 380 px et cinq sur un grand écran : la carte du
   téléphone et la ligne du bureau sont le MÊME objet, sans media query à
   tenir d'accord avec le reste. La largeur qui compte est celle du PANNEAU,
   pas celle de l'écran — même raison que les bandes de la page Prospects. */
/* ⚠️ UNE FICHE DE CONTACT SE LIT COMME LES COORDONNÉES DU CLIENT — même
   liste de définitions, même densité. Les contacts s'enchaînent dans un seul
   panneau : un filet les sépare, et le premier n'en porte pas. */
.ctc-f + .ctc-f{border-top:1px solid var(--line-soft);margin-top:14px;padding-top:14px}
.ctc-h{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.ctc-h .spacer{flex:1}
