/**
 * planning-affaire.css — LA FEUILLE DU PLANNING D'UNE AFFAIRE.
 *
 * La jumelle de `modules/planning-affaire.js`, et pour la même raison : l'écran
 * vit dans DEUX apps (la fenêtre de plan, l'onglet d'airfact) et il ne doit en
 * exister qu'un exemplaire. Elle est SYMLINKÉE par
 * `php cli/sync-app-symlinks.php --apply`, comme les 27 autres feuilles du
 * socle — le MÊME inode dans les deux apps, mesuré par
 * `plan/cli/probe-un-seul-exemplaire.js`.
 *
 * Elle porte AUSSI la boîte du roster (`.pl-people-*`, `.pl-person-*`), qui
 * sert ici ET dans la modale d'allocation de plan : une boîte, une apparence.
 *
 * ⚠ LE PRÉFIXE `pl-` EST HÉRITÉ et il reste. Le renommer toucherait le module,
 * trois sondes et deux vues pour zéro changement de comportement — et le
 * préfixe ne ment pas : ces classes n'appartiennent à personne d'autre.
 *
 * Les couleurs viennent des tokens du socle (`components/tokens.css`) : aucun
 * hex n'entre ici.
 */

/* ═══ LA SYNTHÈSE — LE VERDICT, AVANT TOUTE RANGÉE (12-09-2026) ═══════════
   « il faut simplifier cette page, on comprend rien » (Olivier).

   L'écran ouvrait sur un graphe d'ATELIER puis vingt-neuf rangées, et ne disait
   NULLE PART ni où l'affaire atterrit, ni quand elle finit — deux réponses qui
   se déduisaient de données DÉJÀ chargées. Trois lignes, en tête, et rien
   d'autre : le détail vit dans les rangées, à dix centimètres en dessous. */
.pl-synthese.is-vide { display: none; }
.pl-synthese {
    margin-bottom: 0.75rem;
    padding: 0.6rem 0.75rem 0.65rem;
    background: var(--color-surface-2);
    border-radius: 6px;
    /* LE FILET PORTE LE VERDICT. Il est neutre par défaut et ne devient rouge
       que sous `.is-depasse` — une couleur permanente ne signale rien. */
    border-left: 3px solid var(--border);
}
.pl-synthese:has(.pl-synth-verdict.is-depasse) { border-left-color: var(--error); }
.pl-synth-verdict {
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.3rem 0.5rem;
}
.pl-synth-phrase {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
/* ⚠ L'ENCRE EST LE CRAN `-fg`, PAS LA PASTILLE. `--error` est la couleur d'une
   PUCE ; posée en TEXTE sur `--color-surface-2` elle rend **3,42:1** — mesuré
   dans Chromium par `probe-ecran-planning-affaire.js` [3c], sous le seuil de
   4,5 du socle. C'est le plus gros chiffre de l'écran : il serait le moins
   lisible. `--state-red-fg` monte à 7,55:1. */
.pl-synth-verdict.is-depasse .pl-synth-phrase { color: var(--state-red-fg); }
.pl-synth-sous {
    margin: 0.15rem 0 0;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
/* LES DATES DE FIN. Elles n'existaient nulle part sur cet écran : la réponse à
   « quand la pose est-elle finie ? » vivait dans une cellule « Jusqu'au », au
   milieu d'un tableau de huit colonnes, sur la DERNIÈRE série de la phase. */
.pl-synth-dates {
    margin: 0.4rem 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem 1.1rem;
}
.pl-synth-dates li { display: flex; align-items: baseline; gap: 0.35rem; font-size: 0.75rem; }
.pl-synth-phase { color: var(--text-muted); }
.pl-synth-plage { color: var(--text-secondary); font-variant-numeric: tabular-nums; }

/* ═══ LA CHARGE DE L'ATELIER — OUVERTE, OU ABSENTE ═══════════════════════
   Elle répond à « l'atelier tient-il ? » et c'est le SEUL endroit qui dit OÙ ça
   déborde. Elle a été repliée une demi-journée le 12-09-2026 puis ré-ouverte le
   même jour : un repli dont l'étiquette dit « aucune journée au-dessus de la
   capacité » ne s'ouvre jamais.

   ⚠ LE COÛT VERTICAL SE PAIE AILLEURS : le bloc porte `hidden` tant qu'il n'y a
   aucune charge à mesurer (254 affaires sur 282 au 12-09-2026).

   ⚠ ET IL N'A PLUS D'EN-TÊTE (Olivier, le soir : « supprimer ça, c'est du
   bruit »). `.pl-charge-resume` portait « Charge de l'atelier » et le compte des
   journées au-dessus — le RÉSUMÉ du repli, qui lui a survécu et répétait le
   titre que le graphe écrivait juste en dessous. Cinq lignes se succédaient
   avant la première barre ; il n'en reste aucune. */
.pl-charge-bloc { margin-bottom: 0.75rem; }

/* ═══ LA PHASE SE REPLIE ══════════════════════════════════════════════════
   Le chevron est un `<button>` : ce qui agit en est un, au clavier comme au
   lecteur d'écran. Il porte le NOM de la phase, parce que la cible d'un clic
   doit faire la taille de ce qu'elle désigne — un chevron de 10 px tout seul
   est une cible qu'on rate. */
.pl-phase-plier {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.1rem 0.2rem 0.1rem 0;
    background: none;
    border: 0;
    cursor: pointer;
    color: inherit;
    font: inherit;
}
.pl-phase-chevron {
    display: inline-flex;
    color: var(--text-muted);
    transition: transform 0.12s ease;
}
.pl-plan-phase.is-ouverte .pl-phase-chevron { transform: rotate(90deg); }
.pl-phase-plier:hover .pl-phase-nom { color: var(--text); }

/* CE QUE LE REPLI CACHERAIT, DIT SUR LA RANGÉE. Un badge « Surcharge » vit sur
   une rangée de SÉRIE : replié, il partait avec elle — on aurait remplacé un
   écran illisible par un écran muet. */
.pl-phase-note {
    flex: 0 0 auto;
    font-size: 0.7rem;
    color: var(--text-muted);
    text-transform: none;
    letter-spacing: normal;
    white-space: nowrap;
}
.pl-phase-note.is-avert { color: var(--state-amber-fg); font-weight: 600; }
/* HORS DEVIS — des heures FAITES, aucune vendue, aucune planifiée. Ce n'est pas
   une phase qu'on aurait oublié de planifier : c'est du travail que personne
   n'a vendu, et ça ne se lit pas comme un oubli. */
.pl-phase-hors {
    flex: 0 0 auto;
    padding: 0.05rem 0.35rem;
    border-radius: 3px;
    background: var(--state-amber-bg);
    color: var(--state-amber-fg);
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* L'ÉCART D'ATTERRISSAGE — le chiffre qui décide, et il porte son SIGNE.
   ⚠ Sans budget il n'y a pas d'écart, et c'est différent d'un écart NUL : la
   rangée se tait plutôt que d'écrire « 0 » (le module ne rend alors rien). */
.pl-bilan-ecart {
    flex: 0 0 auto;
    padding: 0.05rem 0.35rem;
    border-radius: 3px;
    font-size: 0.72rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-transform: none;
    letter-spacing: normal;
    white-space: nowrap;
}
.pl-bilan-ecart.is-depasse { background: var(--state-red-bg); color: var(--state-red-fg); }
.pl-bilan-ecart.is-sous    { background: var(--state-green-bg); color: var(--state-green-fg); }
.pl-bilan-ecart.is-tenu    { background: none; color: var(--text-muted); font-weight: 400; padding-left: 0; }

/* « PERSONNE » — le mot, jamais le tiret. Le tiret se lit « rien à signaler » ;
   ici il signale une journée planifiée que personne ne fera. */
.pl-qui-vide { color: var(--state-amber-fg); }

/* ── LA BOÎTE DU ROSTER — « Qui travaille ? » ─────────────────────────────── */
/* ⚠ PAS DE BORDURE ICI (Olivier, 12-09-2026 : « double bordure pas
   nécessaire »). La boîte vit TOUJOURS dans un `.form-fieldset`, qui porte
   déjà la sienne et son libellé : un second cadre à 4 px du premier dessinait
   un champ dans un champ, pour un contenu qui n'est ni l'un ni l'autre — c'est
   la liste du roster, et le fieldset dit déjà où elle commence. */
.pl-people-box {
    padding: 0.15rem 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 0.1rem 0.75rem;
    font-size: 0.85rem;
}
.pl-person-item { display: flex; align-items: center; gap: 0.45rem; padding: 0.15rem 0; cursor: pointer; }
.pl-person-item input { margin: 0; }
.pl-person-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-person-item.is-absent .pl-person-name { color: var(--text-secondary); }
.pl-person-abs { color: var(--warning-hover); font-size: 0.75rem; white-space: nowrap; }
/* « voir les autres fonctions (16) » : seize personnes d'un AUTRE métier sur
   une allocation, c'est l'exception, ça vaut un clic. Le groupe de la fonction
   concernée, lui, n'est jamais replié. */
.pl-people-plus {
    padding: 0.15rem 0.3rem;
    border: none;
    background: none;
    font: inherit;
    font-size: 0.75rem;
    color: var(--primary);
    text-decoration: underline;
    cursor: pointer;
}
/* Les autres prennent leur propre rang : mêlées aux premières, on ne verrait
   plus où s'arrête le métier concerné. La boîte est une GRILLE — il faut donc
   `grid-column: 1 / -1` pour traverser toutes ses colonnes (`flex-basis: 100%`
   n'y veut rien dire), et le groupe redéclare la même grille pour que les
   autres s'alignent sur les premières. */
.pl-people-others {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 0.1rem 0.75rem;
    margin-top: 0.15rem;
    padding-top: 0.3rem;
    border-top: 1px solid var(--border);
}
/* Le bouton traverse lui aussi la grille : au milieu d'une colonne, on le
   prendrait pour une personne. */
.pl-people-plus { grid-column: 1 / -1; text-align: left; }


/* ── L'ÉCRAN DU PLANNING D'UNE AFFAIRE ───────────────────────────────────── */
/* LE BILAN DES HEURES (12-09-2026) — quatre chiffres, une ligne par phase.
   Une GRILLE, pas un tableau : ce ne sont pas des entités qu'on trie ou filtre,
   ce sont quatre agrégats par phase. `table_list()` n'a rien à voir ici, et la
   règle `handrolled-table-shell` ne s'applique pas — il n'y a aucune <table>. */
/* LA TÊTE DE LA FENÊTRE, EN DEUX MOITIÉS (12-09-2026, décision Olivier).
   À gauche le BILAN — ce qui est ENREGISTRÉ, immobile pendant qu'on tape. À
   droite la CHARGE, qui SUIT le brouillon. Elles se replient l'une sous l'autre
   quand la fenêtre est étroite : la charge est une lecture, elle cède la
   première. */
/* ⚠ LA TÊTE N'A PLUS QU'UNE MOITIÉ (12-09-2026, Olivier : « alléger la moitié
   droite, trop lourde, trop grosse »). Elle était en deux : le BILAN à droite —
   une barre et quatre chiffres par phase, plus un total — et la CHARGE à gauche.

   Le bilan est DISSOUS dans le tableau, sur la rangée de regroupement de chaque
   phase : c'est là que la question « où en est cette phase ? » se pose. Il
   nommait chaque phase une SECONDE fois, à trente centimètres de la rangée qui
   la nomme déjà, et il prenait la moitié de la largeur à la charge — seule vraie
   série temporelle de cette fenêtre, qui en manquait : à mi-largeur sur 60
   semaines, il avait fallu éclaircir son axe à huit étiquettes.

   Il n'y a donc plus de grille à deux colonnes, plus de `stretch` à accorder,
   plus de repli à 1000 px : un seul bloc pleine largeur, à toutes les tailles. */
.pl-tete-affaire {
    display: block;
    margin-bottom: 0.75rem;
}

/* ═══ L'HISTOGRAMME DE CHARGE — TOUT L'ATELIER, SEMAINE PAR SEMAINE ═══════
   « Je veux juste une représentation graphique. Les mois et les semaines en
   abscisses. Des histogrammes, vert s'il n'y a pas de problème de capacité,
   rouge quand il y en a un, avec le nombre d'heures et le pourcentage de
   remplissage. Fais simple et beau. » (Olivier, 12-09-2026, cinquième passe.)

   CE QUE LES QUATRE PASSES PRÉCÉDENTES ONT PAYÉ, en une phrase : le bloc
   essayait de dire DEUX choses dans une seule forme — les heures de l'AFFAIRE
   et la capacité de l'ATELIER. Barres empilées, trait de capacité, matrice
   fonction × période : chaque version produisait deux nombres en heures sous le
   même numéro de semaine, et ces deux nombres se lisaient comme un désaccord.

   ⚠ LA HAUTEUR EST UN VOLUME D'HEURES, jamais un taux. Un taux PLAFONNÉ à 100 %
   peignait deux semaines de 24 h l'une pleine et l'autre à moitié — « pourquoi
   le même nombre d'heures et pas la même taille de rectangle ? ». L'échelle est
   commune à toutes les colonnes et couvre AUSSI la capacité, sans quoi la piste
   d'une semaine creuse sortirait du cadre.

   ⚠ LA CAPACITÉ EST UNE PISTE PLEINE, PAS UN TRAIT. Comparer deux hauteurs se
   fait ; voir une barre DÉPASSER DE SA PISTE ne se fait pas, ça se constate. */
.pl-charge {
    padding: 0.6rem 0.7rem 0.5rem;
    /* ⚠ BLANC, ET C'EST STRUCTUREL. La piste de capacité est un gris pâle
       (`--color-surface-2`) : posée sur le même gris, elle disparaîtrait, et
       avec elle la moitié du dessin. */
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.pl-charge-bloc > .pl-tete-affaire { margin-bottom: 0; }
.pl-charge-vide { font-size: 0.78rem; color: var(--text-muted); font-style: italic; }

/* Elle n'apparaît QUE pendant un brouillon, pour dire que ces barres ne sont
   plus l'atelier posé mais ce que l'enregistrement produirait. */
.pl-charge-sous { font-size: 0.7rem; color: var(--text-muted); font-style: italic; margin-bottom: 0.35rem; }

/* ⚠ LE CADRE DÉFILE, LA GRILLE NON. Une affaire de 42 semaines fait 42
   colonnes : à 26 px, aucune ne porte « 268h » et « 104% ». Une colonne a donc
   un PLANCHER, et c'est le cadre qui glisse. Une étiquette tient, ou elle n'est
   pas là — l'éclaircie d'une colonne sur deux était la parade d'avant, et elle
   se mesurait mal (le texte compte autant que la largeur).
   ⚠ `overflow-y: hidden` EST EXPLICITE : dès qu'un axe cesse d'être `visible`,
   l'autre passe en `auto` tout seul, et on hériterait d'un ascenseur vertical
   fantôme sur un contenu dont la hauteur est pourtant fixée. */
.pl-hist-cadre {
    overflow-x: auto;
    overflow-y: hidden;
    /* Le geste à deux doigts reste DANS l'histogramme : ni enchaînement vers la
       page, ni rebond élastique (15-09-2026 — cf. app-core/base.css). */
    overscroll-behavior-x: none;
    padding-bottom: 2px;
}

/* ── DEUX MÉTIERS, DEUX DESSINS, UN SEUL ASCENSEUR ─────────────────────────
   « Il faut séparer en 2 graphes, un pour la fab un pour la pose » (Olivier,
   12-09-2026). Les deux vivent dans le MÊME cadre : deux cadres qui
   défileraient chacun de leur côté montreraient deux semaines différentes
   l'une au-dessus de l'autre, et on comparerait deux moments en croyant
   comparer deux métiers.

   ⚠ `min-width: max-content` EST CE QUI REND LE TITRE COLLANT UTILE. Sans lui,
   la section fait la largeur du cadre VISIBLE : `sticky` n'a plus qu'un écran
   de course et le nom du métier s'en va au premier glissement. Elle reste
   néanmoins extensible — à quelques semaines, la grille remplit la largeur
   comme avant (`1fr`). */
.pl-hist-metier { min-width: max-content; }
.pl-hist-metier + .pl-hist-metier { margin-top: 0.7rem; }

/* Le nom du métier — celui du catalogue, donc « Pose » et non « installation ».
   Il ne s'écrit QUE quand il y a deux dessins : seul, un histogramme de charge
   n'a rien à nommer (l'en-tête de ce bloc a été retirée le 12-09 au matin —
   « supprimer ça, c'est du bruit »). */
.pl-hist-titre {
    position: sticky;
    left: 0;
    display: inline-block;
    margin: 0 0 0.15rem;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* ⚠ DEUX DESSINS DOIVENT TENIR SUR LE MÊME ÉCRAN QUE LE PREMIER. Le second
   n'est pas un appoint : une fabrication en surcharge peut être dessous. Seule
   la rangée de barres cède (7rem → 5.5rem) — les étiquettes, elles, gardent
   leur taille : une barre plus courte reste lisible, un chiffre plus petit ne
   l'est plus. */
.pl-hist-cadre.est-multi .pl-hist { grid-template-rows: auto 5.5rem auto auto; }
.pl-hist {
    display: grid;
    grid-template-columns: repeat(var(--pl-n, 1), minmax(3.25rem, 1fr));
    /* valeurs · barres · semaines · mois */
    grid-template-rows: auto 7rem auto auto;
    align-items: stretch;
    column-gap: 3px;
    font-size: 0.72rem;
}

/* ── RANGÉE 1 : le volume, puis le remplissage ─────────────────────────── */
.pl-hist-val {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    min-width: 0;
    padding-bottom: 0.2rem;
    line-height: 1.2;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.pl-hist-h { font-weight: 700; color: var(--text-primary); }
/* ⚠ L'ENCRE EST LE CRAN `-fg`, jamais le `-dot`. Le `-dot` est une teinte de
   PASTILLE : posé en texte, `--state-green-dot` tombe à 2,5:1 sur blanc. */
.pl-hist-pct { font-size: 0.66rem; font-weight: 600; color: var(--state-green-fg); }
.pl-hist-val.est-over .pl-hist-pct { color: var(--state-red-fg); }

/* ── RANGÉE 2 : la barre, dans sa capacité ─────────────────────────────── */
.pl-hist-piste { position: relative; min-width: 0; }
.pl-hist-dispo {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    background: var(--color-surface-2);
    border-radius: 3px 3px 0 0;
}
/* La barre est plus ÉTROITE que sa piste : c'est ce qui laisse voir la piste de
   part et d'autre, donc ce qui rend le « il reste de la place » visible. */
.pl-hist-barre {
    position: absolute;
    left: 18%; right: 18%; bottom: 0;
    background: var(--state-green-dot);
    border-radius: 3px 3px 0 0;
}
.pl-hist-barre.est-over { background: var(--state-red-dot); }
/* Capacité inconnue : ni vert ni rouge — on ne peint pas un verdict qu'on n'a
   pas. Le pourcentage écrit « — » pour la même raison. */
.pl-hist-barre.est-inconnu { background: var(--state-slate-dot); }

/* ── LA COUPURE : CETTE AFFAIRE, ET LES AUTRES ─────────────────────────────
   « Afficher heures de l'affaire + heures des autres affaires + capacité »
   (Olivier, 12-09-2026). Mesuré sur l'affaire 35 : la semaine 43 porte 707 h,
   dont 160 h à elle — les 547 autres viennent de SEPT autres affaires. Sans la
   coupure, une colonne rouge se lit « cette affaire déborde » alors qu'elle n'y
   est que pour un quart.

   ⚠ LA COULEUR RESTE LE VERDICT, LA TEINTE DIT À QUI C'EST. Donner une couleur
   propre à « cette affaire » ferait trois variables dans une barre, et la
   question posée ici est « est-ce que ça tient ? ».

   ⚠ PAS D'`opacity`, ET PAS D'ALPHA : un segment translucide est un TROU — il
   laisserait voir la piste de capacité au travers, et la frontière des deux
   parts changerait de teinte selon qu'on est au-dessus ou en dessous d'elle.
   `color-mix` avec la SURFACE rend une teinte pleine. */
.pl-hist-barre.est-autres { background: color-mix(in srgb, var(--state-green-dot) 30%, var(--surface)); }
.pl-hist-barre.est-autres.est-over { background: color-mix(in srgb, var(--state-red-dot) 30%, var(--surface)); }
.pl-hist-barre.est-autres.est-inconnu { background: color-mix(in srgb, var(--state-slate-dot) 30%, var(--surface)); }
/* ⚠ LE SEGMENT DU BAS PERD SON ARRONDI QUAND IL EST COUPÉ : un sommet arrondi
   au MILIEU d'une barre se lit comme une seconde barre posée dessus. Seul le
   haut de la colonne s'arrondit — et quand l'affaire est seule, elle EST le
   haut, donc elle le garde. */
.pl-hist-barre.est-moi.is-coupee { border-radius: 0; }

/* ── RANGÉE 3 : les semaines ───────────────────────────────────────────── */
.pl-hist-sem {
    padding-top: 0.25rem;
    font-size: 0.66rem;
    color: var(--text-muted);
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border-top: 1px solid var(--border);
}
.pl-hist-sem.est-over { color: var(--state-red-fg); font-weight: 600; }

/* ── RANGÉE 4 : les mois ───────────────────────────────────────────────── */
/* ⚠ MÊME GRILLE, DONC MÊMES COLONNES. La bande a vécu dans un second conteneur
   aligné par `flex-grow` : elle dérivait d'une gouttière, et il fallait MESURER
   l'écart pour le prouver. En quatrième rangée de la même grille, elle ne peut
   pas se décaler de ses semaines. */
.pl-hist-mois {
    margin-top: 0.3rem;
    padding: 0.15rem 0.25rem;
    background: var(--color-surface-2);
    border-radius: 3px;
    font-size: 0.66rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── LA LÉGENDE ────────────────────────────────────────────────────────── */
.pl-charge-legende {
    display: flex;
    align-items: center;
    /* ⚠ ELLE REPLIE : sans repli, elle débordait du bloc à 622 px — et une
       légende coupée ne légende plus rien. */
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-top: 0.45rem;
    font-size: 0.68rem;
    color: var(--text-muted);
}
/* Le périmètre OUVRE la légende. C'est la seule chose qui distingue ce graphe —
   tout l'atelier, toutes affaires confondues — des chiffres de l'affaire qui
   l'entourent. Le retirer, c'est rouvrir « pourquoi 24 ici et 120 là ». */
.pl-charge-perimetre {
    font-weight: 600;
    color: var(--text-secondary);
    margin-right: 0.15rem;
}
/* ⚠ LA CLÉ ET SON MOT NE SE SÉPARENT PAS. Dans un conteneur qui replie, une
   pastille posée en frère de son mot part à la fin d'une ligne et le mot au
   début de la suivante — vu à 400 px sur « alloué ». */
.pl-charge-item {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    white-space: nowrap;
    margin-left: 0.5rem;
}
.pl-charge-item:first-of-type { margin-left: 0.15rem; }
.pl-charge-cle {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 2px;
    flex: 0 0 auto;
}
/* Chaque clé RESSEMBLE à ce qu'elle nomme : les trois teintes du dessin, dans
   l'ordre où l'œil les rencontre. */
/* ⚠ CHAQUE CLÉ DE PART MONTRE LES COULEURS QU'ELLE PORTE VRAIMENT (12-09-2026,
   Olivier : « le vert et le rouge ne devraient pas être à côté ? ils
   représentent la même chose dans un contexte différent », puis « s'il n'y a
   pas de rouge, ça ne devrait pas apparaître dans la légende »).

   D'OÙ ON PART : une clé rouge posée en bout de liste, après « les autres
   affaires », se lisait comme un TROISIÈME « à qui ». Le dessin porte deux
   variables — la TEINTE dit à qui, la COULEUR dit si ça tient — et une clé
   bicolore les sépare sans un mot.

   TROIS ÉTATS, et c'est le graphe qui les décide, jamais la feuille :
     · rien de rouge      → la clé est VERTE, et la note n'existe pas ;
     · les deux           → `est-double`, vert et rouge côte à côte ;
     · rien de vert       → `est-rouge` (l'affaire 35 ouvre sur cinq semaines
                            d'août toutes au-dessus de la capacité).

   ⚠ UN DÉGRADÉ À BORNES FRANCHES, PAS DEUX ÉLÉMENTS : `0 50%` puis `50% 100%`
   ne laisse aucun fondu, et la clé reste UN nœud — donc insécable du mot
   qu'elle nomme quand la légende replie. */
.pl-charge-cle.is-dispo   { width: 18px; background: var(--color-surface-2); box-shadow: inset 0 0 0 1px var(--border); }
.pl-charge-cle.is-inconnu { background: var(--state-slate-dot); }
.pl-charge-cle.is-moi     { background: var(--state-green-dot); }
.pl-charge-cle.is-autres  { background: color-mix(in srgb, var(--state-green-dot) 30%, var(--surface));
                            box-shadow: inset 0 0 0 1px var(--border); }
.pl-charge-cle.is-moi.est-rouge    { background: var(--state-red-dot); }
.pl-charge-cle.is-autres.est-rouge { background: color-mix(in srgb, var(--state-red-dot) 30%, var(--surface)); }
.pl-charge-cle.is-moi.est-double {
    width: 18px;
    background: linear-gradient(90deg,
        var(--state-green-dot) 0 50%, var(--state-red-dot) 50% 100%);
}
.pl-charge-cle.is-autres.est-double {
    width: 18px;
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--state-green-dot) 30%, var(--surface)) 0 50%,
        color-mix(in srgb, var(--state-red-dot) 30%, var(--surface)) 50% 100%);
}
/* La phrase qui dit ce que la paire signifie — une fois, à la fin, pour les
   deux clés de part, et SEULEMENT quand une semaine déborde. Sans pastille à
   elle : elle ne nomme pas une teinte de plus, elle explique celles d'à côté. */
.pl-charge-note { margin-left: 0.35rem; font-style: italic; }

/* LE BILAN VIT SUR LA RANGÉE DE SA PHASE (12-09-2026, Olivier : « alléger la
   moitié droite, trop lourde, trop grosse »).

   D'OÙ ON PART : un BLOC à droite de la tête, une barre et quatre chiffres par
   phase, plus un total. Il nommait chaque phase une SECONDE fois — à trente
   centimètres de la rangée de regroupement qui la nomme déjà — et il prenait la
   moitié de la largeur à la CHARGE, seule vraie série temporelle de cette
   fenêtre, qui en manquait : à mi-largeur sur 60 semaines, il avait fallu
   éclaircir son axe à huit étiquettes.

   La question « où en est cette phase ? » se pose DEVANT SA RANGÉE. C'est donc
   elle qui porte le rapport, la barre et ce que la phase dit ; la charge prend
   toute la tête, et il ne reste qu'UNE ligne de total pour l'affaire.

   La PISTE est le budget VENDU, la BARRE le PLANIFIÉ, le REPÈRE le RÉALISÉ.

   RETIRÉES AVEC LE BLOC : `.pl-bilan`, `.pl-bilan-attente`, `.pl-bilan-grille`,
   `.pl-bilan-tete`, `.pl-bilan-legende`, `.pl-bilan-phase`, `.pl-bilan-l1`,
   `.pl-bilan-nom`, `.pl-bilan-l2` et `.is-total`. Une feuille qui garde des
   règles pour un balisage disparu fait croire, à la relecture suivante, que ce
   balisage existe encore. */
.pl-bilan-rapport { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.pl-bilan-sur { color: var(--text-muted); font-weight: 400; }
.pl-bilan-pct { color: var(--text-muted); font-weight: 400; font-size: 0.72rem; }
/* CE QUI DÉPASSE SE VOIT — l'affaire 35 a 2 464 h de pose de plus que ce qui est
   vendu. La couleur et le chiffre le disent ; la barre, elle, reste BORNÉE à sa
   piste : à 200 % elle ferait deux fois la largeur du bloc. */
/* ⚠ MÊME CORRECTION QUE LE VERDICT, POUR LA MÊME RAISON. `--error` est la
   couleur d'une PUCE : posée en TEXTE elle rend 3,76:1 sur la surface du
   tableau, sous le seuil de 4,5 — et c'est le chiffre pour lequel la rangée
   existe. Le cran `-fg` EST l'encre. */
.pl-bilan-rapport.is-depasse { color: var(--state-red-fg); }
/* ⚠ LA PISTE EST UN ÉLÉMENT DE RANGÉE, PAS DE BLOC. Dans le bloc de droite elle
   occupait la largeur par construction ; sur une rangée `flex`, sans base, elle
   tombe à ZÉRO — mesuré au navigateur le 12-09-2026 : 0 px sur les deux phases,
   une barre qui occupe la place sans rien dire. Elle prend donc une part de la
   rangée, avec un minimum en dessous duquel elle ne distinguerait plus 90 % de
   100 %. */
.pl-bilan-piste {
    position: relative;
    flex: 1 1 12rem;
    min-width: 6rem;
    max-width: 22rem;
    height: 8px;
    background: var(--border);
    border-radius: 4px;
    overflow: hidden;
}
/* ⚠ TROIS COUCHES, SUPERPOSÉES DEPUIS LA MÊME ORIGINE — jamais bout à bout
   (2026-09-12, Olivier : « gris budgété, bleu clair planifié, bleu foncé
   réalisé »). Réalisé et planifié ne s'ADDITIONNENT pas : l'un est l'exécution,
   l'autre l'intention, et une journée peut être dans les deux. Les mettre bout
   à bout compterait deux fois ce qui est à la fois FAIT et encore PLANIFIÉ.
   La part sombre posée SUR la part claire EST donc l'avancement, lisible d'un
   coup d'œil — c'est tout l'objet de la demande. */
.pl-bilan-plan,
.pl-bilan-fait {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    border-radius: 4px;
}
.pl-bilan-plan { background: var(--state-blue-dot); }
.pl-bilan-plan.is-depasse { background: var(--error); }
/* Le RÉALISÉ passe devant : c'est la couche qu'on vient lire. */
.pl-bilan-fait { background: var(--primary); z-index: 1; }
/* CE QUE LA PHASE DIT — « vendues · 519h faites · 2464h de trop ». La phrase
   CÈDE avant tout le reste quand la rangée manque de place : le rapport et la
   piste sont ce pour quoi la rangée existe, cette ligne les commente. */
.pl-bilan-dit {
    min-width: 0;
    font-size: 0.7rem;
    font-weight: 400;
    color: var(--text-muted);
    text-transform: none;
    letter-spacing: normal;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* CE QUE LE BROUILLON FERAIT — annoncé, jamais fondu dans le chiffre
   ENREGISTRÉ. Un compteur qui bougerait sous les doigts ferait croire que c'est
   écrit ; le taire laisserait supprimer une série sans que la rangée de sa
   phase bronche. Il porte donc la teinte de ce qui est EN ATTENTE, celle des
   notes de brouillon de la grille. */
.pl-bilan-attente-brouillon {
    flex: 0 0 auto;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--state-amber-fg);
    text-transform: none;
    letter-spacing: normal;
    white-space: nowrap;
}
/* LA LIGNE DE TOTAL DE L'AFFAIRE — trois chiffres, AUCUNE barre : un total n'a
   pas de cible qu'on viserait (les budgets des phases ne s'additionnent pas en
   un objectif unique), et une piste le laisserait croire. */
.pl-plan-total td {
    padding-top: 0.5rem;
    border-top: 1px solid var(--border);
    background: var(--color-surface-2);
}
.pl-plan-total .pl-phase-nom { color: var(--text); }
.pl-plan-total .pl-bilan-rapport { font-size: 0.78rem; }

/* UNE PHASE ET SES SÉRIES. La fenêtre montre TOUTES les phases de l'affaire :
   sans en-tête, on ne saurait pas de laquelle on parle. Une phase SANS aucune
   journée garde la sienne — c'est là qu'on vient ajouter, et un « + » qui
   n'existe pas est un geste qu'on ne découvre jamais. */
.pl-plan-phase-tete {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.pl-phase-nom {
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.pl-phase-total { font-size: 0.8rem; color: var(--text-secondary); margin-right: auto; }

/* ===== LE PLANNING D'UNE AFFAIRE — UNE GRILLE DE SAISIE (12-09-2026) =====

   « je ne veux pas de bouton modifier, tout peut être modifié directement
   depuis l'input affiché. Ça doit pouvoir gérer les plages et les jours, fais
   un modal plus grand avec un tableau » (Olivier).

   La liste était une suite de phrases avec un crayon qui dépliait trois champs
   SOUS la rangée : deux clics par chiffre, et le formulaire poussait le reste
   de la liste pendant qu'on s'en servait. Les champs sont dans la rangée. */
.pl-plan-wrap { border: 1px solid var(--border); border-radius: 4px; overflow-x: auto; overscroll-behavior-x: none; }
/* ⚠ DISPOSITION FIXE, ET C'EST UNE DÉCISION. En disposition AUTO une largeur
   n'est qu'une SUGGESTION : le navigateur répartit le mou sur toutes les
   colonnes (deux champs de date de 152 px dans des colonnes de 217, donc deux
   trous au milieu de la rangée) et, à l'inverse, laisse un nom long POUSSER la
   table hors de son cadre — mesuré à 1024 px : 1 164 px de table dans 941 px de
   cadre avec deux noms de 38 caractères.
   La contrepartie est celle que le socle impose (CLAUDE.md, « Largeurs de
   colonnes ») : TOUTES les colonnes portent une largeur — une colonne sans
   largeur ne reçoit que le reste et tombe à ZÉRO si la somme déborde — et les
   cellules COUPENT, sinon un contenu trop large se superpose à sa voisine.
   La seule colonne en `auto` est « Qui » : c'est la seule dont le contenu n'a
   pas de largeur connue, donc la seule à qui le mou appartient. */
.pl-plan-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-size: 0.8rem;
}
.pl-plan-table th.pl-plan-h      { width: 8.25rem; }
.pl-plan-table th.pl-plan-date   { width: 10.5rem; }
.pl-plan-table th.pl-plan-duree  { width: 8.5rem; }
.pl-plan-table th.pl-plan-fin    { width: 8.5rem; }
.pl-plan-table th.pl-plan-num    { width: 5.5rem; }
.pl-plan-table th.pl-plan-qui    { width: auto; }
.pl-plan-table th.pl-plan-etat   { width: 11rem; }
.pl-plan-table th.pl-plan-act    { width: 4.75rem; }
.pl-plan-table th {
    padding: 0.3rem 0.5rem;
    text-align: left;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
    background: var(--color-surface-2);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.pl-plan-table td {
    padding: 0.15rem 0.5rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
    white-space: nowrap;
    /* Compagnon OBLIGATOIRE de `table-layout: fixed` : ce qui dépasse est coupé,
       jamais superposé à la colonne voisine. */
    overflow: hidden;
    text-overflow: ellipsis;
}
.pl-plan-table tr:last-child td { border-bottom: none; }
/* LES CHAMPS SONT LA RANGÉE : ils doivent tenir dans la hauteur d'une ligne de
   liste, pas dans celle d'un formulaire. */
.pl-plan-input {
    height: 28px;
    padding: 0 0.4rem;
    font-size: 0.8rem;
}
.pl-plan-h .pl-plan-input,
.pl-plan-duree .pl-plan-input { width: 4rem; }
.pl-plan-date .pl-plan-input { width: 100%; }
/* LA DATE DE FIN EST UNE LECTURE, pas un champ : elle se lit comme le total,
   en retrait de ce qui se saisit. C'est ce qui distingue « ce que je décide »
   de « ce que ça produit », colonne par colonne. */
.pl-plan-fin { color: var(--text-secondary); }
.pl-plan-suffixe { color: var(--text-muted); font-size: 0.72rem; margin-left: 0.2rem; }
.pl-plan-num { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-secondary); }
.pl-plan-total { color: var(--text); font-weight: 600; }
.pl-plan-act { text-align: right; }
/* « Qui » est le SEUL champ qui n'est pas un input : choisir parmi trente
   personnes est une liste, pas une frappe. Le bouton porte les noms, et il se
   coupe — c'est la seule colonne dont le contenu n'a pas de largeur connue.
   ⚠ `width: 100%` EN DISPOSITION AUTO VEUT DIRE « prends le mou ». Sans lui, le
   navigateur répartissait la place restante sur TOUTES les colonnes, et les deux
   colonnes de date sortaient à 217 px pour un champ de 152 : deux trous au
   milieu de la rangée, pile entre « Du » et « Au ». Le mou appartient à la
   colonne dont le contenu n'a pas de largeur connue. */
.pl-plan-qui { min-width: 8rem; }
.pl-plan-qui-btn {
    display: block;
    width: 100%;
    padding: 0.2rem 0.4rem;
    border: 1px solid transparent;
    border-radius: 4px;
    background: none;
    color: var(--text);
    font-size: 0.8rem;
    text-align: left;
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pl-plan-qui-btn:hover { border-color: var(--border); background: var(--surface); }
.pl-plan-qui-btn[disabled] { cursor: default; color: var(--text-muted); }
.pl-plan-qui-row td { background: var(--color-surface-2); white-space: normal; }
.pl-plan-qui-hote { padding: 0.25rem 0; }
/* La rangée de REGROUPEMENT d'une phase. Elle porte son total et son « + » ;
   elle n'est pas une colonne d'actions, d'où le `colspan` (la règle collante du
   socle exclut `:not([colspan])` pour exactement cette raison). */
.pl-plan-phase td {
    padding: 0.45rem 0.5rem 0.25rem;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.pl-plan-phase td > * { vertical-align: middle; }
.pl-plan-vide td {
    padding: 0.5rem;
    color: var(--text-muted);
    font-style: italic;
}
/* Une série AJOUTÉE n'est pas encore en base : elle se distingue de ce qui y
   est, sinon on ne saurait pas ce qui reste à enregistrer. */
.pl-plan-serie.is-ajout td { background: var(--state-green-bg); }
/* ⚠ UNE RANGÉE NEUVE EST VERTE COMME UN AJOUT, ET PLUS BLEUE (12-09-2026). Le
   bleu était DÉJÀ pris par la rangée d'où l'on vient : deux sens sous une seule
   apparence, dans la même liste. Une rangée neuve est une rangée « à créer » —
   elle porte la couleur de ce qu'elle va devenir, et ses deux boutons la
   distinguent d'une série déjà posée. */
.pl-plan-serie.is-neuve td { background: var(--state-green-bg); }
.pl-plan-serie.is-supprimee .pl-plan-num,
.pl-plan-serie.is-supprimee .pl-plan-fin,
.pl-plan-serie.is-supprimee .pl-plan-qui-btn { text-decoration: line-through; color: var(--text-muted); }
.pl-plan-serie.is-supprimee .pl-plan-input { opacity: 0.55; }
.pl-plan-serie.is-ouverte td { background: var(--color-surface-2); }
/* L'AVERTISSEMENT EST UN BADGE, DANS LA COLONNE « ÉTAT » (12-09-2026, Olivier :
   « pas de jaune, juste un badge orange surcharge dans la bonne colonne »).

   D'OÙ ON PART : la rangée entière était teintée en ambre, avec sa phrase en
   dessous. Elle criait plus fort que ce qu'elle disait — et quatre rangées
   averties sur cinq faisaient un tableau jaune, c'est-à-dire AUCUN signal. Un
   badge tient dans sa colonne et laisse la donnée lisible.

   ⚠ LA PAIRE D'ÉTAT DU SOCLE, pas une teinte inventée : `--state-amber-bg` /
   `-fg` sont faites l'une pour l'autre et leur contraste est mesuré par
   `probe-ecran-planning-affaire`. */
.pl-badge-avert {
    display: inline-flex;
    align-items: center;
    padding: 0.05rem 0.4rem;
    margin-right: 0.3rem;
    border: none;
    border-radius: 10px;
    background: var(--state-amber-bg);
    color: var(--state-amber-fg);
    font-family: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}
button.pl-badge-avert { cursor: pointer; }
button.pl-badge-avert:hover,
.pl-badge-avert.is-ouvert { box-shadow: inset 0 0 0 1px var(--state-amber-fg); }

/* LE DÉTAIL JOUR PAR JOUR — NEUTRE : la couleur appartient au badge, qui
   signale ; cette rangée-ci explique, et elle ne s'ouvre que sur demande. */
.pl-plan-avert td {
    padding: 0.35rem 0.5rem 0.45rem 2rem;
    background: var(--color-surface-2);
    border-bottom: 1px solid var(--border);
    white-space: normal;
}
.pl-plan-avert-titre { font-size: 0.78rem; font-weight: 600; color: var(--state-amber-fg); }
.pl-plan-avert .pl-warn-jours {
    margin: 0.2rem 0 0;
    padding-left: 1.1rem;
    color: var(--text-secondary);
    font-size: 0.75rem;
}

/* Les deux gestes d'une rangée, à droite, hors des champs.
   ⚠ CES TROIS RÈGLES ONT ÉTÉ EMPORTÉES PAR UNE COUPE le 12-09-2026, avec le bloc
   d'avertissement ambre qui les précédait : les boutons sont repassés à
   l'apparence par défaut du navigateur — un cadre gris autour de chaque
   corbeille, sur toute la liste. Aucune sonde jsdom ne pouvait le dire (pas de
   mise en page), seul le NAVIGATEUR l'a montré. */
.pl-serie-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 4px;
    background: none;
    color: var(--text-muted);
    cursor: pointer;
    line-height: 0;
}
.pl-serie-btn:hover { border-color: var(--border); color: var(--primary); background: var(--surface); }
.pl-serie-btn.is-danger:hover { border-color: var(--error); color: var(--error); }

/* ⚠ CE QU'ON ÉPINGLE DOIT AVOIR UNE HAUTEUR BORNÉE PAR CONSTRUCTION.
   Le collage a été posé le 11-09-2026 au matin avec trois avertissements sous
   les yeux. L'après-midi, l'affaire 35 en a rendu CINQUANTE-HUIT : la bande
   ÉTAIT la fenêtre. La borne ne vient donc PAS d'un `max-height` — un
   `overflow` ici rouvrirait le second ascenseur qu'on a supprimé — mais du
   GROUPEMENT : cinquante-huit phrases se rangent en trois groupes, et un
   groupe déplié est le seul à s'ouvrir. Voir `.pl-warn-detail-tete`. */
.pl-warn-ligne { display: block; }
.pl-warn-titre { font-weight: 600; }
/* (`.pl-warn-plus` — le « + N autres » qui EMMENAIT du résumé collé vers le
   détail — est parti le 12-09 avec la bande du résumé : les avertissements ne
   sont plus écrits qu'une fois, il n'y a donc plus d'où partir.) */

/* LE DÉTAIL DES GROUPES — dans le flux, au-dessus du calendrier. Cinquante-huit
   phrases répétées se rangent ici en trois groupes, chacun dépliable sur ses
   jours. */
.pl-warn-detail {
    margin-bottom: 0.5rem;
    border: 1px solid var(--state-amber-fg);
    border-radius: 4px;
    background: var(--state-amber-bg);
}
/* ⚠ C'EST LA TÊTE QUI SE COLLE, PAS LA BANDE — et c'est toute la leçon du
   11-09-2026. Ce jour-là, le résumé et les avertissements ont été épinglés le
   matin avec trois avertissements sous les yeux ; l'après-midi, l'affaire 35 en
   a rendu CINQUANTE-HUIT, et la bande ÉTAIT la fenêtre. **Tout ce qui grandit
   avec les données ne peut pas être épinglé.** Les groupes se déplient sur
   leurs 39 jours : la bande n'a donc aucune hauteur bornée. Sa TÊTE, elle, fait
   une ligne, toujours — « 44 avertissements » reste sous les yeux pendant qu'on
   parcourt la liste, et c'est ce qu'il ne faut pas oublier avant de valider. */
.pl-warn-detail-tete {
    position: sticky;
    top: 0;
    z-index: 2;
    padding: 0.3rem 0.6rem;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--state-amber-fg);
    background: var(--state-amber-bg);
    border-radius: 4px 4px 0 0;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.pl-warn-groupes {
    list-style: none;
    margin: 0;
    padding: 0;
}
.pl-warn-groupe { border-top: 1px solid var(--state-amber-fg); }
.pl-warn-tete {
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
    width: 100%;
    padding: 0.3rem 0.6rem;
    border: none;
    background: none;
    font: inherit;
    font-size: 0.8rem;
    color: var(--text);
    text-align: left;
}
button.pl-warn-tete { cursor: pointer; }
button.pl-warn-tete:hover { background: var(--surface); }
.pl-warn-chevron {
    display: inline-flex;
    line-height: 0;
    color: var(--text-muted);
    transition: transform 0.12s ease;
}
.pl-warn-groupe.is-ouverte .pl-warn-chevron { transform: rotate(90deg); }
.pl-warn-jours {
    margin: 0;
    padding: 0 0.6rem 0.4rem 1.8rem;
    list-style: disc;
    font-size: 0.75rem;
    color: var(--text-secondary);
}

/* Le CALENDRIER : le corps de la fenêtre, plus un repli. */
.pl-shift-preview { margin-top: 0.4rem; }
.pl-shift-loading {
    font-size: 0.8rem;
    color: var(--text-muted);
}
.pl-shift-summary {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text);
    margin-bottom: 0.4rem;
}
.pl-shift-sep { color: var(--text-muted); font-weight: 400; }
/* ⚠ RIEN NE DÉFILE POUR SON COMPTE DANS CETTE FENÊTRE. La liste avait son
   `max-height` + `overflow-y`, ce qui plaçait un ascenseur DANS un ascenseur —
   deux mécanismes pour un seul pouce, et selon l'endroit où l'on pousse c'est
   l'un ou l'autre qui bouge. Un seul défilement par fenêtre (Olivier,
   11-09-2026). `.pl-plan-wrap` ne libère que l'axe HORIZONTAL, celui d'un
   tableau trop large ; ce que l'ascenseur intérieur protégeait est repris par
   `.pl-warn-detail`, qui se colle en haut. */

/* RETIRÉ LE 12-09-2026 : `.pl-shift-degrouper` et la colonne `.pl-plan-poignee`
   qui la logeait — « pas besoin du folding pour éclater par jour sur les lignes
   avec plusieurs jours, cela complique pour rien » (Olivier). Le dégroupement
   datait du temps où une série ne s'éditait que d'un bloc ; on édite désormais
   ses BORNES, ce qui fait le même travail sans apprendre un geste. La grille
   passe de NEUF colonnes à HUIT. */

/* Ce que la rangée fera de plus que porter des heures — cumuler sur une case,
   disparaître, être créée — se dit SUR la rangée, avant le clic, pas dans une
   notification après. */
.pl-shift-note {
    font-size: 0.72rem;
    color: var(--text-muted);
    font-style: italic;
}

/* RETIRÉES LE 12-09-2026, avec la LISTE qu'elles peignaient : `.pl-shift-lines`,
   `.pl-shift-line` (et ses états `is-serie`, `is-ajout`, `is-supprimee`,
   `is-ouverte`, `is-focus`, `is-still`), `.pl-shift-ligne-tete`,
   `.pl-shift-from` / `.pl-shift-to` / `.pl-shift-arrow` / `.pl-shift-hours`,
   `.pl-shift-serie-meta`, `.pl-serie-heures` / `.pl-serie-quand`,
   `.pl-serie-actions`, et le formulaire déplié `.pl-serie-form` /
   `.pl-serie-champ`. La liste est un TABLEAU (`.pl-plan-*`) dont les rangées
   s'éditent dans leurs propres champs : plus aucune de ces classes n'est rendue
   nulle part. Une feuille qui garde des règles pour un balisage disparu fait
   croire, à la relecture suivante, que ce balisage existe encore. */

/* (La mise en forme COMPACTE de la fiche dépliée dans une ligne est partie avec
   le dépliement, lot 6 : la fiche n'a plus qu'un hôte, la modale d'allocation,
   et une seule mise en forme.) */

/* ═══════════════════════════════════════════════════════════════════════════
   LES RANGÉES « RÉEL », SOUS LEURS SÉRIES PLANIFIÉES (2026-09-12)
   ═══════════════════════════════════════════════════════════════════════════
   ⚠ PAS D'ONGLETS — « je dois tout voir d'un coup d'œil » (Olivier). Une
   bascule Planifié/Réel/Atterrissage a vécu une heure ici : elle obligeait à SE
   SOUVENIR de l'autre vue pour comparer, alors que comparer est précisément ce
   qu'on vient faire.

   ⚠ LES DEUX FAMILLES PARTAGENT LES MÊMES COLONNES, parce qu'elles ont la même
   forme : une plage de jours, un volume d'heures, des personnes. C'est ce qui
   fait UN tableau et non deux empilés. Leur distinction se fait par un LISERÉ,
   jamais par un fond qui crie — quatre rangées teintées sur cinq font un
   tableau coloré, donc aucun signal (règle payée sur les avertissements ambre). */
.pl-plan-reel td:first-child { box-shadow: inset 3px 0 0 var(--state-green-fg); }

/* Le taux d'une rangée pointée : c'est un CONSTAT, pas un champ. Il ne doit donc
   pas ressembler aux `<input>` des séries planifiées, qui, eux, se cliquent. */
.pl-reel-taux {
    display: inline-block;
    padding: 0.1rem 0.35rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.pl-badge-reel {
    display: inline-flex;
    align-items: center;
    padding: 0.05rem 0.4rem;
    border-radius: 10px;
    background: var(--state-green-bg);
    color: var(--state-green-fg);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

/* UNE RANGÉE POINTÉE QUI MÈNE QUELQUE PART LE DIT — et seulement là où elle
   mène (l'hôte qui ne sait pas détailler ne pose pas l'attribut). Même règle que
   le badge d'en-tête : ce qui agit doit se voir agir. */
.pl-plan-reel.is-porte { cursor: pointer; }
.pl-plan-reel.is-porte:hover td { background: var(--color-surface-2); }


/* ⚠ `.pl-charge-barre.is-fait` EST RETIRÉE — la hachure qui distinguait, sur
   une barre unique, les heures FAITES des heures PRÉVUES. Le réalisé a sa propre
   forme depuis le 12-09-2026 (une seconde barre, puis un second chiffre dans la
   cellule) : une hachure dirait une seconde fois, autrement, ce qu'il dit déjà. */


/* ═══ LES HEURES DANS L'ORDRE DU TEMPS (12-09-2026) ═══════════════════════
   « Les heures sous forme de tableau chronologique pour chaque fonction
   (toujours ouvert) avec les heures réalisées et les heures planifiées »
   (Olivier, sur airfact /jobs/440#temps).

   C'est le rendu du mode LECTURE : là où l'écran d'édition pose sa grille de
   saisie, l'onglet consultatif pose ces tableaux. Ils n'ont AUCUN geste — ni
   repli, ni champ, ni menu de rangée —, et c'est la raison pour laquelle rien
   ici ne porte de `cursor`, de `:hover` ni de chevron : ce qui n'agit pas n'a
   pas à en porter le dessin.

   ⚠ LE PLANCHER DÉCIDE LE NOMBRE DE PISTES, PAS LEUR LARGEUR — et il a été
   mesuré, pas choisi. À 260 px, `auto-fill` ouvrait TROIS pistes dans les 804 px
   de la colonne d'airfact en mode rail, alors qu'une carte en demande 271 :
   les trois tableaux débordaient de leur fond, sans que la page défile pour le
   dire (mesuré au navigateur le 12-09-2026, `probe-ecran-planning-affaire.js`
   [3d]). Ce qui coupait n'était pas la grille mais son plancher.

   300 px laisse DEUX pistes à 804 px (rail) comme à 622 px (sans rail), et une
   seule à 400 px. Une troisième fonction tombe sur la rangée suivante — elle y
   est seule, et c'est voulu : lisible vaut mieux que dense.

   ⚠ CE QUI FIXE CE PLANCHER EST L'ÉTIQUETTE DE SEMAINE, « sem. 43 · 19/10/2026 »,
   en `nowrap` et ANNÉE COMPRISE. Raccourcir la date rétrécirait la carte — et
   rendrait « sem. 15 · 12/04 » illisible sur une affaire qui passe l'année. */
.pl-chrono-hote {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 0.75rem;
    align-items: start;
}
.pl-chrono {
    background: var(--color-surface-2);
    border-radius: 6px;
    padding: 0.5rem 0.55rem 0.55rem;
    /* La carte est le CONTENANT d'une fonction ; ses deux tableaux sont deux
       objets, chacun sur sa propre surface. D'où le `gap` ici, et le fond blanc
       sur `.pl-chrono-bloc`. */
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    /* ⚠ SANS LUI, UNE ÉTIQUETTE LONGUE POUSSE LA PISTE. Un enfant de grille a
       `min-width: auto` : « sem. 38 · 14/09/2026 » élargit sa colonne au lieu
       de se contenter de la place reçue, et la grille déborde de la page. */
    min-width: 0;
}
.pl-chrono-titre {
    /* L'écart vient du `gap` de la carte : une marge ici s'y AJOUTERAIT. */
    margin: 0;
    /* ⚠ ELLE PORTE DEUX CHOSES DEPUIS LE 12-09-2026 : le nom de la fonction, et
       ses trois totaux. Ils REPLIENT sous le nom plutôt que de le comprimer —
       une carte fait 300 px au plancher, et « 2087h planifié · 519h réalisé »
       en fait déjà 180. */
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.15rem 0.5rem;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
/* Les totaux ne CRIENT pas : ils accompagnent le nom, ils ne le doublent pas.
   D'où la casse normale et le poids rendu aux seuls nombres. */
.pl-chrono-totaux {
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.pl-chrono-totaux b { font-weight: 700; color: var(--text-secondary); }
/* ═══ DEUX TABLEAUX, DEUX OBJETS ══════════════════════════════════════════
   « Ça va pas là de les fusionner, c'est pas les mêmes colonnes, c'est pas la
   même chose » (Olivier, 12-09-2026, capture à l'appui).

   Ils ont vécu une heure EMPILÉS NUS dans la carte, et pire : je leur avais
   imposé des largeurs de colonnes COMMUNES pour que « Réalisé » tombe sur le
   même axe dans les deux. L'intention était bonne (les salariés somment la
   chronologie) mais le résultat disait le contraire de la vérité — même
   rythme de rangée, mêmes colonnes, même fond : un SEUL tableau qui change
   d'en-tête au milieu. Or « Jours » n'a rien à voir avec « Planifié », et une
   personne n'est pas une semaine.

   Chacun a donc SA surface, et chacun dimensionne SES colonnes. */
.pl-chrono-bloc {
    background: var(--surface);
    border-radius: 5px;
    padding: 0.35rem 0.5rem 0.4rem;
}
.pl-chrono-table {
    width: 100%;
    /* ⚠ `fixed` RESTE, mais pour une autre raison qu'avant : c'est lui qui rend
       `max-width: 0` opposable sur la cellule du nom, donc la troncature. En
       disposition auto, un nom de 38 caractères élargirait sa colonne et
       emporterait la carte. */
    table-layout: fixed;
    border-collapse: collapse;
    font-size: 0.78rem;
}
/* Les largeurs sont PROPRES À CHAQUE TABLEAU. « Jours » est un petit entier,
   « Planifié » et « Réalisé » des volumes d'heures : rien ne justifie qu'ils
   partagent une piste. */
.pl-chrono-table th.pl-chrono-num { width: 72px; }
/* ⚠ `:nth-child(2)`, PAS `th.pl-chrono-num:first-of-type` — celui-ci ne matche
   RIEN : `:first-of-type` porte sur le premier `<th>` du parent (« Salarié »),
   pas sur le premier qui porte la classe. Un sélecteur qui ne matche rien ne
   lève pas : la colonne serait restée à 72 px sans que rien ne le dise. */
.pl-chrono-qui th:nth-child(2) { width: 52px; }
.pl-chrono-table th {
    padding: 0.15rem 0.3rem 0.3rem;
    font-size: 0.68rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    text-align: left;
    border-bottom: 1px solid var(--border);
}
.pl-chrono-table td {
    padding: 0.18rem 0.3rem;
    border-bottom: 1px solid var(--border);
}
.pl-chrono-table tbody tr:last-child td { border-bottom: none; }
.pl-chrono-quand { color: var(--text-secondary); white-space: nowrap; }
/* Les nombres se comparent en COLONNE : alignés à droite, et à chasse fixe,
   sinon « 90h » et « 108h » ne s'empilent pas sur le même axe. */
.pl-chrono-num {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.pl-chrono-h { font-weight: 600; }
/* ⚠ LE ZÉRO N'EST PAS UN CHIFFRE ICI, C'EST UNE ABSENCE. « 0h » se lit comme
   une mesure ; le tiret dit qu'il n'y a rien à mesurer sur ce créneau — une
   semaine planifiée non encore pointée, ou pointée hors plan. */
.pl-chrono-rien { color: var(--text-muted); }
/* ═══ LE TABLEAU DES SALARIÉS — QUI, ET SUR QUELLE PÉRIODE ═══════════════
   « Avant, voir les séries permettait de voir par salariés et par date, on
   pourrait avoir les 2 comme avant ? » (Olivier, 12-09-2026), puis « ça doit
   être toujours affiché en haut avec le détail en dessous » : six lignes qui
   tiennent d'un coup d'œil, et la chronologie les détaille en dessous.

   L'écart entre les deux blocs est porté par le `gap` de la carte, jamais par
   une marge du tableau : `bloc + bloc` ne traverserait pas la frontière si l'un
   des deux venait à manquer (une fonction sans pointeur n'a pas de « Salarié »).

   ⚠ LE NOM SE TRONQUE, IL NE POUSSE PAS. « Géraldine Marie-Camille
   SERRANO-BERTHIER » fait 38 caractères dans une carte de 300 px : sans
   `min-width: 0` sur une cellule de table, le texte élargit la colonne et
   emporte la carte avec lui. La rangée porte son nom complet en `title`. */
.pl-chrono-nom {
    max-width: 0;
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* La période sous le nom : la seconde moitié de « par salarié ET par date »,
   et la seule place qui ne dispute rien aux deux colonnes de chiffres. */
.pl-chrono-periode {
    display: block;
    font-size: 0.68rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
}
/* ⚠ AUCUN `cursor`, AUCUN `:hover` : ces rangées ont mené aux saisies jour par
   jour pendant une demi-heure, cette liste est supprimée (12-09-2026). Ce qui
   n'agit pas n'a pas à en porter le dessin. */

.pl-chrono-table tfoot td {
    padding-top: 0.3rem;
    border-top: 1px solid var(--border);
    border-bottom: none;
    font-weight: 700;
}

/* ═══ « PLANIFIER LA CHAÎNE » — la modale partagée (14-09-2026) ════════════
   Jumelle de `modules/planning-chaine.js`, et logée ICI plutôt que dans une
   feuille à elle : les deux vivent sur le même écran, et une feuille de plus à
   symlinker dans les deux apps serait un point de montage de plus à tenir pour
   six déclarations. Elles reprennent `.alloc-period-preview` et
   `.pl-chain-warnings`, qui vivaient dans `plan/modules/my-planning.css` — donc
   nulle part pour airfact. */

/* L'APERÇU. ⚠ Il garde sa hauteur quand il est VIDE : sans `min-height`, le
   pied de la modale remonte d'une ligne au premier « Prévisualiser », et les
   deux boutons se dérobent sous le curseur qui vient de cliquer. */
.plc-apercu {
    margin-top: 0.4rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
    min-height: 1.2em;
}

/* LES AVERTISSEMENTS — ce que l'application REMPLACERAIT, les surcharges
   d'atelier, les journées verrouillées conservées. Ils ne sont pas des erreurs
   (le geste part quand même), d'où le ton d'alerte et non celui d'échec. */
.plc-avertissements { margin: 0.5rem 0 0; padding-left: 1.1rem; }
.plc-avertissements li { color: var(--warning-hover); margin-top: 0.15rem; }

/* LA BASCULE DE SENS — elle tient dans ses deux boutons, pas dans la fenêtre.
   (14-09-2026, Olivier, capture à l'appui : « le à rebours fait toute la
   largeur ».)

   ⚠ LA CAUSE N'EST PAS DANS `.btn-group`, ELLE EST DANS SON PARENT. `.form` est
   une COLONNE FLEX : ses enfants sont étirés sur toute la largeur (align-items
   par défaut), et un `inline-flex` devenu élément flex est BLOQUIFIÉ en `flex`
   — le `display: inline-flex` du socle ne peut donc plus rien. Mesuré au
   navigateur : groupe à 768 px pour 260 px de boutons, soit 506 px de cadre
   vide derrière le second, qu'on lit comme un bouton géant.

   ⚠ ET LA RÈGLE EST PORTÉE ICI, PAS DANS `buttons.css`. Le défaut vaut pour
   TOUT `.btn-group` enfant direct d'un `.form`, mais le socle habille 27 usages
   dans quatre apps : élargir la correction sans les avoir regardés un par un
   changerait des écrans que personne n'a signalés. Les bascules de plan
   (`_planning-gantt.php`) vivent, elles, dans un `fieldset` — pas le même
   parent, pas le même cas.

   Tenu par `ops/ui-capture/bancs/chaine-modale/banc.js`, qui mesure le VIDE
   au-delà du dernier bouton — pas la règle, la géométrie. */
.plc-sens { align-self: flex-start; }
