/* PlaniBulle - Styles globaux */

:root {
    --pb-primary: #5C6BC0;
    --pb-secondary: #80CBC4;
    --pb-bg: #F5F5F5;
    --pb-surface: #FFFFFF;
    --pb-radius: 12px;
    --pb-shadow: 0 2px 8px rgba(0,0,0,0.08);

    /* Couleurs gris fréquentes — à utiliser au lieu de #757575/#9E9E9E inline */
    --pb-text-muted: #757575;
    --pb-text-disabled: #9E9E9E;
    --pb-text-note: #616161;       /* texte de note légèrement plus foncé que muted (fiches parent/enfant) */
    --pb-text-faint: #BDBDBD;      /* gris très clair (placeholders, valeurs nulles) */
    --pb-border-light: #ECEFF1;
    --pb-border-soft: #E0E0E0;     /* bordure plus appuyée que --pb-border-light */
    --pb-bg-subtle: #FAFAFA;
    --pb-bg-card: #F5F5F5;         /* fond alterné de carte/section */

    /* Couleurs sémantiques projet — alignées sur le thème MudBlazor (Routes.razor) avec
       une variante plus saturée pour les Style="color:..." inline qui demandent du contraste.
       Préférer les Color enum MudBlazor (Color.Success, Color.Warning, ...) quand le composant
       le supporte ; utiliser ces vars uniquement pour les Style inline ou les switch C# qui
       retournent une chaîne CSS. */
    --pb-color-success: #43A047;       /* vert solide pour Style="color" inline */
    --pb-color-success-dark: #2E7D32;  /* variante très saturée (KPI, attestation) */
    --pb-color-warning: #FB8C00;
    --pb-color-warning-dark: #E65100;
    --pb-color-error: #E53935;
    --pb-color-info: #1976D2;

    /* Textes blue-grey appuyés (tableaux denses, en-têtes de bilan).
       Préférer ces vars aux valeurs raw Material Blue Grey 700/900. */
    --pb-color-text-strong: #455A64;      /* blue-grey-700 — colonnes / bordures / labels appuyés */
    --pb-color-text-stronger: #263238;    /* blue-grey-900 — valeur emphatique mois courant */

    /* Fonds soft pastel pour zones de statut (badges, options interactives) */
    --pb-bg-success-soft: #E8F5E9;        /* vert très clair (zone vacante / option positive) */
    --pb-bg-success-soft-hover: #C8E6C9;  /* hover/active sur fond --pb-bg-success-soft */
    --pb-bg-info-soft: #E3F2FD;           /* bleu très clair (zone historique / option neutre) */
    --pb-bg-warning-soft: #FFF3E0;        /* orange très clair (journée validée avec modifs) */
    --pb-bg-error-soft: #FDECEA;          /* rose très clair (journée retournée, à re-confirmer) */

    /* Espacement courant pour les cellules de tableau dense */
    --pb-cell-padding: 8px 12px;
    --pb-cell-padding-tight: 4px 8px;
}

/* Classes utilitaires pour réduire les styles inline (cf. lot 6 audit) */
.pb-text-muted { color: var(--pb-text-muted); }
.pb-text-disabled { color: var(--pb-text-disabled); }
.pb-text-note { color: var(--pb-text-note); }
.pb-cell-padded { padding: var(--pb-cell-padding); }
.pb-cell-padded-tight { padding: var(--pb-cell-padding-tight); }
.pb-bg-subtle { background: var(--pb-bg-subtle); }

/* Rayon de coin standard des cartes (MudPaper / MudCard). Remplace les
   Style="border-radius:12px;" inline répétés sur ~45 fichiers. La variante
   --sm (10px) couvre les cartes secondaires/imbriquées (Outlined). */
.pb-card { border-radius: 12px; }
.pb-card--sm { border-radius: 10px; }
.pb-card--xs { border-radius: 8px; }
.pb-card--lg { border-radius: 16px; }

/* Encart gris de dialog (récap, contexte) : fond carte + coins 8px. Remplace les
   Style="background:var(--pb-bg-card);border-radius:8px;" inline des dialogs.
   Variante --bordered : bordure douce sans fond (liste d'items dans un dialog). */
.pb-encart { background: var(--pb-bg-card); border-radius: 8px; }
.pb-encart--bordered { background: none; border: 1px solid var(--pb-border-light); }

/* Coins arrondis + clipping des MudTable desktop des pages liste. Remplace les
   Style="border-radius:8px;overflow:hidden;" inline répétés sur ~18 listes. */
.pb-table-rounded { border-radius: 8px; overflow: hidden; }

/* Footer de dialog mutualisé (composant DialogFooter) : ligne droite desktop,
   stack vertical sous breakpoint mobile (cf. CLAUDE.md § Modals responsive). */
.pb-dialog-footer {
    display: flex;
    flex-direction: row;
    justify-content: flex-end;
    align-items: center;
    gap: 8px;
    width: 100%;
}
@media (max-width: 600px) {
    .pb-dialog-footer {
        flex-direction: column-reverse;
        align-items: stretch;
    }
}

/* Pattern « MudTd qui rend une carte » utilisé pour les listings en cartes
   dans un MudTable (cf. CLAUDE.md § Pagination — rendu cartes mobile via
   MudTable + MudTablePager). 14 sites historiques migrés en Sprint E5. */
.pb-mudtd-card { display: block; padding: 4px 0; }
.pb-mudtd-card--bordered { display: block; padding: 8px 0; border-bottom: 1px solid var(--pb-border-light); }

/* Tuile KPI partagée (composant KpiTile) : compteurs salariée, soldes absences. */
.kpi-tile {
    border: 1px solid var(--pb-border-light);
    border-radius: 12px;
    padding: 12px 16px;
    background: var(--mud-palette-surface);
    height: 100%;
}
.kpi-tile__dot {
    width: 12px; height: 12px;
    border-radius: 50%;
    flex-shrink: 0;
}
.kpi-tile__dot--primary { background: var(--mud-palette-primary); }
.kpi-tile__sub { display: block; }

/* Sélecteur à choix unique en chips de couleur (composant SelecteurChips) :
   alternative au MudSelect quand peu d'options colorées. */
.selecteur-chips-bloc__label { color: var(--pb-text-muted); display: block; margin-bottom: 4px; }
.selecteur-chips-bloc__req { color: var(--pb-color-error); margin-left: 2px; }
.selecteur-chips { display: flex; flex-wrap: wrap; gap: 8px; }

* { box-sizing: border-box; }

body {
    font-family: 'Nunito', Helvetica, Arial, sans-serif;
    background-color: var(--pb-bg);
    margin: 0;
    padding: 0;
}

/* Curseur sur le chrome UI — un curseur I-beam + caret clignotant au clic
   suggère à tort que la zone est éditable (norme = clignotement = champ
   modifiable). On combine :
   - cursor: default → curseur flèche au survol (au lieu d'I-beam)
   - caret-color: transparent → si un caret apparaît malgré tout (focus
     clavier, tabindex, contenteditable hérité), il est invisible

   La sélection texte (et donc le copier-coller) reste possible — c'est
   uniquement le visuel du caret qui disparaît. Permet de garder
   copiables les noms/prénoms d'un header de fiche, les titres, les
   chips, etc., sans le signal trompeur du caret clignotant.

   Les inputs (MudTextField, MudTimePicker, MudSelect…) conservent leur
   curseur text et caret coloré via leurs propres classes plus
   spécifiques (.mud-input-slot, .mud-input-root). */
.mud-typography,
.mud-nav-link,
.mud-nav-link-text,
.mud-list-item,
.mud-list-item-text,
.mud-chip,
.mud-tab,
.mud-button-root,
.mud-input-label,
.mud-table-cell:not(.mud-table-cell-checkbox) {
    cursor: default;
    caret-color: transparent;
}

/* Planning grid — largeur de colonnes constante.
   À poser via `Class="planning-grid"` sur toute MudTable de grille planning
   hebdomadaire (7 colonnes : salariée + 5 jours ouvrés + total). */
.planning-grid {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* Colonnes dimensionnées par le contenu (auto), pas en largeur fixe : depuis que les
   plages sont rendues en lignes « timeline » + un pied actions/total, une largeur figée
   (~150px) tronquait/chevauchait le pied (4 icônes d'action + total). On passe donc en
   `table-layout: auto` avec des `min-width` : chaque colonne jour prend au moins la place
   du pied et des lignes de plage, et le wrapper `.planning-grid` scrolle horizontalement
   plutôt que d'écraser le contenu. L'alignement colonne-à-colonne d'une semaine à l'autre
   n'est plus garanti au pixel près — compromis assumé pour un contenu lisible.

   La colonne total (dernière) tient un total à deux chiffres (« 26h35 ») + son chip
   d'écart signé empilé. Scopé ≥ 600px : sous Sm, MudTable bascule en cartes (DataLabel). */
@media (min-width: 600px) {
    /* Colonnes de largeur ÉGALE (table-layout: fixed) pour que les champs (horaires, type,
       durée, total) s'alignent d'une colonne à l'autre. min-width 1400px : chaque colonne jour
       fait (1400-244)/5 ≈ 231px — assez large pour le pied (icônes + total) et une ligne de plage
       sans troncature. En dessous, .planning-grid scrolle horizontalement. */
    .planning-grid .mud-table-root {
        table-layout: fixed;
        width: 100%;
        min-width: 1400px;
    }
    .planning-grid .mud-table-head .mud-table-cell:first-child {
        width: 140px;
    }
    .planning-grid .mud-table-head .mud-table-cell:last-child {
        width: 104px;
    }
    .planning-grid .mud-table-head .mud-table-cell:not(:first-child):not(:last-child) {
        width: calc((100% - 244px) / 5);
    }
    /* Éditeur de modèle ET grille du mois : la dernière colonne porte un récap de 4-6 lignes
       « libellé + valeur » (total / écart contrat + Terrain / Hors terrain / Réunion / Absence)
       — 104px tronquerait « Hors terrain ».
       Sélecteur à 2 classes pour battre les règles génériques ci-dessus (même spécificité de
       pseudo-classe, spécificité de classe supérieure). */
    .planning-grid.planning-grid--recap .mud-table-head .mud-table-cell:last-child {
        width: 168px;
    }
    .planning-grid.planning-grid--recap .mud-table-head .mud-table-cell:not(:first-child):not(:last-child) {
        width: calc((100% - 308px) / 5);
    }
    /* Contenu ancré en haut de cellule. Par défaut MudTable centre verticalement (vertical-align
       hérité = middle) : dans une ligne haute (journée à plusieurs plages), une cellule courte
       (nom de salariée, total, case vide) est centrée à mi-hauteur → tout paraît désaligné et les
       lignes semblent se chevaucher. En ancrant tout en haut, chaque ligne se lit proprement. */
    .planning-grid .mud-table-cell { vertical-align: top; }
    /* De l'air vertical entre les lignes de salariées : une journée dense (plusieurs plages +
       pied d'actions) ne doit pas coller la salariée suivante — sinon les cellules se lisent
       comme si elles se chevauchaient. */
    .planning-grid .mud-table-body .mud-table-cell { padding-top: 10px; padding-bottom: 12px; }
    /* PAS de height:1px ici : mon enfant direct (.planning-cell) est lui-même height:100%,
       il s'effondrait alors à 1px et les plages débordaient sur la ligne suivante (lignes
       superposées). Les cellules d'une même ligne sont DÉJÀ égalisées à la hauteur de ligne
       par le table layout — comportement natif fiable, sans astuce de hauteur.
       Cases COURTES (« + » ou absence) : on les centre verticalement via vertical-align:middle,
       qui exploite cette hauteur de ligne native SANS dépendre d'un height:100% (fiable partout,
       et surtout : aucun risque d'effondrement). Les cases travaillées gardent vertical-align:top
       (plages ancrées en haut). */
    .planning-grid .mud-table-body .mud-table-cell:has(.planning-cell__add),
    .planning-grid .mud-table-body .mud-table-cell:has(.planning-cell__absence) { vertical-align: middle; }
    /* Bandes alternées : sur une semaine chargée (mêmes réunions d'équipe répétées d'une
       salariée à l'autre), on ne sait plus quelle ligne appartient à qui. Une teinte une ligne
       sur deux rend chaque salariée sans ambiguïté. Les cellules colorées (absence / validation)
       gardent leur fond propre par-dessus. */
    .planning-grid .mud-table-body .mud-table-row:nth-child(even) .mud-table-cell {
        background-color: var(--pb-bg-subtle);
    }
}

/* ─── Barre de navigation planning (structure à gauche / mois à droite) ──── */
.planning-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 4px 8px;
}
/* Modifier : pas de toggle structure, on aligne le sélecteur mois à droite. */
.planning-nav--right { justify-content: flex-end; }

/* Toggle structure (chip-pill, n structures) */
.structure-toggle {
    display: inline-flex;
    background: #ECEFF1;
    border-radius: 999px;
    padding: 3px;
    gap: 2px;
}
.structure-toggle__btn {
    appearance: none;
    border: 0;
    background: transparent;
    color: #455A64;
    font-family: inherit;
    font-weight: 600;
    font-size: 0.85rem;
    padding: 6px 16px;
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
    white-space: nowrap;
}
.structure-toggle__btn:hover:not(.is-active) { background: #CFD8DC; }
.structure-toggle__btn.is-active {
    background: var(--mud-palette-primary);
    color: #FFFFFF;
    box-shadow: 0 2px 6px rgba(0,0,0,0.12);
}

/* Navigateur mois (chevrons + label cliquable) */
.month-nav {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}

/* Navigateur année (chevrons + label simple) */
.year-nav {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}
.year-nav__label {
    display: inline-block;
    min-width: 8rem;
    text-align: center;
    font-weight: 700;
    font-size: 1.05rem;
    color: #263238;
    padding: 6px 12px;
}
.month-nav__center {
    position: relative;
}
.month-nav__label {
    appearance: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 8px;
    font-family: inherit;
    color: #263238;
    transition: background 0.15s ease;
}
.month-nav__label:hover { background: #ECEFF1; }
.month-nav__name {
    font-weight: 700;
    font-size: 1.05rem;
    text-transform: capitalize;
}
.month-nav__year {
    color: #757575;
    font-size: 0.95rem;
}

/* Popover de saut rapide (année + grille 12 mois) */
.month-picker-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1200;
    background: transparent;
}
.month-picker-popover {
    position: absolute;
    z-index: 1201;
    top: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: #FFFFFF;
    border: 1px solid #CFD8DC;
    border-radius: 12px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.16);
    padding: 10px 12px;
    width: 280px;
}
.month-picker__year {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}
.month-picker__year-label {
    font-weight: 700;
    font-size: 1rem;
    flex: 1;
    text-align: center;
}
.month-picker__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
}
.month-picker__btn {
    appearance: none;
    border: 1px solid transparent;
    background: #F5F5F5;
    color: #37474F;
    font-family: inherit;
    font-weight: 600;
    font-size: 0.85rem;
    padding: 8px 4px;
    border-radius: 8px;
    cursor: pointer;
    text-transform: capitalize;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.month-picker__btn:hover:not(.is-active) { background: #ECEFF1; }
.month-picker__btn.is-today:not(.is-active) {
    border-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary);
}
.month-picker__btn.is-active {
    background: var(--mud-palette-primary);
    color: #FFFFFF;
    border-color: var(--mud-palette-primary);
}
.month-picker__footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 8px;
    padding-top: 6px;
    border-top: 1px solid #ECEFF1;
}

/* Navigateur semaine ISO (chevrons + label cliquable + popover MudDatePicker) */
.week-nav {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}
.week-nav__center { position: relative; }
.week-nav__label {
    appearance: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: 8px;
    font-family: inherit;
    color: #263238;
    transition: background 0.15s ease;
}
.week-nav__label:hover { background: #ECEFF1; }
.week-nav__num {
    font-weight: 700;
    font-size: 1.05rem;
}
.week-nav__range {
    color: #757575;
    font-size: 0.95rem;
}
.week-picker-popover {
    position: absolute;
    z-index: 1201;
    top: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: #FFFFFF;
    border: 1px solid #CFD8DC;
    border-radius: 12px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.16);
    padding: 6px 6px 4px;
    width: 320px;
}

@media (max-width: 600px) {
    .planning-nav { justify-content: center; }
    .planning-nav--right { justify-content: center; }
    .month-nav__name { font-size: 0.95rem; }
    .month-nav__year { font-size: 0.85rem; }
    .week-nav__num { font-size: 0.95rem; }
    .week-nav__range { font-size: 0.82rem; }
    .structure-toggle__btn { padding: 5px 12px; font-size: 0.8rem; }
    .month-picker-popover { width: min(260px, 92vw); }
    .week-picker-popover { width: min(300px, 92vw); left: 50%; }

    /* Filet de sécurité pour tous les popovers MudBlazor non explicitement
       contraints (Select sans RelativeWidth.Relative, Menu, Tooltip…). Évite
       qu'un popover ouvert près du bord droit ne sorte du viewport mobile.
       Ne s'applique qu'aux popovers ouverts pour ne pas peser pendant l'idle.
       Les pickers (date/time) doivent passer en PickerVariant.Dialog plutôt
       que de compter sur cette règle. */
    .mud-popover.mud-popover-open {
        max-width: 95vw !important;
    }
}

/* MudBlazor 9.4 — Le clipping originel des picker dialogs imbriqués (clock
   face / calendar / palette coupés à droite, observé 2026-05-26) a finalement
   été traçé à la propagation du paramètre `Style` du `<MudTimePicker>` /
   `<MudColorPicker>` etc. à la fois sur l'input ET sur le toolbar du dialog
   overlay. Solution : ne PLUS passer `Style="width:Npx;..."` directement sur
   le picker — utiliser `Class="..."` ou wrapper dans un `<div>`. Cf. CLAUDE.md
   § « Pièges responsive MudBlazor (mobile) ». `Class` ne propage pas au
   toolbar (vérifié sur le DOM rendu) — donc safe pour contraindre la largeur.

   Les versions V1-V5 de filets CSS (5263926 → a83101b) qui tentaient de
   neutraliser le symptôme côté CSS ont été retirées : le root cause est
   maintenant fixé côté markup. */

/* ─────────────────────────────────────────────────────────────────────────
   JourneeTypeDialog — ligne créneau en grid layout
   ─────────────────────────────────────────────────────────────────────────
   Une ligne créneau aligne 7 éléments : Code / Début / → / Fin / Total /
   Couleur / Pause. On utilise CSS Grid pour fixer chaque cellule à une
   largeur précise indépendante de la largeur naturelle des MudPicker
   (qui sinon overflow la ligne et casse l'alignement vertical entre
   créneaux).

   Les widths sont posées sur les classes appliquées via `Class="..."`
   sur le MudPicker, qui cible le `.mud-input` interne. Pas de propagation
   parasite vers le toolbar du dialog overlay (cf. commentaire précédent).
*/

.pb-creneau-row {
    border-radius: 8px;
    background: var(--pb-bg-card);
    margin-bottom: 4px;
}

.pb-creneau-grid {
    display: grid;
    grid-template-columns: 64px 120px 20px 120px 64px 1fr 96px;
    gap: 6px;
    align-items: center;
}

/* Forcer les MudPicker et MudInputControl à remplir leur cellule de grille */
.pb-creneau-grid > .mud-picker,
.pb-creneau-grid > .mud-input-control,
.pb-creneau-grid > .mud-picker .mud-input,
.pb-creneau-grid > .mud-picker .mud-input-control,
.pb-creneau-grid > .mud-input-control .mud-input,
.pb-creneau-grid > .pb-creneau-color > .mud-picker,
.pb-creneau-grid > .pb-creneau-color > .mud-picker .mud-input,
.pb-creneau-grid > .pb-creneau-color > .mud-picker .mud-input-control {
    width: 100%;
}

/* Flèche entre Début et Fin */
.pb-creneau-arrow {
    text-align: center;
    color: var(--pb-text-muted);
    font-size: 1.1rem;
    line-height: 1;
    user-select: none;
}

/* Total — mis en valeur (chiffre principal du créneau) */
.pb-creneau-total {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--pb-color-text-stronger);
    text-align: center;
    line-height: 1.2;
}

.pb-creneau-total-empty {
    color: var(--pb-text-disabled);
    font-weight: 400;
    font-size: 1rem;
}

/* Couleur — pastille + input hex côte à côte */
.pb-creneau-color {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.pb-creneau-color-dot {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid var(--pb-border-soft);
    flex-shrink: 0;
    transition: background-color 0.15s ease;
}

.pb-creneau-color > .mud-picker {
    flex: 1;
    min-width: 0;
}

/* ⚠️ L'ancienne règle .planning-cell « cellule-lettre » 36×36 (design pré-refonte Vague G,
   mort — plus aucun consommateur) a été RETIRÉE ici : elle posait align-items:center +
   justify-content:center + font-size:0.75rem qui FUITAIENT dans la nouvelle grille (même nom
   de classe). Conséquence : les enfants flex-colonne .planning-cell__plages et .__foot étaient
   RÉTRÉCIS-CENTRÉS (au lieu d'être étirés sur toute la largeur) → largeurs différentes → bords
   droits différents → décalage des créneaux ET des durées/total. La seule règle .planning-cell
   valable est celle du bloc grille plus bas (« Cellule d'une grille planning / modèle »), qui
   étire (align-items:stretch par défaut). Les classes .planning-cell-absence/-empty/-active/
   -verrouille/-lock ci-dessous sont du même design mort (aucun usage razor/cs). */

/* Cartouche d'absence (FE / CP / RTT / AM / EC / CSS / DE / …) — overlay zébré
   diagonal pour distinguer d'un coup d'œil les cellules « absence » des cellules
   « créneau de travail » (toutes deux sont des pavés colorés pleins). Le fond
   coloré arrive en `background-color` inline ; le `background-image` ci-dessous
   pose les rayures par-dessus. Important : côté inline, utiliser `background-color:`
   et JAMAIS le shorthand `background:` — sinon le gradient est écrasé. */
.planning-cell-absence {
    background-image: repeating-linear-gradient(
        45deg,
        rgba(255, 255, 255, 0) 0,
        rgba(255, 255, 255, 0) 6px,
        rgba(255, 255, 255, 0.55) 6px,
        rgba(255, 255, 255, 0.55) 12px
    );
}

/* Cellule vide cliquable (pour sélection en saisie rapide) */
.planning-cell-empty {
    min-width: 36px;
    height: 36px;
    margin: auto;
    border-radius: 6px;
    border: 1px dashed #CFD8DC;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.planning-cell-empty:hover {
    background: #ECEFF1;
    border-color: #90A4AE;
}

/* Cellule active (sélectionnée en saisie rapide) */
.planning-cell-active {
    outline: 3px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* Cellule verrouillée — bordure dorée + cadenas en surimpression, signale qu'une
   RAZ globale ne supprimera pas cette affectation. Le contenu (code lettre) reste
   centré ; le 🔒 se pose en haut à droite. */
.planning-cell-verrouille {
    position: relative;
    box-shadow: inset 0 0 0 2px #F9A825;
}
.planning-cell-lock {
    position: absolute;
    top: -4px;
    right: -4px;
    font-size: 0.6rem;
    line-height: 1;
    background: #fff;
    border-radius: 50%;
    padding: 1px 2px;
    box-shadow: 0 0 0 1px #F9A825;
}

/* Saisie HorsTerrain affichée dans la grille admin : rectangle de couleur secondaire
   rayé pour le distinguer d'un créneau Terrain plein. La variable `--couleur-creneau`
   (couleur du type d'heure / saisie) est posée inline sur l'élément. */
.creneau-ht {
    width: 100%;
    height: 12px;
    margin-top: 2px;
    border-radius: 4px;
    background: repeating-linear-gradient(
        45deg,
        var(--couleur-creneau, #BDBDBD),
        var(--couleur-creneau, #BDBDBD) 4px,
        rgba(255, 255, 255, 0.6) 4px,
        rgba(255, 255, 255, 0.6) 8px
    );
}

/* ─── Mon planning (vue salarié, par jour) ───────────────────────────────── */
/* Grille date | contenu : aligne les sous-lignes (réunions, saisies) avec
   le créneau principal sur desktop, et empile date + contenu sur mobile. */
.mp-jour__grid {
    display: grid;
    grid-template-columns: 64px minmax(0, 1fr);
    gap: 12px;
    align-items: start;
}

.mp-jour__date {
    padding-top: 6px;
    font-size: 0.875rem;
    color: #455A64;
    line-height: 1.3;
    white-space: nowrap;
}

.mp-jour__content {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

/* Une "entrée" représente un événement du jour : créneau d'origine, amendement,
   réunion, ajout, absence. La bordure gauche colorée (--mp-entry-color) signale
   à l'œil le type/créneau ; chaque entrée est un bloc auto-portant. */
.mp-entry {
    border-left: 4px solid var(--mp-entry-color, #BDBDBD);
    background: var(--pb-bg-subtle, #FAFAFA);
    padding: 6px 8px 6px 10px;
    border-radius: 0 4px 4px 0;
    min-width: 0;
}

.mp-entry__row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    min-width: 0;
}

.mp-entry__time {
    font-weight: 600;
    font-size: 0.95rem;
    color: #263238;
}

.mp-entry__title {
    font-size: 0.95rem;
    color: #263238;
}

.mp-entry__sub {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
    flex-wrap: wrap;
    min-width: 0;
}

.mp-entry__caption {
    font-size: 0.78rem;
    color: var(--pb-text-muted, #757575);
}

.mp-entry__note {
    margin-top: 4px;
    font-size: 0.78rem;
    color: #9E9E9E;
    font-style: italic;
}

.mp-entry__note--erreur {
    color: #E53935;
    font-weight: 600;
    font-style: normal;
}

.mp-entry__actions {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
    margin-left: auto;
}

/* Badge structure compact (code court). La palette CSS est dérivée d'un hash
   du code via StructureBadgeHelper — couleurs pastel, contraste suffisant
   pour être lisible. */
.structure-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    line-height: 1.4;
    white-space: nowrap;
}
.structure-badge--c0 { background: #E3F2FD; color: #0D47A1; }
.structure-badge--c1 { background: #E8F5E9; color: #1B5E20; }
.structure-badge--c2 { background: #FFF3E0; color: #E65100; }
.structure-badge--c3 { background: #F3E5F5; color: #4A148C; }
.structure-badge--c4 { background: #FFEBEE; color: #B71C1C; }
.structure-badge--c5 { background: #E1F5FE; color: #01579B; }
.structure-badge--c6 { background: #FFF9C4; color: #F57F17; }

@media (max-width: 600px) {
    /* Date sur sa propre ligne, créneau et sous-lignes pleine largeur dessous. */
    .mp-jour__grid {
        grid-template-columns: minmax(0, 1fr);
        gap: 4px;
    }
    .mp-jour__date {
        padding-top: 0;
        font-weight: 700;
        color: #263238;
        font-size: 0.95rem;
    }
    .mp-entry__time { font-size: 0.9rem; }
    .structure-badge { font-size: 0.68rem; }
}

/* Palette d'affectation rapide — popover ancré aux coords du curseur */
.palette-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1200;
    background: transparent;
}

.palette-popover {
    position: fixed;
    z-index: 1201;
    background: #FFFFFF;
    border-radius: 10px;
    border: 1px solid var(--mud-palette-primary);
    box-shadow: 0 6px 18px rgba(0,0,0,0.18);
    padding: 10px 14px;
    /* Largeur fixe (au lieu d'un min-width/max-width qui s'adaptait au contenu) :
       garantit que la palette a toujours la même empreinte visuelle qu'on ait ou
       non une affectation courante (boutons Verrouiller/Modifier horaires en plus).
       Sans ça, l'admin voit la palette « sauter » entre 2 tailles selon la cellule
       cliquée — gêne UX remontée en validation manuelle Sprint 2. */
    width: 340px;
    /* Empêche tout dépassement viewport sur petit écran (cf. media query mobile). */
    max-width: 90vw;
    transform: translate(0, 0);
}
@media (max-width: 600px) {
    .palette-popover {
        width: 95vw;
        max-width: 95vw;
    }
}

/* Grid uniforme des créneaux pour aligner les cellules en colonnes régulières
   plutôt que d'avoir un flex-wrap qui laisse un gap d'air aléatoire à droite
   sur la 2e ligne. 4 colonnes par défaut, 3 sur mobile pour conserver une
   cellule lisible. */
.palette-creneaux-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
}
@media (max-width: 600px) {
    .palette-creneaux-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

.palette-creneau {
    min-width: 0;
    height: 56px;
    border-radius: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: white;
    font-weight: 700;
    transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.12s ease;
    user-select: none;
    padding: 0 4px;
    overflow: hidden;
}
.palette-creneau:hover:not(.palette-creneau--disabled) {
    transform: translateY(-2px);
    box-shadow: 0 4px 10px rgba(0,0,0,0.18);
}
.palette-creneau--disabled {
    opacity: 0.25;
    cursor: not-allowed;
    filter: grayscale(0.4);
}
.palette-creneau--current {
    outline: 3px solid #212121;
    outline-offset: 2px;
}
.palette-creneau .code {
    font-size: 1.2rem;
    line-height: 1;
}
.palette-creneau .horaire {
    font-size: 0.65rem;
    opacity: 0.9;
    max-width: 100%;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
}

/* Bouton "X créneaux ▾" cliquable dans l'en-tête de chaque jour de la grille admin.
   Permet de changer le JourneeType d'un jour ouvré tant que le planning est en Draft. */
.header-jt-btn {
    background: transparent;
    border: 1px dashed #CFD8DC;
    border-radius: 6px;
    padding: 1px 6px;
    color: #607D8B;
    font-size: 0.65rem;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
    display: inline-flex;
    align-items: center;
    gap: 3px;
}
.header-jt-btn:hover {
    background: #ECEFF1;
    color: #37474F;
    border-color: #90A4AE;
}
/* Variante read-only (planning publié) — pas de bordure pointillée ni de hover. */
.header-jt-btn--readonly {
    border-style: solid;
    cursor: default;
}
.header-jt-btn--readonly:hover {
    background: transparent;
    color: #607D8B;
    border-color: #CFD8DC;
}
/* États de couverture : orange doux = au moins un créneau pris mais incomplet,
   vert = tous les créneaux du JourneeType sont affectés. Sans modifier =
   blanc / neutre = aucun créneau saisi pour ce jour. Spécificité doublée
   (.header-jt-btn.header-jt-btn--xxx) pour battre la déclaration `border:`
   shorthand de `.header-jt-btn` dans tous les navigateurs. */
.header-jt-btn.header-jt-btn--partial,
.header-jt-btn.header-jt-btn--partial:hover {
    background: #FFF3E0;
    color: #E65100;
    border: 1px solid #FFCC80;
}
.header-jt-btn.header-jt-btn--complete,
.header-jt-btn.header-jt-btn--complete:hover {
    background: #E8F5E9;
    color: #2E7D32;
    border: 1px solid #A5D6A7;
}
.header-jt-caret {
    font-size: 0.7rem;
    line-height: 1;
}

/* Badge créneau de fermeture */
.badge-fermeture {
    background: #FFE0E0;
    color: #C62828;
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 0.7rem;
    font-weight: 700;
}

/* Chip statut planning */
.chip-draft { background: #FFF9C4 !important; color: #F57F17 !important; }
.chip-publie { background: #E8F5E9 !important; color: #2E7D32 !important; }
.chip-cloture { background: #EDE7F6 !important; color: #4527A0 !important; }

/* Quota bar — barre empilée par catégorie d'heures */
.quota-bar-stacked {
    display: flex;
    width: 100%;
    height: 10px;
    border-radius: 8px;
    background: #EEEEEE;
    overflow: hidden;
}
.quota-bar-segment {
    height: 100%;
    transition: width 0.3s ease;
}

/* Légende du quota — items alignés sur 1 ligne (wrap si la viewport est trop étroite) */
.quota-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 18px;
}
.quota-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}
.quota-legend__dot {
    width: 10px;
    height: 10px;
    border-radius: 2px;
    flex-shrink: 0;
    display: inline-block;
}
.quota-legend__label {
    color: #757575;
    font-size: 0.75rem;
}
.quota-legend__value {
    font-size: 0.875rem;
    font-weight: 500;
}

/* Salariée color dot */
.salarie-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    display: inline-block;
    flex-shrink: 0;
}

/* Pastille « hors compteur » utilisée sur tables/cartes affichant une salariée
   exclue des totaux d'équipe (compteurs heures, récap planning, fiche salariée). */
.hors-compteur-pastille {
    font-size: 0.7rem;
    font-weight: 700;
    background: #ECEFF1;
    color: #546E7A;
    padding: 1px 6px;
    border-radius: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Ligne « hors compteur » dans une grille dense (compteurs absences/heures) :
   salariée affichée mais exclue des totaux d'équipe. Générique sur toute table
   dense — le fond grisé de la variante carte reste scopé côté composant. */
tr.ligne-hors-compteur td { color: var(--pb-text-disabled); font-style: italic; }

/* Récap latéral (sticky) — toujours visible à droite de la grille planning */
.recap-lateral-sticky {
    position: sticky;
    top: 16px;
    max-height: calc(100vh - 32px);
    overflow-y: auto;
    padding-right: 4px;
}

.recap-lateral-card {
    background: var(--pb-surface);
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.recap-lateral-card:hover {
    box-shadow: 0 2px 8px rgba(0,0,0,0.06);
    border-color: #CFD8DC !important;
}

.recap-lateral-line {
    align-items: center;
    min-height: 22px;
}

/* Puce ultra-compacte du panneau récap (fermetures, vendredi) */
.recap-puce.mud-chip-size-small {
    height: 18px;
    min-width: 22px;
    padding: 0 6px;
    font-size: 0.7rem;
    font-weight: 700;
}

/* Mobile responsive */
@media (max-width: 600px) {
    .planning-cell {
        min-width: 28px;
        height: 28px;
        font-size: 0.65rem;
    }
}

/* Scrollbar custom */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #BDBDBD; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #9E9E9E; }

/* ─── Planning équipe (vue salarié, lecture seule) ───────────────────────── */
.planning-equipe-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}
.planning-equipe-table th,
.planning-equipe-table td {
    border: 1px solid #ECEFF1;
    padding: 6px 6px;
    vertical-align: middle;
    text-align: center;
    font-size: 0.85rem;
}
.planning-equipe-table th {
    background: #F5F7FA;
    color: #37474F;
    font-weight: 700;
    padding: 8px 6px;
}
.planning-equipe-table .th-jour-nom {
    font-size: 0.9rem;
    font-weight: 700;
}
.planning-equipe-table .th-jour-date {
    color: #757575;
    font-size: 0.72rem;
    margin-top: 2px;
}
.planning-equipe-table .th-jour-ferie {
    color: #E65100;
    font-size: 0.65rem;
    font-weight: 700;
    margin-top: 2px;
}
.planning-equipe-table .th-sub-row th.th-sub {
    background: #FAFBFC;
    font-weight: 500;
    color: #90A4AE;
    font-size: 0.65rem;
    padding: 3px 4px;
    letter-spacing: 0.02em;
}
.planning-equipe-table .th-sub .th-sub-creneau { color: #455A64; font-weight: 600; }
.planning-equipe-table .th-sub .th-sub-reunion { color: #78909C; font-style: italic; }
.planning-equipe-table .th-sub .th-sub-sep { margin: 0 4px; color: #CFD8DC; }

.planning-equipe-table .col-salarie {
    text-align: left;
    width: 150px;
    min-width: 150px;
    background: #FAFBFC;
    padding-left: 12px;
}
.planning-equipe-table .col-jour {
    width: 130px;
    min-width: 130px;
}
.planning-equipe-table .col-total {
    width: 95px;
    min-width: 95px;
    background: #F0F4F7;
    font-weight: 700;
}
.planning-equipe-table .total-week {
    font-size: 0.95rem;
    color: #263238;
}
.planning-equipe-table .cell-salarie {
    display: flex;
    align-items: center;
    gap: 8px;
}
.planning-equipe-table .salarie-prenom {
    font-weight: 700;
    font-size: 0.9rem;
    color: #263238;
}

/* Ligne « créneau » (1ʳᵉ ligne par salariée) */
.planning-equipe-table .row-creneau td.cell-creneau {
    height: 44px;
    padding: 6px 4px;
    background: #FFFFFF;
}
.planning-equipe-table .creneau-hours {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    border-left: 4px solid #BDBDBD;
    background: #F5F7FA;
    padding: 5px 8px;
    border-radius: 4px;
    font-weight: 600;
    color: #263238;
    white-space: nowrap;
    font-size: 0.85rem;
    min-width: 96px;
    justify-content: center;
}
.planning-equipe-table .creneau-hours-text {
    font-variant-numeric: tabular-nums;
}
.planning-equipe-table .creneau-pill {
    display: inline-block;
    color: white;
    font-weight: 700;
    border-radius: 4px;
    padding: 5px 12px;
    font-size: 0.85rem;
    min-width: 44px;
    letter-spacing: 0.03em;
}
.planning-equipe-table .cell-empty {
    color: #CFD8DC;
    font-size: 1rem;
}

/* Ligne « réunion » (2ᵉ ligne par salariée) */
.planning-equipe-table .row-reunion td.cell-reunion {
    height: 30px;
    padding: 3px 4px;
    background: #FAFBFC;
    border-top: 1px dashed #E0E0E0;
}
.planning-equipe-table .row-reunion td:not(.col-salarie):not(.col-total) {
    border-bottom: 2px solid #CFD8DC;
}
.planning-equipe-table .reunion-tag {
    display: inline-block;
    background: #E8EAF6;
    color: #3949AB;
    border-radius: 3px;
    padding: 2px 6px;
    font-size: 0.72rem;
    font-weight: 600;
    margin: 1px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.planning-equipe-total-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #FAFAFA;
    border: 1px solid #ECEFF1;
    border-radius: 999px;
    padding: 6px 14px;
    font-size: 0.85rem;
}

/* ─── Planning équipe — vue mobile : carte par JOUR avec liste salariées ─ */
.planning-equipe-mobile { display: flex; flex-direction: column; gap: 8px; }

/* Jour / ligne / carte « en absence » (CP, FE, EC, AM, …) : filet gauche coloré de
   la raison. Le fond teinté et la couleur du filet sont posés inline via
   AbsenceVisuel.LigneStyle (couleur = TypeAbsence.CouleurHex). Fait ressortir la
   raison sur toute la ligne, pas seulement via un chip. */
.pb-jour-absence {
    border-left-width: 4px;
    border-left-style: solid;
}
/* Variante ligne salariée (vue équipe mobile) : arrondi + retrait pour matérialiser
   le bloc absence dans la carte-jour. */
.planning-equipe-day__row.pb-jour-absence {
    border-radius: 6px;
    padding-left: 8px;
}

.planning-equipe-day__header {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding-bottom: 6px;
    border-bottom: 1px dashed #ECEFF1;
    margin-bottom: 6px;
}
.planning-equipe-day__name {
    font-weight: 700;
    color: #263238;
    font-size: 0.95rem;
    text-transform: capitalize;
}
.planning-equipe-day__date {
    color: #607D8B;
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}
.planning-equipe-day__ferie {
    margin-left: auto;
    color: #E65100;
    font-size: 0.75rem;
    font-weight: 700;
}
.planning-equipe-day__fermeture-msg {
    display: block;
    color: #757575;
    font-style: italic;
    font-size: 0.85rem;
    padding: 2px 0 4px;
}

/* Ligne salariée d'une carte-jour : en-tête (dot + prénom) puis corps empilé en
   dessous (timeline des plages, indenté) — même anatomie que Mon planning
   (en-tête crèche + timeline). */
.planning-equipe-day__row {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 6px 0;
}
.planning-equipe-day__row + .planning-equipe-day__row {
    border-top: 1px solid #F5F5F5;
}

.planning-equipe-day__salarie {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    color: #263238;
    font-size: 0.85rem;
}
.planning-equipe-day__salarie .salarie-dot {
    width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0;
}

/* Corps de la ligne salariée : timeline des plages, total et actions, indenté
   sous le prénom pour rattacher visuellement au bon salariée. */
.planning-equipe-day__body {
    padding-left: 16px;
    min-width: 0;
}

/* Vue mobile admin /admin/planning : bouton "+ ajouter" inline pour une cellule
   vide cliquable. Plus visible que le `cell-empty` du salarié (qui rend juste
   "—") puisqu'on veut signaler une action interactive — pas seulement une
   case sans contenu. */
.planning-mobile-cell-empty {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 96px;
    padding: 4px 10px;
    border: 1px dashed #CFD8DC;
    border-radius: 4px;
    color: var(--mud-palette-primary);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.planning-mobile-cell-empty:hover {
    background: #ECEFF1;
    border-color: #90A4AE;
}
.planning-mobile-cell-empty.planning-cell-active {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* Wrapper de la vue mobile admin : juste un gap vertical entre les MudPaper jour. */
.planning-mobile-week {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 8px;
}

/* FAB Menu mobile : position fixed en bas à droite, accessible au pouce.
   Au-dessus de la cible 56 px du Material Design pour confort tactile. z-index
   élevé pour passer au-dessus du contenu scrollé. */
.page-fab {
    position: fixed;
    bottom: 16px;
    right: 16px;
    z-index: 1100;
}

/* Speed Dial pour PageHeader.Actions / EnTeteFiche.Actions sur mobile.
   Cf. CLAUDE.md § « Guide UI / UX (strict) » → Speed Dial mobile. */
.speed-dial-container {
    position: fixed;
    bottom: 16px;
    right: 16px;
    z-index: 1100;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
}

.speed-dial-stack {
    display: flex;
    flex-direction: column-reverse;
    align-items: flex-end;
    gap: 8px;
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transform: translateY(20px);
    transition: max-height 200ms ease-out, opacity 200ms ease-out, transform 200ms ease-out;
    pointer-events: none;
}

.speed-dial-container.is-open .speed-dial-stack {
    max-height: 600px;
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.speed-dial-overlay {
    z-index: 1099;
}

/* Layout 2 colonnes de la fiche salariée /admin/salaries/{id}. Desktop : la
   col gauche empile les blocs md=8 en flot continu indépendamment de la
   hauteur de la col droite (md=4 dominée par Planning) — évite le trou
   vertical qu'imposait un MudGrid quand Planning est plus haut que Compteurs
   Abs. Mobile (≤ 600 px) : `display: contents` rend les col wrappers
   transparents au layout, les blocs deviennent enfants directs de
   .salarie-details-layout (flex column) et sont réordonnés par les classes
   .salarie-mob-order-N ci-dessous. Cf. SalarieDetails.razor commentaire
   d'intro. */
.salarie-details-layout {
    display: flex;
    flex-direction: column;
}

@media (min-width: 960px) {
    .salarie-details-layout {
        display: grid;
        grid-template-columns: 2fr 1fr;
        grid-template-areas:
            "wide narrow"
            "full full";
        column-gap: 12px;
        align-items: start;
    }
    .salarie-details-layout > .col-wide {
        grid-area: wide;
        display: flex;
        flex-direction: column;
        min-width: 0;
    }
    .salarie-details-layout > .col-narrow {
        grid-area: narrow;
        display: flex;
        flex-direction: column;
        min-width: 0;
    }
    .salarie-details-layout > .col-full {
        grid-area: full;
    }
}

@media (max-width: 959.95px) {
    .salarie-details-layout > .col-wide,
    .salarie-details-layout > .col-narrow {
        display: contents;
    }
}

@media (max-width: 600px) {
    .salarie-mob-order-1 { order: 1; }
    .salarie-mob-order-2 { order: 2; }
    .salarie-mob-order-3 { order: 3; }
    .salarie-mob-order-4 { order: 4; }
    .salarie-mob-order-5 { order: 5; }
    .salarie-mob-order-6 { order: 6; }
    .salarie-mob-order-7 { order: 7; }
}

/* Réutilisation des pills creneau-hours/creneau-pill/reunion-tag/cell-empty
   définies plus haut (table desktop). Mêmes styles, on évite la duplication. */
.planning-equipe-day .creneau-hours {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border-left: 4px solid;
    padding-left: 6px;
    font-weight: 600;
    font-size: 0.85rem;
    color: #263238;
    font-variant-numeric: tabular-nums;
}
/* Pavé carré coloré portant le code lettre du créneau, devant l'horaire. Aide
   à positionner mentalement l'action (matin/midi/soir/fermeture) sans avoir à
   lire l'horaire complet. */
.planning-equipe-day .creneau-hours__code {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 20px;
    padding: 0 5px;
    border-radius: 4px;
    color: #fff;
    font-weight: 700;
    font-size: 0.75rem;
    letter-spacing: 0.02em;
}
.planning-equipe-day .creneau-pill {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-weight: 700;
    font-size: 0.75rem;
    color: #fff;
}
.planning-equipe-day .reunion-tag {
    display: inline-block;
    background: #E8EAF6;
    color: #3949AB;
    border-radius: 3px;
    padding: 1px 5px;
    font-size: 0.7rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.planning-equipe-day .cell-empty {
    color: #9E9E9E;
    font-size: 0.85rem;
}

/* ─── Mon planning (/salarie/planning) — carte jour en timeline ──────── */
/* En-tête de carte : nom du jour à gauche, total de la journée + actions
   épinglés à droite. `nowrap` est volontaire — jour / heures / Valider / crayon
   tiennent sur UNE ligne, y compris à 375 px : sans ça le groupe d'actions
   repassait sous le nom du jour dès que le total faisait 4 caractères (7h30). */
.mon-planning-jour__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding-bottom: 6px;
    margin-bottom: 6px;
    border-bottom: 1px dashed var(--pb-border-light);
    flex-wrap: nowrap;
}
.mon-planning-jour__name {
    font-weight: 700;
    color: var(--pb-color-text-stronger);
    font-size: 0.95rem;
    text-transform: capitalize;
    white-space: nowrap;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
.mon-planning-jour__header-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}
.mon-planning-jour__actions {
    display: flex;
    align-items: center;
    gap: 6px;
}
/* Boutons d'action de l'en-tête : cible tactile WCAG 2.5.5 (≥ 44 px) sans la
   min-width de 64 px de MudButton, qui pousserait le crayon hors de la ligne. */
.mon-planning-jour__btn.mud-button-root {
    min-height: 44px;
    min-width: 0;
    white-space: nowrap;
}
.mon-planning-jour__btn--icon.mud-button-root {
    width: 44px;
    padding-left: 0;
    padding-right: 0;
}
.mon-planning-jour__total {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--pb-color-text-strong);
    white-space: nowrap;
}

/* Groupe crèche. Cliquable (ouvre le popover de la journée pour cette crèche)
   uniquement si la journée est saisissable — une journée à venir est en lecture
   seule, le popover n'apporterait rien de plus que la carte. */
.mon-planning-creche {
    padding: 4px;
    border-radius: 8px;
    transition: background 0.15s ease;
}
.mon-planning-creche--tappable { cursor: pointer; }
.mon-planning-creche--tappable:hover { background: var(--pb-bg-subtle); }
.mon-planning-creche + .mon-planning-creche {
    margin-top: 6px;
    border-top: 1px solid var(--pb-border-light);
}
.mon-planning-creche__header {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 4px;
}
.mon-planning-creche__total {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--pb-color-text-strong);
    white-space: nowrap;
}

/* Une plage = une ligne : filet coloré du type (posé inline), horaire, libellé
   du type, contenu additionnel optionnel, durée épinglée à droite. Classe
   partagée (composant PlageTimelineLigne) entre Mon planning et la vue mobile
   des grilles planning équipe. */
.plage-line {
    display: flex;
    align-items: center;
    justify-content: space-between;   /* groupe gauche (horaires + type) / durée à droite */
    gap: 10px;
    border-left: 3px solid var(--pb-border-soft);
    padding: 3px 0 3px 10px;
}
.plage-line + .plage-line { margin-top: 3px; }
/* Groupe gauche : horaires + libellé du type (+ contenu additionnel), tronqué si trop long. */
.plage-line__main {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    overflow: hidden;
}
.plage-line__time {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--pb-color-text-stronger);
    white-space: nowrap;
}
.plage-line__type {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.8rem;
    font-weight: 600;
}
.plage-line__duree {   /* colonne de largeur fixe, texte à droite → même colonne que le total du jour */
    flex: 0 0 auto;
    min-width: 3em;
    text-align: right;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--pb-text-muted);
    white-space: nowrap;
}

/* ─── Cellule d'une grille planning / modèle : plages en lignes timeline, pied
   avec actions à gauche et total à droite (fin des « cartouches » en pilule).

   La cellule remplit toute la hauteur de la ligne (height:100% dans une table-cell = hauteur
   de ligne) : les plages sont épinglées en HAUT et le pied en BAS (margin-top:auto). Résultat,
   d'une cellule à l'autre d'une même ligne, les barres de créneaux s'alignent en haut et les
   boutons d'action s'alignent en bas — quel que soit le nombre de plages. Ça neutralise aussi
   le vertical-align:middle hérité de MudBlazor qui faisait « flotter » le contenu au centre. ─ */
/* align-items par défaut = stretch → .planning-cell__plages et .planning-cell__foot occupent
   TOUTE la largeur de la cellule (bords droits identiques → durées de plage et total alignés).
   font-size:0.75rem conserve la densité de la grille (avant, elle fuitait de l'ancienne règle). */
.planning-cell { display: flex; flex-direction: column; gap: 4px; width: 100%; height: 100%; font-size: 0.75rem; }
/* Retrait gauche = padding interne réel du MudIconButton size-small (3px) + demi-icône (~9px)
   → centre de l'icône « copier » ≈ 12px. La barre colorée (3px) de la 1re plage est retraitée
   de 11px pour que son centre tombe SOUS le centre de l'icône. Sans ça, barres (bord 0) et
   icônes (~12px) forment deux bords gauches → décalage perçu, d'autant plus visible qu'il y a
   de plages. Le bouton n'est pas touché (son pied reste parfait). */
.planning-cell__plages { display: flex; flex-direction: column; gap: 3px; padding-left: 11px; }
.planning-cell__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;   /* actions à gauche, total à droite */
    gap: 6px;
    width: 100%;                      /* occupe toute la largeur de la cellule pour que le total soit collé à droite */
    flex-wrap: wrap;                  /* si trop étroit, le total passe sous les actions (jamais de chevauchement) */
    margin-top: auto;                 /* colle le pied en bas → boutons alignés d'une cellule à l'autre */
    padding-top: 4px;
    border-top: 1px solid var(--pb-border-light);   /* sépare nettement le pied des plages */
}
/* Boutons du pied : bord gauche à x=0, comme la colonne d'actions. Pas de marge négative. */
.planning-cell__actions { display: flex; align-items: center; gap: 0; margin-left: 0; }
/* Cellule vide : « + » (et « coller » quand un presse-papier est actif) centrés horizontalement.
   Le centrage VERTICAL vient du vertical-align:middle posé sur la table-cell (cf. plus haut) — pas
   de height:100% (qui s'effondrerait). Le gap sépare « + » et « coller » quand les deux sont là. */
.planning-cell__add { display: flex; justify-content: center; gap: 4px; }
/* Cartouche d'absence : alignée à GAUCHE au même retrait que les barres de plages (11px). Le
   centrage VERTICAL (milieu) vient du vertical-align:middle de la table-cell — pas de height:100%. */
.planning-cell__absence { display: flex; justify-content: flex-start; padding-left: 11px; }
/* Éditeur de modèle : cellule vide → le pied ne contient que le « + ». Pas de séparateur, « + »
   collé en bas (margin-top:auto) pour rester aligné avec les pieds des cellules voisines, centré
   horizontalement. (La grille planning, elle, utilise .planning-cell__add — « + » centré.) */
.planning-cell__foot--empty { border-top: none; padding-top: 0; margin-top: auto; justify-content: center; }
.planning-cell__meta {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-left: auto;   /* ancre le total (et le badge d'état) à droite, même sans actions ou après wrap */
}
.planning-cell__total {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--pb-text-muted);
    white-space: nowrap;
}
.planning-cell__alerte {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--pb-color-warning-dark);
}

/* Récap de fin de ligne d'une grille modèle (dernière colonne) : écart contrat + répartition
   par type d'heure de la semaine. Lignes « libellé à gauche / valeur à droite », valeurs en
   chiffres tabulaires pour s'aligner verticalement d'une salariée à l'autre. Le libellé porte
   la couleur sémantique de son type (posée inline depuis TypeHeureFormatter). */
.planning-recap { display: flex; flex-direction: column; gap: 2px; font-size: 0.7rem; }
.planning-recap__ligne {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
}
.planning-recap__libelle { color: var(--pb-text-muted); white-space: nowrap; }
.planning-recap__valeur {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ─── Enfants liste — cartes mobile ─────────────────────────────────── */
.enfants-mobile-cards { display: flex; flex-direction: column; gap: 8px; }

.enfant-card {
    cursor: pointer;
    transition: background 0.15s;
}

.enfant-card:hover { background: #FAFAFA; }

.print-only { display: none; }

/* ─── Planning présence enfants ───────────────────────────────────────────── */
.pb-presence-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}
.pb-presence-nav {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.pb-presence-mois {
    min-width: 160px;
    text-align: center;
    font-size: 1.1rem;
    font-weight: 600;
    color: #263238;
}
.pb-presence-legende {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    font-size: 0.82rem;
    color: var(--pb-text-muted);
}
.pb-presence-legende-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.pb-presence-pastille {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.08);
}
.pb-presence-titre {
    font-size: 14pt;
    font-weight: 700;
    color: #263238;
    margin: 0 0 6mm;
}
.pb-presence-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    table-layout: fixed;
    background: #fff;
    border: 1px solid var(--pb-border-light);
    border-radius: 8px;
    overflow: hidden;
}
.pb-presence-table thead th {
    background: #FAFAFA;
    color: #455A64;
    font-weight: 600;
    font-size: 0.85rem;
    text-align: center;
    padding: 8px 6px;
    border-bottom: 1px solid var(--pb-border-light);
}
.pb-presence-table thead th .jour-libelle {
    display: inline-block;
}
.pb-presence-table thead th .jour-count {
    display: inline-block;
    margin-left: 6px;
    background: #ECEFF1;
    color: #455A64;
    font-size: 0.72rem;
    font-weight: 700;
    border-radius: 999px;
    padding: 1px 8px;
    font-variant-numeric: tabular-nums;
}
.pb-presence-table thead th.depasse .jour-count {
    background: #FFCDD2;
    color: #B71C1C;
}
.pb-presence-table tbody td {
    height: 30px;
    text-align: center;
    font-size: 0.85rem;
    padding: 3px 6px;
    border-right: 1px solid #F0F2F4;
    border-bottom: 1px solid #F0F2F4;
}
.pb-presence-table tbody td:last-child { border-right: none; }
.pb-presence-table tbody tr:last-child td { border-bottom: none; }
/* Zébrage par ligne pour faciliter la lecture horizontale (suivi d'un enfant
   sur la semaine). Le fond de cellule (cell-enfant / cell-vide / absence)
   surcharge le zébrage là où il a une sémantique propre. */
.pb-presence-table tbody tr:nth-child(odd) td { background: #FAFAFA; }
.pb-presence-table tbody tr:nth-child(even) td { background: #FFFFFF; }

/* Jour non réservé pour cet enfant (= absent du contrat) — bleu-gris froid
   distinct du zébrage neutre. */
.pb-presence-table .cell-vide,
.pb-presence-table tbody tr:nth-child(odd) td.cell-vide,
.pb-presence-table tbody tr:nth-child(even) td.cell-vide {
    background: #E3F2FD;
}

.pb-presence-table .cell-enfant {
    color: #263238;
    font-weight: 500;
    border-radius: 3px;
    text-align: left;
    padding: 4px 8px !important;
    vertical-align: middle;
}
/* Surcharge du zébrage sur les cellules à sémantique forte (allergie / absence) */
.pb-presence-table tbody tr td.cell-enfant.has-allergie { background: #FFEBEE; }

/* Vue semaine : cellules plus larges, layout interne flex (nom à gauche, actions à droite) */
.pb-presence-table--semaine thead th .jour-libelle {
    font-weight: 700;
    text-transform: capitalize;
}
.pb-presence-table--semaine thead th .jour-date {
    display: inline-block;
    margin-left: 4px;
    color: #757575;
    font-weight: 500;
    font-size: 0.78rem;
}

.pb-presence-table .cell-row {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
}
.pb-presence-table .cell-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pb-presence-table .cell-name.is-absent {
    text-decoration: line-through;
    color: #90A4AE;
}
.pb-presence-table .cell-actions {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
}
.pb-presence-table .cell-chip {
    font-size: 0.72rem !important;
    height: 22px !important;
    font-weight: 600;
}

/* Chip type-repas — fond + texte colorés via TypeRepasHelper.CouleurFond/CouleurTexte,
   appliqués inline. Présent sur grille planning enfants (admin/salarié), print view
   et fiche enfant. */
.repas-chip {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.4;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.pb-presence-table .cell-absence-tag {
    display: block;
    margin-top: 2px;
    font-size: 0.7rem;
    color: #90A4AE;
    font-style: italic;
}

/* Absence (programmée ou imprévue) : orange doux uniforme. La distinction
   prog. vs imprévu se fait par le tag textuel sous le nom, pas par la couleur. */
.pb-presence-table tbody tr td.cell-enfant.absence-prog,
.pb-presence-table tbody tr td.cell-enfant.absence-imp {
    background: #FFE0B2;
}
.pb-presence-mobile-item.absence-prog,
.pb-presence-mobile-item.absence-imp { background: #FFE0B2; }
.pb-presence-mobile-item .is-absent {
    text-decoration: line-through;
    color: #90A4AE;
}

.pb-presence-mobile-item {
    padding: 6px 10px;
    border-radius: 4px;
    font-size: 0.9rem;
    color: #263238;
    background: var(--pb-bg-subtle, #FAFAFA);
}
.pb-presence-mobile-item.has-allergie { background: #FFEBEE; }
.pb-presence-mobile-item.is-tappable {
    cursor: pointer;
    min-height: 44px; /* Cible tactile WCAG 2.5.5 — pages /salarie/* */
}

/* Bouton PDF / actions sur entité — garantit 44px en mobile pour le tap */
@media (max-width: 600px) {
    .pb-tappable.mud-button-root { min-height: 44px; }
}

/* Error UI */
#blazor-error-ui {
    background: #B71C1C;
    color: white;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0,0,0,0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
    font-family: 'Nunito', sans-serif;
}
#blazor-error-ui .dismiss { cursor: pointer; color: rgba(255,255,255,0.7); float: right; }

/* ── Notifications (cloche header + page) ───────────────────────────────── */
.notification-bell-panel {
    width: 360px;
    max-width: 92vw;
    max-height: 80vh;
    overflow-y: auto;
}
.notification-bell-list {
    max-height: 60vh;
    overflow-y: auto;
}
.notif-non-lue {
    background: rgba(33, 150, 243, 0.08);
    border-left: 3px solid var(--pb-primary, #1976D2);
}
.notif-lue {
    opacity: 0.78;
}

/* ─── Inputs HTML bruts (auth + profil) — rendu visuel proche de MudTextField ──
   Utilisée sur les formulaires qui POST vers /auth/* (impossible en MudBlazor
   car SignalR ne transporte pas Set-Cookie). font-size: 16px obligatoire pour
   éviter le zoom involontaire iOS sur sélection. */
.form-control-mud {
    font-family: inherit;
    font-size: 16px;
    padding: 0.625rem 0.75rem;
    width: 100%;
    border: 1px solid var(--mud-palette-lines-default, #E0E0E0);
    border-radius: 4px;
    background: var(--mud-palette-surface, #FFFFFF);
    color: var(--mud-palette-text-primary, #212121);
    box-sizing: border-box;
    transition: border-color 0.2s, box-shadow 0.2s;
    min-height: 44px;
}
.form-control-mud:focus {
    outline: none;
    border-color: var(--mud-palette-primary, #5C6BC0);
    box-shadow: 0 0 0 2px rgba(92, 107, 192, 0.18);
}
.form-control-mud:disabled {
    background: #F5F5F5;
    color: #9E9E9E;
}

.btn-mud-styled {
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    padding: 0.6rem 1.2rem;
    border-radius: 4px;
    border: none;
    cursor: pointer;
    background: var(--mud-palette-primary, #5C6BC0);
    color: #FFFFFF;
    min-height: 44px;
    transition: filter 0.15s;
}
.btn-mud-styled:hover:not(:disabled) { filter: brightness(1.08); }
.btn-mud-styled:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-mud-styled--secondary {
    background: transparent;
    color: var(--mud-palette-primary, #5C6BC0);
    border: 1px solid currentColor;
}

/* Filter row des 3 list views (AbsenceListView / HeureListView / PreferenceListView).
   3 classes pour ajuster la largeur cible des MudSelect selon le label (Salariée largest,
   Type d'absence medium, Type heure plus court).
   Desktop : min-width fixe (équivalent du commit selects-larger ×2).
   Mobile (≤ 600 px) : reset à 100% pour shrink et empilement vertical (Wrap.Wrap parent). */
.demandes-filter-select-wide   { min-width: 400px; flex: 0 1 480px; }
.demandes-filter-select-medium { min-width: 360px; flex: 0 1 440px; }
.demandes-filter-select-narrow { min-width: 320px; flex: 0 1 400px; }
@media (max-width: 600px) {
    .demandes-filter-select-wide,
    .demandes-filter-select-medium,
    .demandes-filter-select-narrow {
        min-width: 100% !important;
        flex: 0 0 100% !important;
    }
}

/* /admin/demandes — grille de cartes au-dessus d'un MudTable (pager natif
   conservé). 3 colonnes ≥960 px, 2 colonnes 600–960 px, 1 colonne <600 px
   — équivalent du MudGrid xs=12 sm=6 md=4 historique. */
.demandes-card-grid tbody {
    display: grid !important;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 12px;
    padding: 4px 0;
}
.demandes-card-grid tbody tr {
    display: block !important;
    background: transparent !important;
    border: none !important;
    min-width: 0;
}
.demandes-card-grid tbody tr:hover {
    background: transparent !important;
}
.demandes-card-grid tbody tr td {
    display: block !important;
    padding: 0 !important;
    border: none !important;
    text-align: left !important;
}
/* Sous breakpoint mobile, MudBlazor pose .mud-xs-table .mud-table-cell::before
   { content: attr(data-label) } qui devient un flex item invisible — combiné au
   display:flex; justify-content:space-between de la même règle, il pousse la
   MudCard à droite. On neutralise le pseudo-element pour récupérer un layout
   block normal. */
.demandes-card-grid tbody tr td::before {
    content: none !important;
}

/* Hauteur uniforme : en grid, align-items vaut `stretch` par défaut → chaque tr
   prend la hauteur de la rangée. Pour que la carte (MudCard ou MudPaper) à
   l'intérieur remplisse cette hauteur (et que les actions s'alignent en bas,
   peu importe la taille du contenu), on cascade height:100% jusqu'à la card
   + flex-col pour pousser les actions au bottom. Sans ça, une carte au
   contenu court reste petite à côté d'une carte au contenu long.

   Couvre les 2 patterns : MudCard avec MudCardActions, et MudPaper avec une
   dernière MudStack en pied. Si la carte n'a pas de bloc d'actions, le
   contenu reste en haut et le vide tombe en bas — c'est OK visuellement,
   c'est juste l'alignement qui s'uniformise entre cartes voisines. */
.demandes-card-grid tbody tr,
.demandes-card-grid tbody tr td,
.demandes-card-grid tbody tr td > .mud-card,
.demandes-card-grid tbody tr td > .mud-paper {
    height: 100%;
}
.demandes-card-grid tbody tr td > .mud-card,
.demandes-card-grid tbody tr td > .mud-paper {
    display: flex;
    flex-direction: column;
}
.demandes-card-grid tbody tr td > .mud-card > .mud-card-actions,
.demandes-card-grid tbody tr td > .mud-paper > .mud-stack:last-child {
    margin-top: auto;
}

/* Pattern A (CLAUDE.md « Listes responsive ») — liste simple où chaque valeur
   s'auto-explique (nom, chip statut, email…). Pas besoin de DataLabel sur
   chaque MudTd. On neutralise juste le ::before vide et on aligne à gauche
   pour éviter l'effet "tout collé à droite". À poser via Class sur la MudTable. */
.mud-table-mobile-list .mud-table-cell::before {
    content: none !important;
}
.mud-table-mobile-list .mud-table-cell {
    justify-content: flex-start !important;
    text-align: left !important;
    width: 100% !important;
    box-sizing: border-box !important;
}
/* Force le contenu unique de la cellule (typiquement une <MudCard>) à occuper toute la largeur
   disponible. Sinon MudBlazor met flex sur la cellule et la carte garde sa taille naturelle,
   produisant un effet "carte décalée vers la gauche" (bug constaté sur /admin/salaries, etc.). */
.mud-table-mobile-list .mud-table-cell > * {
    flex: 1 1 100% !important;
    width: 100% !important;
}
@media (max-width: 960px) {
    .demandes-card-grid tbody {
        grid-template-columns: 1fr 1fr;
    }
}
@media (max-width: 600px) {
    .demandes-card-grid tbody {
        grid-template-columns: 1fr;
    }
}

/* Overlay d'auto-remplissage planning : gros emoji animé + phrase qui pulse.
   Donne du signe de vie pendant les 30-60s où le serveur prépare le contexte et
   fait tourner le solveur CP-SAT — sinon l'utilisateur croit que la page est gelée. */
@keyframes spinner-fun-bounce {
    0%, 100% { transform: translateY(0) scale(1); }
    50%      { transform: translateY(-14px) scale(1.08); }
}
@keyframes spinner-fun-fade {
    0%, 100% { opacity: 0.7; }
    50%      { opacity: 1; }
}
.spinner-fun-emoji {
    font-size: 4.5rem;
    line-height: 1;
    animation: spinner-fun-bounce 1.6s ease-in-out infinite;
}
.spinner-fun-phrase {
    text-align: center;
    animation: spinner-fun-fade 2.4s ease-in-out infinite;
    font-style: italic;
}

/* Documentation interne SA (Sprint D2) — rendu du markdown via Markdig. */
.documentation-markdown {
    line-height: 1.6;
    color: rgba(0, 0, 0, 0.87);
}
.documentation-markdown h1 { font-size: 1.8rem; margin: 1.5rem 0 1rem; }
.documentation-markdown h2 { font-size: 1.5rem; margin: 1.5rem 0 0.8rem; border-bottom: 1px solid #e0e0e0; padding-bottom: 0.3rem; }
.documentation-markdown h3 { font-size: 1.25rem; margin: 1.2rem 0 0.6rem; }
.documentation-markdown h4 { font-size: 1.05rem; margin: 1rem 0 0.5rem; font-weight: 600; }
.documentation-markdown p { margin: 0.6rem 0; }
.documentation-markdown ul, .documentation-markdown ol { padding-left: 1.5rem; margin: 0.5rem 0; }
.documentation-markdown li { margin: 0.2rem 0; }
.documentation-markdown code {
    background: #f4f4f4;
    padding: 0.1rem 0.35rem;
    border-radius: 3px;
    font-size: 0.92em;
    font-family: 'Consolas', 'Courier New', monospace;
}
.documentation-markdown pre {
    background: #f8f8f8;
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    padding: 0.75rem 1rem;
    overflow-x: auto;
}
.documentation-markdown pre code {
    background: none;
    padding: 0;
}
.documentation-markdown table {
    border-collapse: collapse;
    margin: 0.8rem 0;
    width: 100%;
}
.documentation-markdown th, .documentation-markdown td {
    border: 1px solid #d8d8d8;
    padding: 0.4rem 0.7rem;
    text-align: left;
    vertical-align: top;
}
.documentation-markdown th {
    background: #fafafa;
    font-weight: 600;
}
.documentation-markdown blockquote {
    border-left: 4px solid #b0bec5;
    margin: 0.8rem 0;
    padding: 0.4rem 1rem;
    background: #fafafa;
    color: rgba(0, 0, 0, 0.7);
}
.documentation-markdown a { color: #1976d2; text-decoration: none; }
.documentation-markdown a:hover { text-decoration: underline; }

/* ── Cockpit « Heures réalisées » (/admin/heures) — cartouches de cellule ───── */
/* Un cartouche = un créneau / HT / T+ / réunion : bord gauche coloré (type/créneau)
   + plage horaire (début aligné, tabular-nums) + durée séparée à droite. */
.he-line {
    display: flex;
    align-items: center;
    width: 100%;
    box-sizing: border-box;
    background: var(--pb-bg-subtle);
    border-radius: 6px;
    border-left: 3px solid var(--pb-text-faint);
    padding: 3px 8px;
    margin-bottom: 4px;
    line-height: 1.3;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.he-line:last-child { margin-bottom: 0; }
.he-time { font-size: 0.78rem; color: var(--pb-color-text-stronger); }
.he-dur {
    margin-left: auto;
    padding-left: 8px;
    border-left: 1px solid var(--pb-border-soft);
    font-size: 0.72rem;
    color: var(--pb-text-muted);
    /* Largeur fixe + texte à droite : le filet séparateur (bord gauche) tombe à la même
       position d'un cartouche à l'autre, quelle que soit la durée (5h30 / 0h30 / 2h). */
    flex: 0 0 auto;
    min-width: 3.4em;
    text-align: right;
}
/* Statut → couleur de la plage horaire (validé fort / à valider atténué / en attente orange). */
.he-line--valide .he-time { font-weight: 600; }
.he-line--prev .he-time { color: var(--pb-text-muted); }
.he-line--attente .he-time { color: var(--pb-color-warning-dark); font-weight: 600; }
/* Pastille de légende (carré coloré + code), utilisée hors grille pour mapper couleur → type. */
.he-badge {
    display: inline-block;
    min-width: 1.4em;
    text-align: center;
    color: white;
    border-radius: 4px;
    padding: 0 4px;
    font-size: 0.7rem;
    font-weight: 700;
}
.he-vide { color: var(--pb-text-faint); font-weight: 600; }
.he-abs {
    color: white;
    margin: 0;
    width: 100%;
    text-align: center;
}
.he-mobile-jour {
    border: 1px solid var(--pb-border-light);
    border-radius: 8px;
    padding: 8px;
    margin-bottom: 8px;
}
.he-mobile-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 4px;
    border-top: 1px solid var(--pb-border-light);
}
.he-mobile-row:first-of-type { border-top: none; }
