/*
 * Socle front Projecture.
 *
 * ⚠️ FEUILLE STATIQUE, SANS ÉTAPE DE BUILD. Elle se sert telle quelle depuis
 * public/. Pas de Vite, pas de Tailwind à compiler : le déploiement est un
 * copier-coller de fichiers sur OVH, et une chaîne de build y serait une
 * dépendance de plus à faire tourner sur un serveur qui n'en a pas besoin.
 *
 * ⚠️ TOUT CE QUI EST ICI NE DOIT PLUS ÊTRE RÉÉCRIT DANS UNE VUE. C'était la
 * principale dette front : chaque module reposait ses variables de couleur,
 * ses .card, ses .field, ses .button, dans un <style> inline. Quatre copies
 * d'une même charte divergent, c'est mécanique.
 *
 * Les modules existants — wiki, projets, agenda, matériel — ne sont PAS migrés
 * ici : leur reprise est un chantier à part. Ce socle sert le RH, et servira
 * aux autres le jour où on les reprendra.
 */

:root {
    color-scheme: light;

    /* Identité Projecture et couleurs sémantiques. */
    --teal: #0f6f6c;
    --magenta: #be2d62;
    --bg: #f4f6f8;
    --card: #fff;
    --surface-muted: #f8fafb;
    --surface-strong: #eef2f4;
    --field-bg: #fff;
    --field-disabled: #f2f5f7;
    --ink: #17212b;
    --ink-soft: #52616c;
    --muted: #697680;
    --line: #dfe5e9;
    --line-strong: #c9d2d9;
    --brand: var(--teal);
    --brand-ink: #fff;
    --on-color: #fff;
    --brand-bg: #e7f4f3;
    --danger: var(--magenta);
    --danger-bg: #fceef3;
    --danger-line: #e8a9c0;
    --ok: #067647;
    --ok-bg: #ecfdf3;
    --ok-line: #9ed8bd;
    --warn: #b54708;
    --warn-bg: #fffaeb;
    --warn-line: #f2c38b;
    --focus-ring: color-mix(in srgb, var(--brand) 24%, transparent);
    --shadow-sm: 0 1px 4px rgb(15 33 43 / 8%);
    --shadow-lg: 0 24px 70px rgb(15 23 32 / 28%);
    --overlay: rgb(15 23 32 / 55%);

    /*
     * ⚠️ **Le menu latéral a SES jetons.** Ce sont les seules couleurs de la
     * palette qui vivent sur fond sombre : les réutiliser ailleurs donnerait du
     * texte gris pâle sur du blanc.
     */
    --lateral-bg: #1e2b38;
    --lateral-ink: #c9d6e0;

    /*
     * ⚠️ **La hauteur de la barre du haut, recopiée.** Elle est écrite en dur
     * dans `partials/app-menu.blade.php`, qui est partagé : le jeton évite au
     * moins qu'elle soit répétée trois fois de ce côté-ci. Si elle change
     * là-bas, c'est ici qu'il faut la suivre — 58 px, 52 sous 760.
     */
    --barre-haut: 58px;

    --radius-card: 14px;
    --radius-control: 9px;
    --radius-pill: 999px;

    --page: 1400px;
    --gap: 14px;

    --font: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

@media (prefers-color-scheme: dark) {
    :root {
        color-scheme: dark;
        --bg: #0f1719;
        --card: #172225;
        --surface-muted: #1c292c;
        --surface-strong: #243337;
        --field-bg: #111c1f;
        --field-disabled: #243034;
        --ink: #eef7f6;
        --ink-soft: #c1cfcd;
        --muted: #9eafad;
        --line: #334548;
        --line-strong: #496064;
        --brand: #55b8b3;
        --brand-ink: #081313;
        --brand-bg: #163c3b;
        --danger: #ef77a1;
        --danger-bg: #3d1d2a;
        --danger-line: #74334c;
        --ok: #69d5a2;
        --ok-bg: #143629;
        --ok-line: #2d7658;
        --warn: #f2b66d;
        --warn-bg: #3c2b16;
        --warn-line: #76552a;
        --shadow-sm: 0 1px 4px rgb(0 0 0 / 28%);
        --shadow-lg: 0 24px 70px rgb(0 0 0 / 55%);
        --overlay: rgb(0 0 0 / 68%);
    }
}

* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font);
    font-size: 15px;
    line-height: 1.5;
}

/* ---------------------------------------------------------------- page */

/*
 * ⚠️ **TROIS NIVEAUX QUI SE TOUCHAIENT.** La barre de navigation, le fil
 * d'Ariane et le titre s'enchaînaient sans respiration : le titre semblait
 * collé au menu, sur le wiki comme sur la fiche employé — donc c'était le
 * socle, pas les vues.
 *
 * ⚠️ **L'air se pose ICI, pas dans chaque écran.** Une marge ajoutée vue par
 * vue diverge à la première qu'on oublie, et personne ne sait plus laquelle
 * fait référence. Les deux modules en bénéficient du même coup.
 */
.page {
    width: min(var(--page), calc(100% - 36px));
    margin: auto;
    padding: 36px 0 48px;
}

.page--etroit { --page: 900px; }

/*
 * ⚠️ **TROIS NIVEAUX, TROIS RESPIRATIONS.** Le fil d'Ariane dit où l'on est,
 * le titre de qui il s'agit, le sous-titre ce qu'on regarde de lui. Serrés,
 * ils se lisent comme un seul bloc et on ne distingue plus lequel répond à
 * quelle question.
 */
.page__header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 26px;
}

.page__header h1 { margin: 0; font-size: 32px; line-height: 1.2; }
.page__sous-titre { margin: 9px 0 0; color: var(--muted); }

/* Fil d'Ariane — la position dans l'application, pas une décoration. */
.fil {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    /* Entre le fil et le titre : le fil dit OÙ, le titre dit QUOI. */
    margin: 0 0 26px;
    padding: 0;
    list-style: none;
    color: var(--muted);
    font-size: 13px;
}

.fil a { color: var(--muted); text-decoration: none; }

/*
 * ⚠️ **Les liens d'un tableau tombaient sur le DÉFAUT DU NAVIGATEUR** — bleu
 * souligné — parce que rien ne les habillait : la feuille ne portait qu'une
 * règle sur le fil d'Ariane. Ce n'était pas une couleur écrite en dur qu'il
 * fallait chasser, c'était une règle absente.
 *
 * ⚠️ **Le soulignement revient au survol.** L'enlever tout court laisserait un
 * texte coloré que rien ne désigne comme cliquable — et la couleur seule ne
 * suffit pas : elle ne se voit pas de la même façon selon les yeux.
 */
.tableau a {
    color: var(--brand);
    text-decoration: none;
}

.tableau a:hover,
.tableau a:focus-visible { text-decoration: underline; }
.fil a:hover { color: var(--ink); text-decoration: underline; }
.fil li + li::before { content: "›"; margin-right: 8px; color: var(--muted); }
.fil [aria-current="page"] { color: var(--ink); font-weight: 700; }

/* ---------------------------------------------------------------- carte */

/* ------------------------------------------------- menu lateral du module */

/*
 * ⚠️ **`display: contents` par defaut, et c'est ce qui rend l'ajout sur** :
 * l'enveloppe disparait de l'arbre de rendu tant qu'aucun menu lateral n'est
 * posé. Une page sans `$lateral` se dispose exactement comme avant.
 */
.enveloppe { display: contents; }

.enveloppe--lateral {
    display: flex;
    align-items: flex-start;
    gap: 0;
}

/*
 * ⚠️ **UN MENU SOMBRE, PAS UNE COLONNE PALE.** En gris clair sur blanc il se
 * confondait avec la page : rien ne séparait la navigation du contenu, et
 * l'œil devait lire pour savoir où il était. C'est le premier trait de la
 * référence Scriptcase (`Scriptcase/RH/50.png`) — un fond contrasté fait la
 * séparation avant qu'un seul mot soit lu.
 *
 * ⚠️ **Une teinte DISTINCTE de la barre du haut**, pas la même. Deux surfaces
 * sombres identiques donneraient un seul bloc en L dont on ne verrait plus la
 * charnière ; celle-ci est un cran plus claire.
 *
 * ⚠️ **272 px, pas 232.** « Administration du personnel » tenait à peine et
 * « Récapitulatif mensuel » frôlait le bord. Une entrée qui se coupe oblige à
 * deviner, et l'icône consomme sa part de largeur.
 */
/*
 * ⚠️ **`max-height` LAISSAIT LE FOND S'ARRÊTER SOUS LA DERNIÈRE ENTRÉE.** La
 * colonne prenait la hauteur de son contenu — l'enveloppe est en
 * `align-items: flex-start` — et le sombre s'interrompait à mi-page. Une
 * hauteur FIXE la fait couvrir la fenêtre entière, qu'il y ait cinq entrées ou
 * dix-huit.
 *
 * ⚠️ **`sticky`, PAS `fixed`.** Fixed la sortirait du flux : la colonne ne
 * réserverait plus sa largeur et le contenu passerait dessous. Sticky donne le
 * même résultat à l'œil — la bande ne bouge plus quand la page défile — en
 * gardant la place qu'elle occupe.
 *
 * ⚠️ **`top` vaut la hauteur de la barre du haut**, qui est elle-même sticky :
 * à zéro, le menu glisserait dessous. Les deux valeurs sont couplées, et la
 * barre vit dans `partials/app-menu.blade.php` — infrastructure partagée
 * (§0 quater) : d'où le jeton, pour qu'un seul endroit porte le nombre de ce
 * côté-ci.
 *
 * ⚠️ **`overscroll-behavior: contain`** : arrivé en bas du menu, la molette ne
 * doit pas emporter la page avec elle. Sans lui, dérouler la navigation fait
 * défiler l'écran qu'on regardait.
 */
.lateral {
    flex: 0 0 272px;
    position: sticky;
    top: var(--barre-haut, 58px);
    height: calc(100vh - var(--barre-haut, 58px));
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 16px 12px 28px;
    background: var(--lateral-bg, #1e2b38);
    color: var(--lateral-ink, #c9d6e0);
}

/*
 * ⚠️ **La page reprend ses marges A L'INTERIEUR de l'enveloppe.** Hors flux,
 * elle se centrait avec `margin: auto` et son `width: min(...)` lui donnait
 * des marges laterales ; devenue element flex, elle les perd et le contenu
 * vient coller la colonne de gauche.
 */
/*
 * ⚠️ **`margin: auto` CENTRAIT LA PAGE VERTICALEMENT, et personne ne l'avait
 * demandé.** Sur un élément flex, une marge automatique absorbe l'espace libre
 * dans **les deux axes** — et elle l'emporte sur `align-items: flex-start`. La
 * règle `.page { margin: auto }` sert à centrer horizontalement hors flex ;
 * dans l'enveloppe elle centrait aussi de haut en bas.
 *
 * ⚠️ **Le défaut s'est RÉVÉLÉ en donnant sa hauteur au menu**, il n'est pas né
 * là : tant que la colonne mesurait la hauteur de son contenu, il n'y avait
 * pas d'espace libre à absorber. C'est pourquoi il se voit sur un écran court
 * — une liste vide flottait au milieu de la fenêtre.
 *
 * ⚠️ **C'est le SOCLE, pas un écran** : tous les écrans RH courts étaient
 * concernés. Une correction posée sur la vue des demandes aurait laissé les
 * vingt autres.
 */
.enveloppe--lateral .page {
    flex: 1;
    min-width: 0;
    margin-block: 0;
    align-self: flex-start;
    padding-inline: 28px;
}

@media (max-width: 900px) {
    .enveloppe--lateral .page { padding-inline: 18px; }
}

/* La barre du haut passe à 52 px sous 760 : le menu suit, sinon il glisse. */
@media (max-width: 760px) {
    :root { --barre-haut: 52px; }
}

.lateral__section { margin: 0 0 2px; }

/*
 * ⚠️ **Le titre de section est un `<summary>`, donc un BOUTON.** Il n'a plus
 * rien d'une étiquette : on clique dessus, il se déplie. À 11 px en capitales
 * grises il ressemblait à une légende — quelque chose qu'on ne clique pas.
 */
.lateral__titre {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0;
    padding: 9px 10px;
    border-radius: 8px;
    color: var(--lateral-ink, #c9d6e0);
    font-size: 14.5px;
    font-weight: 700;
    cursor: pointer;
    list-style: none;
    user-select: none;
}

/* Le triangle natif de `<details>`, remplacé par notre chevron. */
.lateral__titre::-webkit-details-marker { display: none; }
.lateral__titre::marker { content: ''; }

.lateral__titre:hover { background: rgb(255 255 255 / 7%); color: #fff; }

.lateral__chevron {
    margin-left: auto;
    width: 7px;
    height: 7px;
    border-right: 2px solid currentcolor;
    border-bottom: 2px solid currentcolor;
    transform: rotate(-45deg);
    opacity: .6;
    transition: transform .15s ease;
}

/* Déplié : le chevron pointe vers le bas. */
.lateral__section[open] > .lateral__titre { color: #fff; }
.lateral__section[open] > .lateral__titre .lateral__chevron { transform: rotate(45deg); }

.lateral__liste { list-style: none; margin: 2px 0 8px; padding: 0 0 0 12px; }

/*
 * ⚠️ **Les libellés en taille NORMALE.** 13,5 px dans une colonne sombre se
 * lit moins bien que 13,5 px sur blanc — le contraste inversé demande un peu
 * plus de corps. La référence Scriptcase est à 14-15.
 */
.lateral__lien {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: 8px;
    color: var(--lateral-ink, #c9d6e0);
    text-decoration: none;
    font-size: 14px;
    line-height: 1.3;
}

.lateral__lien--seul { font-weight: 700; margin-bottom: 2px; }

.lateral__lien:hover { background: rgb(255 255 255 / 8%); color: #fff; }

/*
 * ⚠️ **L'entrée active est un BLOC PLEIN**, pas une nuance de gris. Sur un fond
 * sombre, un simple changement de teinte ne se voit pas ; c'est le remplissage
 * qui dit « vous êtes ici », et il se voit avant qu'on lise.
 *
 * ⚠️ **Elle garde sa barre à gauche**, qui survit là où la couleur ne survit
 * pas — écran pâle, impression, daltonisme. La teinte seule ne suffit jamais.
 */
.lateral__lien.is-active {
    background: var(--brand);
    color: #fff;
    font-weight: 700;
    box-shadow: inset 3px 0 0 rgb(255 255 255 / 55%);
}

.lateral__lien.is-active .lateral__icone { opacity: 1; }

/*
 * ⚠️ **Une icône par entrée, et la MÊME pour un même sujet.** « Équipes » et
 * « Gestion équipe » partagent la leur : ce sont deux portes sur la même
 * matière, et deux dessins différents suggéreraient deux choses différentes.
 */
.lateral__icone {
    flex: 0 0 auto;
    width: 17px;
    height: 17px;
    opacity: .78;
}

/*
 * ⚠️ **Sous 900 px la colonne passe AU-DESSUS, elle ne disparait pas.** Un
 * menu qu'on replie derriere un bouton demande de savoir qu'il existe ; ici
 * il devient une bande horizontale defilante, et tout reste atteignable.
 */
@media (max-width: 900px) {
    .enveloppe--lateral { flex-direction: column; }

    .lateral {
        flex: none;
        position: static;
        max-height: none;
        width: 100%;
        border-right: 0;
        border-bottom: 1px solid var(--line);
        padding: 12px 14px;
    }

    .lateral__nav { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
    .lateral__section { margin: 0; }
    .lateral__titre { margin: 0; padding: 4px 8px; }
    .lateral__liste { display: flex; flex-wrap: wrap; gap: 4px; padding-left: 0; }
    .lateral__lien.is-active { box-shadow: inset 0 -3px 0 rgb(255 255 255 / 55%); }
}

.carte {
    padding: 20px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow-sm);
}

.carte + .carte { margin-top: var(--gap); }
.carte__titre { margin: 0 0 4px; font-size: 19px; }
.carte__note { margin: 0 0 16px; color: var(--muted); font-size: 13.5px; }
.carte__titre + .carte__corps { margin-top: 16px; }

.grille {
    display: grid;
    grid-template-columns: repeat(var(--colonnes, 3), minmax(0, 1fr));
    gap: var(--gap);
}

/* ---------------------------------------------------------------- champs */

.champ { display: block; margin-bottom: 16px; }
.champ__label { display: block; margin-bottom: 6px; font-size: 14px; font-weight: 700; }

/*
 * ⚠️ **L'unité se lit DEUX fois, et ce n'est pas un doublon** : dans
 * l'étiquette quand on parcourt le formulaire, contre le champ quand on tape.
 * C'est au moment de la saisie qu'on se trompe.
 */
.champ__unite { font-weight: 500; color: var(--muted); }

.champ__avec-unite { display: flex; align-items: center; gap: 7px; }
.champ__avec-unite .champ__saisie { min-width: 0; }
.champ__suffixe { flex: 0 0 auto; color: var(--muted); font-size: 13px; }
.champ__requis { color: var(--danger); }

.champ__aide {
    display: block;
    margin-top: 6px;
    color: var(--muted);
    font-size: 12px;
}

.champ__saisie,
input[type="text"], input[type="email"], input[type="password"],
input[type="date"], input[type="time"], input[type="number"],
select, textarea {
    width: 100%;
    padding: 9px 11px;
    border: 1px solid var(--line);
    border-radius: var(--radius-control);
    background: var(--field-bg);
    color: var(--ink);
    font-family: inherit;
    font-size: 14px;
}

.champ__saisie:focus, input:focus, select:focus, textarea:focus {
    border-color: var(--brand);
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
}

.champ__saisie:disabled, input:disabled, select:disabled, textarea:disabled {
    background: var(--field-disabled);
    color: var(--muted);
    cursor: not-allowed;
}

/*
 * ⚠️ Un champ verrouillé n'est pas un champ vide. Il porte sa valeur et dit
 * pourquoi on ne peut pas la changer — §2 : « un responsable voit une fiche
 * différente, pas un formulaire aux champs vides ».
 */
.champ--verrouille .champ__saisie { background: var(--field-disabled); color: var(--muted); }

.champ--erreur .champ__saisie,
.champ--erreur input, .champ--erreur select, .champ--erreur textarea {
    border-color: var(--danger);
}

.champ__erreur {
    display: block;
    margin-top: 6px;
    color: var(--danger);
    font-size: 12px;
    font-weight: 700;
}

/* ---------------------------------------------------------- éditeur HTML */

.editeur-html__cadre {
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: var(--radius-control);
    background: var(--card);
}

.editeur-html__outils {
    margin: 0;
    padding: 10px;
    border-bottom: 1px solid var(--line);
    background: var(--surface-muted);
}

.editeur-html__outils .bouton { min-height: 36px; padding: 6px 10px; }
.editeur-html__bloc { width: auto; min-width: 130px; }
.editeur-html__surface, .editeur-html__source {
    min-height: 280px;
    border: 0;
    border-radius: 0;
    background: var(--field-bg);
    line-height: 1.65;
    resize: vertical;
}
.editeur-html__surface:focus, .editeur-html__source:focus {
    outline: 2px solid var(--focus-ring);
    outline-offset: -2px;
}
.editeur-html__surface img { max-width: 100%; height: auto; }

/* ---------------------------------------------------------------- boutons */

.bouton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 9px 15px;
    border: 1px solid transparent;
    border-radius: var(--radius-control);
    background: var(--brand);
    color: var(--brand-ink);
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
}

.bouton:hover { filter: brightness(.94); }
.bouton:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.bouton:disabled { opacity: .55; cursor: not-allowed; filter: none; }

.bouton--secondaire {
    border-color: var(--line);
    background: var(--field-bg);
    color: var(--ink);
}

.bouton--discret { border-color: transparent; background: transparent; color: var(--muted); }
.bouton--danger { background: var(--danger); }

.barre-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    margin-top: 18px;
}

.barre-actions--fin { justify-content: flex-end; }

/* ---------------------------------------------------------------- messages */

.message {
    margin: 0 0 18px;
    padding: 12px 14px;
    border: 1px solid var(--line);
    border-left-width: 4px;
    border-radius: var(--radius-control);
    background: var(--field-bg);
    font-size: 14px;
}

.message__titre { margin: 0 0 4px; font-size: 14px; font-weight: 800; }
.message ul { margin: 8px 0 0; padding-left: 20px; }
.message--succes { border-left-color: var(--ok); background: var(--ok-bg); color: var(--ok); }
.message--erreur { border-left-color: var(--danger); background: var(--danger-bg); color: var(--danger); }
.message--alerte { border-left-color: var(--warn); background: var(--warn-bg); color: var(--warn); }
.message--info { border-left-color: var(--brand); background: var(--brand-bg); color: var(--brand); }

/* ---------------------------------------------------------------- tableau */

.tableau { width: 100%; overflow-x: auto; }

.tableau table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

.tableau th, .tableau td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--line);
    text-align: left;
    vertical-align: top;
}

.tableau th {
    color: var(--muted);
    font-size: 12.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .04em;
    white-space: nowrap;
}

/*
 * ⚠️ **LES VALEURS SE LISENT, ELLES NE SE DEVINENT PAS.** Le corps des tableaux
 * héritait des 15 px du body mais les libellés voisins étaient à 12 : l'écart
 * donnait une page qui paraissait entièrement petite. Une taille explicite ici
 * évite qu'un composant parent la rabaisse sans qu'on s'en aperçoive.
 */
.tableau td { font-size: 14px; }

.tableau tbody tr:last-child td { border-bottom: 0; }
.tableau tbody tr:hover { background: var(--surface-muted); }
.tableau .num { text-align: right; font-variant-numeric: tabular-nums; }
.tableau caption { margin-bottom: 10px; color: var(--muted); font-size: 13.5px; text-align: left; }

.etiquette {
    display: inline-block;
    padding: 3px 9px;
    border-radius: var(--radius-pill);
    background: var(--field-disabled);
    color: var(--ink-soft);
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
}

.etiquette--ok { background: var(--ok-bg); color: var(--ok); }
.etiquette--danger { background: var(--danger-bg); color: var(--danger); }
.etiquette--alerte { background: var(--warn-bg); color: var(--warn); }

/* Le trou explicite : une case délibérément vidée, pas une case sans donnée. */
.etiquette--vide { background: repeating-linear-gradient(45deg,var(--field-disabled),var(--field-disabled) 4px,var(--surface-strong) 4px,var(--surface-strong) 8px); color: var(--ink-soft); }

.vide {
    padding: 40px;
    border: 1px dashed var(--line-strong);
    border-radius: var(--radius-card);
    background: var(--field-bg);
    color: var(--muted);
    text-align: center;
}

.muet { color: var(--muted); }
.num { font-variant-numeric: tabular-nums; }

/*
 * ⚠️ Réservé aux lecteurs d'écran. Sert aux libellés que le regard déduit de
 * la mise en page mais qu'une synthèse vocale ne peut pas deviner.
 */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
}

/* ------------------------------------------------------- compteurs RH */

/*
 * ⚠️ L'EN-TÊTE DE SEMAINE. Ses chiffres viennent du plan calculé sur la
 * grille affichée — jamais d'une lecture séparée en base. C'est un point de
 * conception, pas de style : l'écran Scriptcase montre 0 h 00 dans son
 * en-tête pendant que sa grille porte 38 h, parce que les deux lisent deux
 * sources. Le CSS ne peut pas empêcher ça, mais il ne doit pas le maquiller.
 */
/*
 * ⚠️ **UNE LIGNE DE VALEURS, PLUS DIX CARTES.** Le prévisionnel et les
 * prestations sont des écrans de SAISIE : les compteurs en cartes occupaient la
 * moitié de la hauteur avant qu'on n'atteigne la grille, alors qu'on vient
 * encoder un planning. Ils sont désormais **sous** la grille, et tiennent sur
 * une ligne.
 *
 * ⚠️ **Le point médian sépare, il ne décore pas.** Sans lui, « Presté 22h48
 * Congés 15h12 » se lit comme une phrase et il faut compter les mots pour
 * retrouver les paires.
 */
.compteurs__ligne {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 0;
    margin: 0;
}

.compteurs__ligne .compteur {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 0 14px;
    border: 0;
    border-radius: 0;
    background: none;
}

/* Le séparateur, entre les valeurs et jamais avant la première. */
.compteurs__ligne .compteur + .compteur { border-left: 1px solid var(--line); }

.compteurs__ligne dt {
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
}

.compteurs__ligne dd {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/*
 * ⚠️ **Les quatre compteurs qui touchent un SOLDE se distinguent des mesures.**
 * « Reconnu » et « Récupérables » engagent le compteur de l'employé ; « Presté »
 * et « Férié » ne font que décrire la semaine. La couleur dit lesquels comptent.
 */
.compteurs__ligne .compteur--fort dd { color: var(--brand); }

/*
 * ⚠️ Le manque n'est pas une erreur : c'est l'entrée de la chaîne du §14 —
 * case vidée, manque hebdomadaire, défalcation en récupération. Il se
 * remarque sans crier.
 */
.compteurs__ligne .compteur--manque dd { color: var(--warn); }

.compteurs__mention {
    margin: 0 0 10px;
    font-size: 13px;
    color: var(--muted);
}

.compteurs__mention:last-child { margin: 10px 0 0; }

/*
 * ⚠️ UNE PROJECTION S'AFFICHE EN JETON, pas en champ désactivé. Un champ grisé
 * invite à essayer ; un jeton ne promet rien. Pour changer une projection on
 * modifie la DEMANDE, qui repasse par le cycle de validation (§2).
 */
.jeton {
    display: inline-block;
    padding: 2px 9px;
    margin: 1px 3px 1px 0;
    border-radius: var(--radius-pill);
    background: var(--bg);
    border: 1px solid var(--line);
    font-size: 12px;
    white-space: nowrap;
}

/*
 * Les signaux d'une semaine à valider — §18, étape 6.
 *
 * ⚠️ **`white-space: normal` et pas de `nowrap`.** Un signal est une PHRASE,
 * pas une étiquette : « Une journée dépasse 11 h (11h40) » sur une seule ligne
 * pousserait la carte hors de l'écran sur un téléphone.
 */
.liste-signaux {
    list-style: none;
    margin: 8px 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.liste-signaux .jeton {
    white-space: normal;
}

/*
 * ⚠️ **La variante grave se voit, elle ne refuse rien.** Sur les prestations on
 * signale, on ne bloque pas (§10) : la couleur dit « regardez ceci », pas
 * « corrigez avant de continuer ».
 */
.jeton--alerte {
    background: var(--warn-bg);
    border-color: var(--warn);
    color: var(--warn);
}

/*
 * ⚠️ **LES SIX FAMILLES DE TYPES — la palette du récapitulatif mensuel.** Les
 * blocs y étaient tous gris : un mois de trente lignes identiques ne se lit
 * pas, il se déchiffre. La grille de présence, elle, se balaye du regard parce
 * que la couleur y porte l'état.
 *
 * ⚠️ **LA COULEUR NE PORTE JAMAIS L'INFORMATION SEULE.** Chaque bloc écrit son
 * type en clair — « Congés », « Maladie » —, et le mot survit en niveaux de
 * gris comme il survit au daltonisme. La couleur ne fait qu'accélérer une
 * lecture qui reste possible sans elle.
 *
 * ⚠️ **Six familles, pas dix-sept teintes.** Ce qu'on lit d'un coup d'œil sur
 * un mois, c'est « travaillé / absent pourquoi » — pas la nuance entre un congé
 * de circonstance et une raison impérieuse. Le regroupement vit dans
 * `HoraireType::famille()`, jamais dans cette feuille : deux écrans ne doivent
 * pas pouvoir peindre la même journée de deux couleurs.
 *
 * ⚠️ **Aplats PÂLES et texte foncé, contrairement à la présence.** Un mois
 * affiche jusqu'à six blocs par jour sur une carte étroite : des aplats saturés
 * en feraient un damier. Ici la couleur situe, elle ne crie pas.
 */
.jeton--travail { background: #e7f7f0; border-color: #9ed8bd; color: #0a5c42; }
.jeton--conges { background: #e8f1fd; border-color: #a8c8ee; color: #1c4e8f; }
.jeton--recup { background: #efe9fb; border-color: #c3b2e8; color: #4a3287; }
.jeton--maladie { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn); }
.jeton--ferie { background: #fdeef5; border-color: #e8a9c0; color: #8f2350; }

/*
 * ⚠️ **« Sans solde » et « case vidée » RESTENT GRIS, et c'est le bon signal** :
 * ces cases ne valent rien — ni reconnu, ni compensatoire. Leur donner une
 * couleur les rendrait aussi présentes que les autres à la lecture, alors que
 * ce sont précisément les journées où il ne s'est rien passé.
 */
.jeton--sans-solde,
.jeton--vide,
.jeton--inconnu { background: var(--surface-strong); border-color: var(--line-strong); color: var(--muted); }

/*
 * ⚠️ « PROPOSÉ » N'EST PAS « ENREGISTRÉ ». La case porte l'horaire de base et
 * rien n'est écrit en base. Sans cette distinction, un employé croirait sa
 * semaine encodée alors qu'aucune ligne n'existe — et la première sauvegarde
 * la remplirait de trous.
 */
.ligne--proposee > * { background: color-mix(in srgb, var(--warn-bg) 45%, transparent); }

/* --------------------------------------------------- grille de semaine */

/*
 * ⚠️ HORIZONTALE : sept lignes de jours, trois périodes en colonnes. C'est la
 * disposition de Scriptcase, et ce n'est pas qu'une habitude — vingt-et-une
 * lignes empilées obligent à défiler pour saisir une semaine, et on ne voit
 * jamais sa semaine entière. Ici elle tient sur un écran.
 */
.grille-semaine table { table-layout: fixed; }

.grille-semaine th[scope="col"] { width: auto; }
.grille-semaine th[scope="row"] { width: 108px; white-space: nowrap; }
.grille-semaine .colonne-total { width: 84px; }

.grille-semaine td { vertical-align: top; }

/*
 * ⚠️ LA DATE SOUS LE NOM DU JOUR — reprise de la grille Scriptcase, et pas
 * décorative : le férié se détecte sur la DATE et non sur le type (§6), et
 * c'est lui qui déclenche le taux 3.
 */
.grille-semaine__date { display: block; font-size: 12px; font-weight: 400; }

/*
 * ⚠️ **La flèche de copie tient sur la LIGNE du jour.** Sous la date, elle
 * ajoutait une ligne à chacune des sept rangées — et cette grille a justement
 * été refaite pour tenir sur un écran.
 */
.jour-entete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
}

/*
 * ⚠️ LE TOTAL DE LA SEMAINE compte les HEURES ENCODÉES, pas le reconnu : une
 * absence valorisée depuis l'horaire de base ne porte pas d'heures sur sa
 * ligne. L'écart avec l'en-tête est légitime, et la note de la ligne le dit —
 * un total qui aurait l'air faux serait pire que pas de total du tout.
 */
.grille-semaine__total > * {
    background: var(--bg);
    font-weight: 650;
}

.grille-semaine__total th[scope="row"] {
    width: auto;
    white-space: normal;
    text-align: right;
}

.grille-semaine__total small { display: block; font-weight: 400; }

/* Les trois contrôles d'une case s'empilent dans leur colonne. */
/*
 * ⚠️ **UNE LIGNE PAR JOUR, PAS TROIS.** La cellule empilait le type au-dessus
 * des deux heures : sept jours donnaient vingt-et-une lignes visuelles, plus
 * les notes, et une semaine ne tenait plus sur un écran. Le type et les deux
 * heures vivent maintenant côte à côte — c'est la forme de Scriptcase, et
 * elle tient.
 */
.case-saisie {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 4px;
}

/*
 * ⚠️ **`min-width: 0` RÉDUISAIT LE SÉLECTEUR À SA FLÈCHE.** Avec
 * `table-layout: fixed`, la colonne se partage entre trois contrôles ; les deux
 * champs d'heures ont une largeur fixe, et le type absorbait tout le manque.
 * À zéro de minimum, il tombait à la largeur du chevron — le libellé
 * « Present » était bien rendu dans le HTML, il n'y avait plus de place pour
 * l'afficher.
 *
 * ➡️ **Un plancher qui contient le plus long libellé** — « Télétravail »,
 * « Compensatoires » — plutôt qu'une largeur fixe : il grandit encore quand la
 * colonne le permet.
 */
.case-saisie > .champ__saisie {
    flex: 1 1 auto;
    min-width: 8.6em;
}

.case-heures { display: flex; gap: 3px; flex: 0 0 auto; }
.case-heures .champ__saisie { min-width: 0; width: 5.9em; padding-inline: 3px; }

.grille-semaine .champ__saisie { font-size: 12.5px; padding-block: 4px; }

/*
 * ⚠️ **Sous 1200 px la cellule REVIENT à deux lignes**, plutôt que d'imposer un
 * défilement horizontal. Une grille qu'on fait glisser cache toujours la
 * colonne qu'on regarde : mieux vaut deux lignes lisibles qu'une seule
 * inaccessible.
 */
@media (max-width: 1200px) {
    .case-saisie { flex-direction: column; align-items: stretch; }
    .case-saisie > .champ__saisie { width: 100%; }
    .case-heures .champ__saisie { width: 100%; }
}

/*
 * ⚠️ ORANGE, ET RIEN D'AUTRE (§9). Un type renseigné sans heures ne bloque pas,
 * ne déclenche aucune boîte de dialogue, n'empêche pas la validation : vérifier
 * ses prestations relève de la responsabilité de l'employé. Une alerte
 * hebdomadaire finit cliquée sans être lue et érode la crédibilité des vraies
 * alertes — le signal reste visuel.
 */
.total--sans-heures { color: var(--warn); font-weight: 650; }

/*
 * La flèche qui recopie une journée sur la suivante. Geste quotidien de la
 * version Scriptcase : une semaine ordinaire se saisit une fois puis se
 * propage.
 */
.copie-jour {
    border: 1px solid var(--line);
    background: var(--card);
    color: var(--muted);
    border-radius: var(--radius-control);
    padding: 1px 7px;
    cursor: pointer;
    font-size: 13px;
    line-height: 1.5;
}

.copie-jour:hover { color: var(--brand); border-color: var(--brand); }

/* Le sélecteur de semaine, ses deux flèches de part et d'autre. */
.semaine-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.semaine-nav form { display: flex; align-items: center; gap: 8px; }

/* ---------------------------------------------------------------- < 700px */

/*
 * ⚠️ UNE COLONNE sous 700px. La grille RH fait sept jours de large : sur un
 * téléphone elle déborde, et un tableau qui déborde se lit de travers ou pas
 * du tout. Les tableaux gardent leur défilement horizontal propre, dans leur
 * conteneur, plutôt que de faire glisser la page entière.
 */
@media (max-width: 700px) {
    .page { width: min(calc(100% - 20px), var(--page)); padding-top: 20px; }
    .page__header { flex-direction: column; align-items: flex-start; gap: 10px; }
    .page__header h1 { font-size: 26px; }
    .grille { grid-template-columns: 1fr; }
    .carte { padding: 16px; }
    .barre-actions { flex-direction: column; align-items: stretch; }
    .barre-actions .bouton { width: 100%; }
}

@media (max-width: 700px) {
    .compteurs__ligne .compteur { padding-inline: 10px; }
}

/*
 * ⚠️ LA GRILLE BASCULE EN CARTES, une par jour. Sept colonnes ne tiennent pas
 * sur un téléphone, et un tableau qui déborde se lit de travers ou pas du tout.
 *
 * ⚠️ Le coût est réel : `display: block` détruit la sémantique de tableau, donc
 * une synthèse vocale n'annonce plus « Mardi, Après-Midi ». C'est pourquoi
 * chaque case répète sa période en `data-periode` — le libellé que l'en-tête
 * portait revient dans la cellule.
 */
@media (max-width: 700px) {
    .grille-semaine table,
    .grille-semaine tbody,
    .grille-semaine tr,
    .grille-semaine th,
    .grille-semaine td { display: block; width: auto; }

    .grille-semaine thead { display: none; }

    .grille-semaine tr {
        border: 1px solid var(--line);
        border-radius: var(--radius-card);
        background: var(--card);
        margin-bottom: 12px;
        padding: 10px 12px;
    }

    .grille-semaine th[scope="row"] {
        border: 0;
        padding: 0 0 8px;
        font-size: 15px;
        font-weight: 700;
    }

    .grille-semaine td { border: 0; padding: 6px 0; }

    /*
     * ⚠️ En cartes, la ligne de total n'a plus de colonne où s'aligner : elle
     * redevient une simple ligne de texte. Sans ça, son `colspan` la ferait
     * flotter à droite d'une carte vide.
     */
    .grille-semaine__total th[scope="row"] { text-align: left; }
    .grille-semaine__total td { font-size: 18px; }

    .grille-semaine td[data-periode]::before {
        content: attr(data-periode);
        display: block;
        margin-bottom: 3px;
        font-size: 12px;
        text-transform: uppercase;
        letter-spacing: .04em;
        color: var(--muted);
    }
}

/* ----------------------------------------------- récapitulatif mensuel */

/*
 * ⚠️ UN CALENDRIER, PAS UN TABLEAU DE SAISIE. Cet écran RELIT un mois pour le
 * vérifier avant transmission : rien n'y est modifiable, et il ne porte ni code
 * paie ni récupérable — les seconds sont hebdomadaires, un mois n'a pas de
 * seuil.
 */
.mois {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
    gap: 10px;
}

.mois__jour {
    border: 1px solid var(--line);
    border-radius: var(--radius-control);
    padding: 9px 10px;
    background: var(--bg);
}

.mois__jour--weekend { background: color-mix(in srgb, var(--line) 22%, transparent); }
.mois__jour--vide { opacity: .55; }

.mois__date {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin: 0 0 6px;
    font-size: 13px;
}

.mois__date strong { font-size: 17px; }

.mois__total {
    margin-left: auto;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
}

/* ------------------------------------- note du jour et dérogations */

/*
 * ⚠️ LA NOTE EST UNE LIGNE DE TABLEAU À ELLE SEULE, sous les trois périodes :
 * c'est une note sur la JOURNÉE, pas sur une case. La glisser dans une cellule
 * la rattacherait à une période et obligerait à choisir laquelle.
 *
 * ⚠️ Elle est MODIFIABLE, toujours — et c'est ce qui interdit d'y loger la
 * justification d'une dérogation, qui se fige à la validation (§10).
 */
/*
 * ⚠️ **La note est une COLONNE, plus une ligne.** Elle prenait toute la largeur
 * sous chaque jour et doublait la hauteur de la grille. À droite, elle reste
 * sous les yeux sans peser.
 */
td.note-jour { min-width: 150px; }
.note-jour__saisie { width: 100%; font-size: 12.5px; padding-block: 4px; }

/* Une journée sans note s'efface : la case reste, elle ne réclame rien. */
.note-jour--vide .note-jour__saisie { background: transparent; border-style: dashed; }

/*
 * ⚠️ **Les explications descendent sous le tableau.** Elles ne se lisent pas à
 * chaque consultation — on vient chercher un chiffre — mais elles doivent
 * rester à portée : un renvoi coûte un coup d'œil, une colonne de texte coûte
 * la largeur de tout le tableau.
 */
/*
 * ⚠️ **DES VALEURS COURTES N'ONT PAS BESOIN DE LA LARGEUR ENTIÈRE.** Six
 * champs de quelques caractères occupaient chacun une ligne pleine, avec un
 * vide des deux tiers à droite. `auto-fit` place ce qui tient : Nom, Prénom et
 * Date sur une ligne, Fonction et Régime sur la suivante — sans largeur écrite
 * en dur, donc sans casse quand un libellé s'allonge.
 */
.fiche-champs,
.grille-champs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 4px 22px;
    margin: 0;
}

.fiche-champs__item { padding: 6px 0; border-bottom: 1px solid var(--line); }

.fiche-champs dt {
    font-size: 12px;
    font-weight: 650;
    color: var(--muted);
}

.fiche-champs dd { margin: 2px 0 0; }

.notes-tableau {
    margin: 8px 0 0;
    padding-left: 20px;
    font-size: 12px;
    color: var(--muted);
}

.renvoi {
    margin-left: 2px;
    font-size: 10px;
    font-weight: 700;
    color: var(--brand);
}

/* Des chiffres courts n'ont pas besoin de colonnes larges. */
.tableau td.num { white-space: nowrap; width: 1%; }

.violations { margin: 0; padding-left: 18px; }
.violations li { margin-bottom: 10px; }
.violations small { display: block; }

/*
 * ⚠️ LE CONTOURNEMENT DOIT ÊTRE PLUS LOURD QUE LE BLOCAGE (§10). Le motif est
 * un champ obligatoire, pas une case à cocher : demander une dérogation coûte
 * une phrase, et c'est délibéré.
 */
.derogation-demande {
    display: flex;
    gap: 6px;
    align-items: center;
    margin-top: 6px;
}

.derogation-demande .champ__saisie { flex: 1; min-width: 0; }

/* --------------------------------------------------------------- équipes */

/*
 * ⚠️ UNE ÉQUIPE DÉSACTIVÉE RESTE LISIBLE. On désactive, on ne supprime pas :
 * l'historique d'appartenance se conserve, et une équipe dissoute reste
 * lisible sur les décisions qu'elle a portées. Elle s'efface visuellement,
 * elle ne disparaît pas.
 */
.equipe--inactive { opacity: .62; }

.liste-nue { list-style: none; margin: 0; padding: 0; }

.liste-nue li {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 0;
}

.liste-nue form { display: contents; }

/* ------------------------------------------------- tuiles du tableau de bord */

.tuiles {
    display: grid;

    /*
     * ⚠️ **UNE SEULE LIGNE, quel que soit le NOMBRE de tuiles.** `auto-fit`
     * plaçait autant de colonnes que la largeur en permettait, et la septième
     * tombait seule à la ligne — un bloc orphelin, et un grand vide à droite.
     *
     * ⚠️ **`grid-auto-flow: column` s'adapte au rôle**, là où `repeat(7, ...)`
     * aurait laissé deux colonnes vides à un chef d'équipe : il n'en voit que
     * cinq, ni la maladie ni les sorties (§2). Le nombre de tuiles dépend de
     * qui regarde ; la mise en page ne doit pas le supposer.
     */
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 10px;
    margin-bottom: 20px;
}

/*
 * ⚠️ **`grid-auto-rows: 1fr` A ÉTÉ RETIRÉ.** Il étirait la rangée à une hauteur
 * que rien ne réclamait, et les cartes gagnaient une trentaine de pixels vides
 * en bas. Deux corrections successives ont déplacé ce vide — sous le bouton,
 * puis de part et d'autre — sans jamais le supprimer : **la question n'était
 * pas où le placer, c'était pourquoi il existait.**
 *
 * ➡️ **Des cartes de même contenu ont naturellement la même hauteur.** L'étirement
 * par défaut d'une grille suffit à les égaliser dans leur rangée ; il n'ajoute
 * rien tant que les contenus se ressemblent. Si un écart d'une ligne
 * réapparaît, **c'est la carte qu'il faut corriger** — un titre ou une note
 * trop longue —, pas la grille qu'il faut étirer.
 */

/*
 * ⚠️ **Sous 1100 px, sept colonnes deviennent illisibles** — une centaine de
 * pixels par tuile, moins le padding : il ne reste pas de quoi écrire un mot.
 * On repasse alors au retour à la ligne, où l'orphelin coûte moins cher qu'un
 * texte coupé.
 */
@media (max-width: 1100px) {
    .tuiles {
        grid-auto-flow: row;
        grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    }
}

/*
 * ⚠️ **Une tuile est plus SERRÉE qu'une carte ordinaire.** Le padding de 20 px
 * du socle vaut pour une carte qui porte un tableau ou un formulaire ; sur sept
 * tuiles alignées il se paie six fois en largeur et deux fois en hauteur, pour
 * entourer trois lignes de texte.
 */
.tuile { padding: 12px 10px 10px; text-align: center; }

/*
 * ⚠️ **NI MARGE AUTOMATIQUE, NI ÉTIREMENT.** `margin-top: auto` calait le
 * bouton en bas ; mais une marge automatique n'espace pas, elle **absorbe** —
 * elle ramassait tout l'espace libre en un seul trou. `flex: 1` sur le corps
 * faisait la même chose autrement : il réclamait une hauteur que le contenu ne
 * demandait pas.
 *
 * ➡️ **Quatre écarts fixes, du chiffre au bouton.** La carte fait exactement la
 * hauteur de ce qu'elle contient, et les boutons s'alignent parce que les
 * cartes se ressemblent — pas parce qu'on les y pousse.
 *
 * ⚠️ Le flex vit sur `.carte__corps`, pas sur `.tuile` : le composant enveloppe
 * son contenu dans ce `div`.
 */
.tuile,
.tuile .carte__corps {
    display: flex;
    flex-direction: column;
}

.tuile .carte__corps { align-items: center; }

.tuile__nombre {
    margin: 0;
    font-size: 26px;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
    line-height: 1.05;
}

/*
 * ⚠️ **Le chiffre et son titre sont UNE seule information**, pas deux : c'est
 * « 4 demandes d'absence » qu'on lit, en un coup d'œil. Les espacer les
 * détache l'un de l'autre et oblige à recoller les deux moitiés.
 */
.tuile__titre {
    min-height: 2.4em;
    margin: 4px 0 0;
    font-size: 13px;
    line-height: 1.2;
}

/*
 * ⚠️ **SEUL LE TITRE GARDE SA RÉSERVE DE DEUX LIGNES**, et c'est la carte qu'on
 * corrige, pas la grille qu'on étire : dans une colonne de cette largeur,
 * « Maladie à traiter » tient sur une ligne là où « Prestations à valider » en
 * prend deux. Réserver la boîte du texte le plus long est le seul moyen de les
 * égaliser sans renommer des tuiles dont le nom est l'identité.
 *
 * ➡️ Si l'un des sept titres se raccourcit un jour au point que TOUS tiennent
 * sur une ligne, cette réserve devient inutile et doit sauter avec eux.
 */

/*
 * ⚠️ **PLUS DE HAUTEUR RÉSERVÉE ICI.** Les sept notes tiennent sur une ligne
 * depuis qu'elles sont bornées à 30 signes — un test le garantit —, donc elles
 * ont déjà la même hauteur. En réserver deux ajoutait une ligne vide à chacune
 * des sept.
 */
.tuile__note {
    margin: 4px 0 10px;
    font-size: 11.5px;
    line-height: 1.3;
}

/*
 * ⚠️ « RIEN À TRAITER » EST L'ÉTAT NORMAL, pas une réussite à célébrer.
 * Scriptcase teinte ses tuiles en vert quand la file est vide et en rouge
 * sinon ; on garde la distinction, qui se lit d'un coup d'œil, mais le rouge
 * dit « il y a du travail » — jamais « il y a un problème ». D'où une bordure
 * accentuée plutôt qu'un fond d'alerte.
 */
.tuile--travail { border-color: var(--brand); }
.tuile--travail .tuile__nombre { color: var(--brand); }

/* ------------------------------------------------------- écran de présence */

/*
 * ⚠️ TROIS ÉTATS, ET AUCUN DÉTAIL (§2). C'est l'absence de détail qui rend cet
 * écran ouvert à tout le personnel : un écran distinguant « maladie »
 * d'« absent » diffuserait une donnée de santé à tout le monde. Il n'y a donc
 * que trois couleurs ici, et il ne doit jamais y en avoir une quatrième — une
 * nuance de plus, c'est une donnée personnelle de plus.
 */
/*
 * ⚠️ LES TROIS ÉTATS SONT DES JETONS, pas des littéraux — pour que la palette
 * ait UN endroit où les retoucher, et un seul. Le socle existe précisément pour
 * qu'aucune couleur ne soit réécrite ailleurs.
 *
 * ⚠️ Ils gardent trois TEINTES DISTINCTES, et ce n'est pas décoratif : le §2
 * pose que confondre « hors murs » et « absent » ferait renoncer à joindre
 * quelqu'un qui travaille et répond. Une palette qui les rapprocherait casserait
 * la seule chose que cet écran sert à dire.
 */
:root {
    --presence-present: #10b981;
    --presence-hors-murs: #38a3c9;
    --presence-absent: #414c58;
}

/*
 * ⚠️ **LA COULEUR NE PORTE JAMAIS L'INFORMATION SEULE.** Un daltonien ne
 * distingue pas le vert du bleu : chaque état porte donc une FORME qui le
 * différencie en niveaux de gris — pastille pleine et arrondie, pastille
 * pleine et carrée, contour pointillé. La couleur ne fait que confirmer.
 *
 * ⚠️ **La lettre, elle, porte la PÉRIODE** — M, AM, S. Deux informations par
 * pastille, aucune redondante : sans elle, il faudrait compter les positions
 * pour savoir de quelle demi-journée on parle.
 */
/*
 * ⚠️ **DES BLOCS PLEINS, PAS DES ÉTIQUETTES GRISES.** C'est ce qui fait la
 * lisibilité de la grille Scriptcase (`Scriptcase/RH/49.png`) : on lit une
 * semaine d'un balayage du regard, sans lire un seul mot. Une pastille discrète
 * oblige à déchiffrer case par case — sur vingt employés et sept jours, c'est
 * cent quarante déchiffrages.
 *
 * ⚠️ **LA COULEUR NE PORTE JAMAIS L'INFORMATION SEULE.** Un daltonien ne
 * distingue pas le vert du bleu : chaque bloc porte donc son **mot** en clair —
 * « Présent », « Hors murs », « Absent » — et le mot survit en niveaux de gris.
 * La couleur ne fait qu'accélérer une lecture qui reste possible sans elle.
 *
 * ⚠️ **UNE SEULE LIGNE : « MATIN Présent ».** Scriptcase les empile sur deux,
 * ce qui double la hauteur de chaque case ; à vingt employés il faut défiler
 * pour lire une semaine. Le `<b>` porte la période, le reste porte l'état.
 */
.creneau {
    display: block;
    margin: 0 0 3px;
    padding: 3px 7px;
    border: 1.5px solid transparent;
    border-radius: 5px;
    background: var(--presence-absent, #414c58);
    color: #fff;
    font-size: 11.5px;
    font-weight: 600;
    line-height: 1.35;
    white-space: nowrap;
}

.creneau:last-child { margin-bottom: 0; }

/*
 * ⚠️ **La période est ÉCRASÉE, pas mise en gras.** Elle sert de repère, pas
 * d'information principale : « MATIN » en petites capitales translucides se
 * saute à la lecture quand on cherche l'état, et se retrouve quand on cherche
 * la demi-journée.
 */
.creneau b {
    margin-right: 4px;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .4px;
    opacity: .72;
}

.creneau small { margin-left: 5px; font-size: 10.5px; opacity: .8; }

.creneau--present { background: var(--presence-present, #10b981); }
.creneau--hors_murs { background: var(--presence-hors-murs, #38a3c9); }

/*
 * ⚠️ « Absent » est SOURD, pas alarmant : il ne signale aucun problème et ne
 * porte aucun jugement — la personne peut être en congé, en formation, ou
 * n'avoir simplement rien à faire là ce jour-là. Le rouge en ferait une alerte.
 */
.creneau--absent { background: var(--presence-absent, #414c58); }

/*
 * ⚠️ **LE POINTILLÉ CHANGE CE QUE LA CASE AFFIRME**, il ne la décore pas. Plein
 * = constaté, aux prestations ; pointillé = prévu, encore au prévisionnel et
 * que la semaine peut démentir. Un « Absent » planifié et un « Absent » constaté
 * n'engagent pas la même chose, et la légende le dit — sans elle, les deux se
 * lisent comme un fait.
 *
 * ⚠️ **Ce n'est PAS la distinction de Scriptcase**, qui oppose l'horaire de base
 * au prévisionnel : il affiche la semaine type quand rien n'est encodé. Notre
 * service ne lit jamais l'horaire de base — une case inconnue reste vide et le
 * dit.
 */
.creneau--prevu {
    border-style: dashed;
    border-color: rgb(255 255 255 / 65%);
    background-image: linear-gradient(rgb(255 255 255 / 22%), rgb(255 255 255 / 22%));
}

/*
 * ⚠️ **L'objectif tenait en une phrase : huit personnes et sept jours sur un
 * portable, sans ascenseur.** C'est un écran de consultation rapide — on
 * l'ouvre pour savoir si un collègue est là. Il doit répondre d'un coup d'œil.
 */
.presence__legende {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 14px;
    margin: 0;
    font-size: 12.5px;
    color: var(--muted);
}

.presence__legende .creneau { display: inline-block; margin: 0 2px 0 0; }

.presence__reserve { margin: 8px 0 0; font-size: 12px; }

/*
 * ⚠️ **Le nom du jour ET sa date, sur deux lignes** — l'en-tête de Scriptcase.
 * Le nom seul ne dit pas laquelle des cinquante-deux semaines on regarde ; la
 * date seule oblige à compter pour savoir si le 03/09 est un jeudi.
 */
.presence thead th {
    text-align: center;
    line-height: 1.2;
    white-space: nowrap;
}

.presence thead th:first-child { text-align: left; }
.presence__jour { display: block; font-size: 12.5px; }
.presence__date { display: block; font-size: 11px; font-weight: 600; opacity: .72; }

/*
 * ⚠️ **Le jour courant se repère AVANT de se lire.** C'est la colonne qu'on
 * vient chercher neuf fois sur dix — « qui est là aujourd'hui ». Sans repère,
 * il faut d'abord retrouver la date, puis descendre.
 */
.presence thead th.est-aujourdhui {
    background: var(--brand);
    color: var(--brand-ink);
    border-radius: 6px 6px 0 0;
}

.presence td.est-aujourdhui { background: var(--brand-bg); }

/*
 * ⚠️ **Le week-end grisé n'est pas décoratif** : les centres culturels n'ont
 * pas de week-end structurel (§7), donc aucune case n'y est attendue — et
 * quand il y en a une, elle déclenche les taux 2 et 3 (§6). Le fond dit
 * « ici, c'est l'exception ».
 */
.presence thead th.est-weekend { background: var(--surface-strong); }
.presence td.est-weekend { background: var(--surface-muted); }

.presence th[scope="row"] { white-space: normal; min-width: 120px; font-size: 13px; }
.presence td { vertical-align: middle; }
.presence th, .presence td { padding-block: 5px; }

/*
 * ⚠️ **LE WEEK-END EST GRISÉ SUR TOUTES LES GRILLES DE SEMAINE**, et ce n'est
 * pas de la décoration : les centres culturels n'ont **pas de week-end
 * structurel** (§7) — l'horaire de base n'y porte jamais de case. Une ligne
 * samedi ou dimanche est donc toujours une exception, et elle coûte cher :
 * c'est elle qui déclenche le **taux 2** et le **taux 3** (§6), et le dimanche
 * sort du cumul des compensatoires.
 *
 * ➡️ Celui qui encode doit voir qu'il change de régime **avant** de saisir, pas
 * en relisant son solde le mois suivant.
 *
 * ⚠️ **Une seule règle, trois grilles** — encodage des prestations, du
 * prévisionnel, et les deux écrans de lecture seule. Elles portent toutes
 * `data-jour` : une teinte posée grille par grille divergerait à la première
 * qu'on oublie.
 */
[data-jour="Samedi"],
[data-jour="Dimanche"] { background: var(--surface-muted); }

[data-jour="Samedi"] > th[scope="row"],
[data-jour="Dimanche"] > th[scope="row"] { background: var(--surface-strong); }

/* -------------------------------------------------------------- onglets */

/*
 * La barre d'onglets de la fiche employé.
 *
 * ⚠️ **Ce sont des LIENS, pas des boutons.** Chaque onglet est une URL propre :
 * on l'ouvre dans un onglet du navigateur, on le met en favori, on y revient
 * par le bouton Précédent. Un basculement JavaScript aurait perdu les trois.
 *
 * ⚠️ **Elle défile horizontalement plutôt que de passer à la ligne.** Sept
 * onglets sur un téléphone tiendraient sur trois lignes et pousseraient le
 * contenu sous la ligne de flottaison ; le défilement garde la grille visible.
 */
/*
 * ⚠️ **ILS PASSENT À LA LIGNE, ILS NE SE COUPENT PAS.** `overflow-x: auto`
 * seul ne suffisait pas : une zone défilante à l'intérieur d'une page se
 * remarque mal, et sept onglets sortaient du cadre à droite sans que rien ne
 * l'indique. Le retour à la ligne garantit qu'aucun onglet n'est hors
 * d'atteinte, quelle que soit la largeur.
 *
 * ⚠️ Éprouvé aux deux largeurs qui comptent ici : 1280 px et 720p.
 */
.onglets {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 2px;
    margin: 0 0 var(--gap);
    padding: 0 0 2px;
    border-bottom: 1px solid var(--line);
}

.onglets__lien {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    flex: 0 1 auto;
    min-width: 0;
    padding: 9px 14px;
    border: 1px solid var(--line);
    border-bottom: 0;
    border-radius: 9px 9px 0 0;
    background: var(--surface-strong, #eef2f5);
    color: var(--ink-soft);
    text-decoration: none;
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
}

.onglets__icone { width: 15px; height: 15px; flex: 0 0 auto; opacity: .7; }

/*
 * ⚠️ `var(--jeton, littéral)` PARTOUT OÙ UNE COULEUR RESTE EN DUR. Le token
 * n'existe pas encore sur cette branche ; le repli garde l'apparence actuelle.
 */
.onglets__lien:hover { color: var(--ink); background: var(--card); }

/*
 * ⚠️ **L'ONGLET ACTIF EST RATTACHÉ À SA PAGE**, il n'est pas seulement plus
 * foncé. Fond blanc, filet de marque au-dessus, et un pixel qui recouvre la
 * ligne du bas : la languette se raccorde visuellement au contenu, comme dans
 * la référence (`Scriptcase/RH/51.png`). Des onglets tous plats et gris se
 * lisent comme une liste de liens, pas comme une position.
 */
.onglets__lien.is-active {
    position: relative;
    bottom: -1px;
    border-color: var(--line);
    border-top: 3px solid var(--brand);
    padding-top: 7px;
    background: var(--card);
    color: var(--ink);
    font-weight: 800;
}

.onglets__lien.is-active .onglets__icone { opacity: 1; color: var(--brand); }
