/* =============================================================================
   LOGIKLEAN - feuille de style

   LA CHARTE, EN UNE PHRASE : un logiciel en ligne sobre et lisible, ou la
   couleur sert a dire quelque chose (une action, un etat, une urgence) et
   jamais a decorer.

   Sans framework externe et sans police telechargee : rien a autoriser dans
   la politique de securite, aucune adresse IP envoyee a un tiers, et
   l'affichage reste instantane sur un telephone en 4G au fond d'un parking.

   Tout passe par les VARIABLES ci-dessous. Les ecrans propres a chaque module
   (plus bas dans ce fichier) les reutilisent : changer une couleur ici la
   change partout.
   ========================================================================== */

:root {
    /* -- La marque -------------------------------------------------------- */
    --bleu:         #1d64a3;
    --bleu-fonce:   #154b7a;
    --bleu-pale:    #ebf3fb;
    --bleu-anneau:  rgba(29, 100, 163, .18);

    /* -- Les etats -------------------------------------------------------- */
    --vert:         #12805c;
    --vert-pale:    #e7f6ee;
    --rouge:        #b3261e;
    --rouge-pale:   #fdecea;
    --orange:       #b26a00;
    --orange-pale:  #fdf3e1;

    /* -- Les neutres ------------------------------------------------------ */
    --texte:        #111827;
    --texte-moyen:  #344054;
    --texte-doux:   #5d6b7e;
    --texte-faible: #8a96a8;
    --bordure:      #e4e7ec;
    --bordure-forte:#d0d5dd;
    --fond:         #f5f6f8;
    --fond-doux:    #f9fafb;
    --blanc:        #ffffff;

    /* -- Les formes ------------------------------------------------------- */
    --radius:       10px;
    --radius-lg:    14px;
    --ombre:        0 1px 2px rgba(16, 24, 40, .05);
    --ombre-carte:  0 1px 3px rgba(16, 24, 40, .06), 0 1px 2px rgba(16, 24, 40, .03);
    --ombre-haute:  0 12px 24px -6px rgba(16, 24, 40, .14), 0 4px 8px -4px rgba(16, 24, 40, .06);

    --police: "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
              "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: var(--police);
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--texte);
    background: var(--fond);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a { color: var(--bleu); text-decoration: none; }
a:hover { color: var(--bleu-fonce); text-decoration: underline; text-underline-offset: 2px; }

h1 { font-size: 21px; font-weight: 650; letter-spacing: -.015em; margin: 0; }
h2 { font-size: 16.5px; font-weight: 650; letter-spacing: -.01em; margin: 0 0 12px; }
h3 {
    font-size: 12px;
    font-weight: 600;
    margin: 0 0 8px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--texte-faible);
}

.muted { color: var(--texte-doux); }
.small { font-size: 13px; }

/* Les icones (apps/core/templatetags/icones.py) : la couleur du texte, et
   jamais de retrecissement dans une ligne trop etroite. */
.icone { flex-shrink: 0; vertical-align: -3px; }
.icone-lg { width: 22px; height: 22px; }

/* Visible pour un lecteur d'ecran, invisible a l'oeil.
 *
 * Sert la ou le champ se comprend sans etiquette - la zone d'ecriture d'un
 * fil de discussion, par exemple, dont le texte d'invite dit deja tout. Une
 * etiquette « Message » au-dessus d'une zone de saisie de messagerie est du
 * bruit a l'ecran, mais son absence rendrait le champ muet pour quelqu'un qui
 * navigue a la voix. On la retire de la vue, pas du document. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Le contour au clavier, partout, et seulement au clavier. */
:focus-visible { outline: 2px solid var(--bleu); outline-offset: 2px; }

/* -----------------------------------------------------------------------------
   MISE EN PAGE APPLICATIVE
   --------------------------------------------------------------------------
   UN MENU CLAIR, UNE PAGE CLAIRE. Le menu sombre faisait deux mondes sur le
   meme ecran ; clair, il s'efface derriere le contenu, et seule l'entree ou
   l'on se trouve prend la couleur de la marque.

   Trois espaces, trois signatures - celui qui garde plusieurs onglets ouverts
   doit savoir d'un coup d'oeil ou il est :
     - l'entreprise   menu clair, accent bleu ;
     - l'espace client menu clair, accent VERT D'EAU ;
     - le back-office  menu SOMBRE : on y administre la plateforme entiere.
   -------------------------------------------------------------------------- */
.app { display: flex; min-height: 100vh; }

.sidebar {
    --accent: var(--bleu);
    --accent-pale: var(--bleu-pale);
    position: sticky;
    top: 0;
    height: 100vh;
    width: 256px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    color: var(--texte-moyen);
    background: var(--blanc);
    border-right: 1px solid var(--bordure);
}
.sidebar-portal { --accent: #0f766e; --accent-pale: #e6f4f2; }

.brand {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 18px 18px 16px;
}
.brand-mark {
    display: grid;
    place-items: center;
    width: 36px; height: 36px;
    flex-shrink: 0;
    border-radius: 10px;
    background: linear-gradient(135deg, var(--accent, var(--bleu)), var(--bleu-fonce));
    color: #fff;
    font-weight: 700;
    font-size: 13px;
    letter-spacing: .02em;
    box-shadow: 0 2px 6px rgba(21, 75, 122, .25);
}
.sidebar-portal .brand-mark { background: linear-gradient(135deg, #14958a, #0f5f59); }
.brand-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    font-weight: 650;
    font-size: 14.5px;
    color: var(--texte);
    line-height: 1.25;
}
.brand-text small {
    font-weight: 600;
    font-size: 10.5px;
    letter-spacing: .08em;
    color: var(--texte-faible);
}

.nav { display: flex; flex-direction: column; padding: 8px 12px 12px; gap: 2px; flex: 1; }
.nav a {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 11px;
    border-radius: 8px;
    color: var(--texte-moyen);
    font-size: 14px;
    font-weight: 500;
    line-height: 1.35;
}
.nav a .icone { color: var(--texte-faible); }
.nav a > span:not(.nav-badge) { flex: 1; min-width: 0; }
.nav a:hover { background: var(--fond); color: var(--texte); text-decoration: none; }
.nav a:hover .icone { color: var(--texte-doux); }
.nav a.active {
    background: var(--accent-pale);
    color: var(--accent);
    font-weight: 600;
}
.nav a.active .icone { color: var(--accent); }

.nav-section {
    margin: 18px 11px 6px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--texte-faible);
}
.nav-disabled {
    padding: 8px 12px;
    font-size: 14px;
    color: var(--texte-faible);
    display: flex;
    justify-content: space-between;
}
.nav-disabled em { font-style: normal; font-size: 11px; opacity: .8; }

.sidebar-footer { padding: 12px; border-top: 1px solid var(--bordure); }
.user-chip {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px;
    margin-bottom: 6px;
    border-radius: 10px;
    color: var(--texte);
}
.user-chip:hover { background: var(--fond); text-decoration: none; color: var(--texte); }
.user-chip > span:last-child { min-width: 0; }
.user-chip strong { display: block; font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-chip small { display: block; color: var(--texte-doux); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.avatar {
    display: grid; place-items: center;
    width: 34px; height: 34px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--accent-pale, var(--bleu-pale));
    color: var(--accent, var(--bleu));
    font-size: 12.5px; font-weight: 700;
}

/* -- Le back-office : le meme menu, en sombre ---------------------------- */
.sidebar-platform {
    --accent: #ffffff;
    --accent-pale: rgba(255, 255, 255, .12);
    color: #c9d4df;
    background: #0f2233;
    border-right-color: #0f2233;
}
.sidebar-platform .brand-mark { background: linear-gradient(135deg, #2b7bc4, #154b7a); }
.sidebar-platform .brand-text { color: #fff; }
.sidebar-platform .brand-text small { color: #8ba0b3; }
.sidebar-platform .nav a { color: #c9d4df; }
.sidebar-platform .nav a .icone { color: #7f95a9; }
.sidebar-platform .nav a:hover { background: rgba(255, 255, 255, .07); color: #fff; }
.sidebar-platform .nav a.active .icone { color: #fff; }
.sidebar-platform .sidebar-footer { border-top-color: rgba(255, 255, 255, .08); }
.sidebar-platform .user-chip { color: #fff; }
.sidebar-platform .user-chip small { color: #8ba0b3; }
.sidebar-platform .avatar { background: rgba(255, 255, 255, .12); color: #fff; }
.sidebar-platform .btn-ghost { color: #c9d4df; }
.sidebar-platform .btn-ghost:hover { background: rgba(255, 255, 255, .08); color: #fff; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: 68px;
    padding: 14px 32px;
    background: var(--blanc);
    border-bottom: 1px solid var(--bordure);
}
.topbar-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }

/* -----------------------------------------------------------------------------
   LE MENU LATERAL SE REPLIE
   --------------------------------------------------------------------------
   Il DISPARAIT au lieu de retrecir : voir `static/js/menu.js`.

   Le bouton, lui, reste dans la barre du haut : visible dans les deux etats,
   toujours au meme endroit. Un bouton qui partirait avec le menu ne
   permettrait plus de le rappeler.
   -------------------------------------------------------------------------- */
.topbar-gauche { display: flex; align-items: center; gap: 14px; min-width: 0; }
.topbar-gauche h1 { min-width: 0; }

.menu-bascule {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 36px; height: 36px;
    border: 1px solid var(--bordure);
    border-radius: 9px;
    background: var(--blanc);
    color: var(--texte-doux);
    line-height: 1;
    cursor: pointer;
}
.menu-bascule:hover { background: var(--fond); color: var(--texte); }

body.menu-replie .sidebar { display: none; }

.content { padding: 28px 32px 48px; }

/* -----------------------------------------------------------------------------
   CARTES ET GRILLES
   -------------------------------------------------------------------------- */
.card {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius-lg);
    box-shadow: var(--ombre-carte);
    padding: 20px 24px;
    margin-bottom: 20px;
}
.card-title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}
.card-title h2 { margin: 0; }

.grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }

/* -- Les indicateurs (KPI) ------------------------------------------------
   Le chiffre d'abord, gros ; ce qu'il compte dessous, en clair. Un etat
   (orange, rouge) colore le CHIFFRE et un liseré : le fond reste blanc, sinon
   quatre tuiles colorees cote a cote ne disent plus laquelle presse. */
.stat {
    position: relative;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    padding: 16px 18px;
    overflow: hidden;
}
.stat-value {
    font-size: 28px;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
}
.stat-label { margin-top: 4px; font-size: 13px; font-weight: 500; color: var(--texte-doux); }
.stat-icone {
    display: grid;
    place-items: center;
    width: 36px; height: 36px;
    margin-bottom: 12px;
    border-radius: 10px;
    background: var(--bleu-pale);
    color: var(--bleu);
}

/* -----------------------------------------------------------------------------
   TABLEAUX
   -------------------------------------------------------------------------- */
.table-wrapper { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { padding: 11px 14px; text-align: left; border-bottom: 1px solid var(--bordure); }
th {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--texte-doux);
    background: var(--fond-doux);
    white-space: nowrap;
}
thead th:first-child { border-top-left-radius: 8px; }
thead th:last-child { border-top-right-radius: 8px; }
tbody tr { transition: background-color .12s ease; }
tbody tr:hover { background: var(--fond-doux); }
tbody tr:last-child td { border-bottom: 0; }
.table-empty { padding: 32px 16px; text-align: center; color: var(--texte-doux); }

/* -----------------------------------------------------------------------------
   BADGES
   --------------------------------------------------------------------------
   En casse normale : une pastille en capitales se lit comme un cri, et cinq
   pastilles par ecran font un ecran qui crie. Le petit point devant donne la
   couleur meme a qui la distingue mal - le libelle, lui, dit tout. */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    line-height: 18px;
    white-space: nowrap;
    background: #f0f2f5;
    color: var(--texte-moyen);
}
.badge-ACTIVE::before, .badge-ok::before, .badge-TRIAL::before,
.badge-SUSPENDED::before, .badge-warn::before,
.badge-DISABLED::before, .badge-off::before {
    content: "";
    width: 6px; height: 6px;
    flex-shrink: 0;
    border-radius: 50%;
    background: currentColor;
    opacity: .7;
}
.badge-ACTIVE, .badge-ok      { background: var(--vert-pale); color: #0d6b4c; }
.badge-TRIAL                  { background: var(--bleu-pale); color: var(--bleu-fonce); }
.badge-SUSPENDED, .badge-warn { background: var(--orange-pale); color: #8a5200; }
.badge-DISABLED, .badge-off   { background: var(--rouge-pale); color: #8f201a; }

/* -----------------------------------------------------------------------------
   FORMULAIRES
   -------------------------------------------------------------------------- */
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 13.5px; font-weight: 600; color: var(--texte-moyen); margin-bottom: 6px; }
.required { color: var(--rouge); }

.form-control, .form-select {
    width: 100%;
    min-height: 40px;
    padding: 8px 12px;
    font: inherit;
    color: var(--texte);
    background: var(--blanc);
    border: 1px solid var(--bordure-forte);
    border-radius: 8px;
    box-shadow: var(--ombre);
    transition: border-color .12s ease, box-shadow .12s ease;
}
textarea.form-control { min-height: 96px; line-height: 1.5; }
.form-control::placeholder { color: var(--texte-faible); }
.form-control:hover, .form-select:hover { border-color: #b8c0cc; }
.form-control:focus, .form-select:focus {
    outline: none;
    border-color: var(--bleu);
    box-shadow: 0 0 0 4px var(--bleu-anneau);
}
.form-control:disabled, .form-select:disabled { background: var(--fond); color: var(--texte-doux); }
.field-error .form-control, .field-error .form-select { border-color: var(--rouge); }
.field-error .form-control:focus, .field-error .form-select:focus { box-shadow: 0 0 0 4px rgba(179, 38, 30, .15); }

input[type="checkbox"], input[type="radio"] { accent-color: var(--bleu); width: 16px; height: 16px; vertical-align: -3px; }

.help { margin: 6px 0 0; font-size: 12.5px; color: var(--texte-doux); }
.error { margin: 6px 0 0; font-size: 12.5px; font-weight: 500; color: var(--rouge); }

.form-row { display: grid; gap: 0 20px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.form-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 20px;
    padding-top: 18px;
    border-top: 1px solid var(--bordure);
}

/* -----------------------------------------------------------------------------
   BOUTONS
   -------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 38px;
    padding: 8px 16px;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    border: 1px solid transparent;
    border-radius: 8px;
    cursor: pointer;
    background: var(--bleu);
    color: #fff;
    box-shadow: var(--ombre);
    transition: background-color .12s ease, border-color .12s ease, box-shadow .12s ease;
}
.btn:hover { background: var(--bleu-fonce); text-decoration: none; color: #fff; }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 4px var(--bleu-anneau); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }
.btn-secondary { background: var(--blanc); color: var(--texte-moyen); border-color: var(--bordure-forte); }
.btn-secondary:hover { background: var(--fond-doux); color: var(--texte); border-color: #b8c0cc; }
.btn-danger { background: var(--rouge); }
.btn-danger:hover { background: #8f201a; }
.btn-ghost {
    width: 100%;
    justify-content: flex-start;
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    color: var(--texte-doux);
    font-weight: 500;
}
.btn-ghost:hover { background: var(--fond); color: var(--texte); }
.btn-sm { min-height: 32px; padding: 5px 12px; font-size: 13px; border-radius: 7px; }
.btn-block { width: 100%; }

/* -----------------------------------------------------------------------------
   MESSAGES
   -------------------------------------------------------------------------- */
.messages { margin-bottom: 20px; }
.alert {
    padding: 12px 16px;
    border-radius: var(--radius);
    border: 1px solid;
    border-left-width: 4px;
    margin-bottom: 10px;
    font-size: 14px;
}
.alert-success { background: #f0faf5; border-color: #b7e2cc; border-left-color: var(--vert); color: #0d5c41; }
.alert-info    { background: #f1f7fd; border-color: #c4dcf1; border-left-color: var(--bleu); color: var(--bleu-fonce); }
.alert-warning { background: #fffaf0; border-color: #f0d9ab; border-left-color: var(--orange); color: #7a4800; }
.alert-error   { background: #fef4f3; border-color: #f3c7c3; border-left-color: var(--rouge); color: #8f201a; }

/* -----------------------------------------------------------------------------
   PAGES D'AUTHENTIFICATION
   --------------------------------------------------------------------------
   Deux panneaux : a gauche, ce qu'est le logiciel ; a droite, le formulaire.
   Sous 900 px, le panneau de gauche disparait - sur un telephone, on vient
   se connecter, pas lire une plaquette. */
.layout-auth { min-height: 100vh; background: var(--blanc); }
.auth-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); min-height: 100vh; }
.auth-aside {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 32px;
    padding: 48px 56px;
    color: #dbe7f3;
    background:
        radial-gradient(1200px 500px at -10% -10%, rgba(255, 255, 255, .10), transparent 60%),
        linear-gradient(150deg, #1d64a3 0%, #154b7a 55%, #0f2f4d 100%);
}
.auth-aside-marque { display: flex; align-items: center; gap: 12px; color: #fff; font-weight: 700; font-size: 17px; letter-spacing: .04em; }
.auth-aside h2 { color: #fff; font-size: 30px; line-height: 1.2; letter-spacing: -.02em; max-width: 440px; margin: 0 0 14px; }
.auth-aside p { margin: 0; max-width: 440px; font-size: 15.5px; color: #c4d6e8; }
.auth-points { list-style: none; padding: 0; margin: 28px 0 0; display: grid; gap: 14px; }
.auth-points li { display: flex; gap: 12px; align-items: flex-start; font-size: 14.5px; color: #e6eef6; }
.auth-points .icone { margin-top: 1px; padding: 6px; width: 30px; height: 30px; border-radius: 8px; background: rgba(255, 255, 255, .12); color: #fff; }
.auth-aside-pied { font-size: 12.5px; color: #9fb7cd; }

.auth-main { display: grid; place-items: center; padding: 40px 24px; background: var(--fond); }
.auth-wrapper { width: 100%; max-width: 420px; }
.auth-card {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: 16px;
    box-shadow: var(--ombre-haute);
    padding: 36px 36px 32px;
}
.auth-brand { text-align: center; margin-bottom: 28px; }
.auth-brand .brand-mark { margin: 0 auto 14px; width: 48px; height: 48px; font-size: 16px; border-radius: 13px; }
.auth-brand h1 { font-size: 22px; }
.auth-brand p { margin: 4px 0 0; font-size: 13.5px; }
.auth-card .btn[type="submit"] { width: 100%; min-height: 42px; margin-top: 4px; }
.auth-footer { text-align: center; margin-top: 22px; font-size: 12.5px; color: var(--texte-doux); }
.auth-links { margin-top: 18px; text-align: center; font-size: 13.5px; }

@media (max-width: 900px) {
    .auth-split { grid-template-columns: 1fr; }
    .auth-aside { display: none; }
}

/* -----------------------------------------------------------------------------
   FILTRES ET PAGINATION
   -------------------------------------------------------------------------- */
.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 18px; }
.filters .field { margin-bottom: 0; }
.filters .form-control, .filters .form-select { min-width: 180px; width: auto; }
.filters input[type="search"], .filters input[name="q"] {
    padding-left: 36px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238a96a8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 12px center;
}

.pagination { display: flex; gap: 8px; align-items: center; justify-content: center; margin-top: 20px; font-size: 14px; }
.pagination a {
    display: inline-flex; align-items: center;
    min-height: 34px; padding: 6px 12px;
    border: 1px solid var(--bordure-forte); border-radius: 8px;
    background: var(--blanc); color: var(--texte-moyen); font-weight: 500;
}
.pagination a:hover { background: var(--fond-doux); text-decoration: none; }

/* -----------------------------------------------------------------------------
   PAGES D'ERREUR
   -------------------------------------------------------------------------- */
.error-page { display: grid; place-items: center; min-height: 100vh; text-align: center; padding: 24px; }
.error-code { font-size: 72px; font-weight: 800; letter-spacing: -.03em; color: var(--bleu); line-height: 1; }

/* =============================================================================
   RESPONSIVE - TELEPHONE, TABLETTE, ORDINATEUR
   =============================================================================
   TROIS PALIERS, ET ILS CORRESPONDENT A TROIS FACONS DE TENIR L'APPAREIL :

     > 1024px   ORDINATEUR. Menu lateral deploye, tableaux en colonnes.
     641-1024   TABLETTE. Menu en TIROIR, tableaux encore en colonnes mais
                les grilles se resserrent. C'est le format du responsable qui
                fait le tour du depot avec une tablette a la main.
     <= 640px   TELEPHONE. Menu en tiroir, et LES TABLEAUX DEVIENNENT DES
                CARTES (voir `.table-stack`).

   POURQUOI UN TIROIR ET PAS UN MENU EMPILE
   -----------------------------------------
   La version precedente passait la barre laterale en pleine largeur au-dessus
   du contenu. Sur un telephone, cela voulait dire faire defiler QUINZE
   ENTREES DE MENU avant d'atteindre le titre de la page - a chaque page, y
   compris quand on ne cherchait pas le menu. Un menu qu'on traverse pour
   arriver ailleurs est un menu mal place.

   Le tiroir sort par-dessus le contenu, sur commande, et se referme au
   changement de page. Il utilise le meme bouton que le repli du bureau
   (`menu.js` choisit la classe selon la largeur).
   ========================================================================== */

/* -----------------------------------------------------------------------------
   LE TABLEAU QUI DEVIENT DES CARTES
   --------------------------------------------------------------------------
   Un tableau de six colonnes sur un ecran de 360 px ne se lit pas : soit il
   deborde, soit les colonnes se reduisent a deux caracteres. Les deux
   solutions habituelles sont mauvaises - le defilement horizontal fait
   perdre la premiere colonne (celle qui dit DE QUOI on parle), et masquer des
   colonnes cache justement ce qu'on est venu lire.

   `.table-stack` transforme donc chaque LIGNE en carte : l'en-tete disparait,
   et chaque cellule porte son intitule a gauche, pris dans son `data-label`.

   USAGE : `<table class="table-stack">` et `<td data-label="Client">`.
   Une cellule sans `data-label` s'affiche simplement sans intitule - c'est ce
   qu'on veut pour les colonnes d'actions.
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
    .table-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
    .table-stack, .table-stack tbody, .table-stack tr, .table-stack td { display: block; width: 100%; }

    .table-stack tr {
        margin-bottom: 10px;
        padding: 10px 12px;
        border: 1px solid var(--bordure);
        border-radius: var(--radius);
        background: var(--blanc);
    }
    .table-stack td {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        gap: 12px;
        padding: 5px 0;
        border: 0;
        text-align: left;
    }
    .table-stack td::before {
        content: attr(data-label);
        flex-shrink: 0;
        font-size: 12px;
        font-weight: 600;
        color: var(--texte-doux);
    }
    /* Une cellule sans intitule prend toute la largeur : c'est le cas des
       colonnes d'actions, ou un intitule vide laisserait un trou. */
    .table-stack td:not([data-label]) { display: block; }
    .table-stack td.row-actions { padding-top: 10px; }
    .table-stack td.row-actions .btn { width: 100%; }
    .table-stack .table-empty { text-align: center; }
    .table-stack tfoot tr { background: #f7f9fc; }
}

/* -----------------------------------------------------------------------------
   TABLETTE ET TELEPHONE - le tiroir
   -------------------------------------------------------------------------- */
@media (max-width: 1024px) {
    .sidebar {
        position: fixed;
        top: 0; bottom: 0; left: 0;
        z-index: 60;
        width: 270px;
        max-width: 85vw;
        overflow-y: auto;
        transform: translateX(-100%);
        transition: transform .18s ease;
        box-shadow: 0 0 24px rgba(16, 24, 40, .28);
    }
    /* Le repli du bureau ne s'applique plus : sur ces largeurs, le tiroir est
       ferme PAR DEFAUT, et `menu-ouvert` est la seule chose qui l'ouvre. Sans
       cette regle, un `menu-replie` restaure depuis localStorage laisserait le
       tiroir invisible mais toujours declare `display:none`. */
    body.menu-replie .sidebar { display: flex; }
    body.menu-ouvert .sidebar { transform: none; }

    /* Le voile : il ferme le tiroir au toucher, et il dit surtout que le
       contenu derriere n'est pas actif. Sans lui, on tape sur un bouton du
       fond en croyant fermer le menu. */
    body.menu-ouvert::after {
        content: "";
        position: fixed;
        inset: 0;
        z-index: 55;
        background: rgba(16, 24, 40, .45);
    }

    .content { padding: 16px; }
    .topbar { padding: 12px 16px; }
    .grid-4 { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}

/* -----------------------------------------------------------------------------
   TELEPHONE
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
    /* LA BARRE DU HAUT PASSE SUR DEUX LIGNES. Le titre et les boutons se
       partageaient une ligne : a trois boutons, le titre tombait a deux
       caracteres. */
    .topbar {
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
    }
    .topbar h1 { font-size: 18px; }
    .topbar-actions { flex-wrap: wrap; }

    /* LES BOUTONS D'ACTION S'ETALENT. Un bouton de 90 px au milieu d'une
       ligne vide se vise mal ; sur un telephone on tape large. */
    .topbar-actions .btn,
    .form-actions .btn,
    .form-actions button { flex: 1 1 auto; min-height: 42px; }
    .form-actions { flex-wrap: wrap; }

    .content { padding: 12px; }
    .card { padding: 14px; margin-bottom: 12px; }

    /* LES FILTRES EN COLONNE, ET EN PLEINE LARGEUR. Poses cote a cote sur
       360 px, ils se coupaient au milieu d'un menu deroulant. */
    .filters { flex-direction: column; align-items: stretch; }
    .filters .field,
    .filters .form-control,
    .filters .form-select { width: 100%; min-width: 0; }

    /* 16 px EXACTEMENT SUR LES CHAMPS, ET C'EST UNE REGLE DE SAFARI : en
       dessous, iOS ZOOME sur le champ au moment ou on le touche, et la page
       reste zoomee ensuite. C'est le defaut mobile le plus courant, et le
       plus penible. */
    .form-control, .form-select, input, select, textarea { font-size: 16px; }

    /* Les cibles tactiles : 44 px est le minimum recommande, et c'est aussi
       la largeur d'un pouce. */
    .btn { min-height: 42px; }
    .btn-sm { min-height: 34px; }
    .nav a { padding: 12px; }

    h1 { font-size: 19px; }
    h2 { font-size: 16px; }

    .grid-2, .grid-4 { grid-template-columns: 1fr; }

    /* Les statistiques se lisent sur deux colonnes plutot qu'une : quatre
       chiffres empiles font quatre ecrans de defilement. */
    .grid-4 { grid-template-columns: repeat(2, 1fr); }
    .stat { padding: 12px; }
    .stat-value { font-size: 21px; }

    .card-title { flex-wrap: wrap; gap: 8px; }
    .subnav { margin-bottom: 14px; }
    .pagination { flex-wrap: wrap; }
}

/* -----------------------------------------------------------------------------
   CE QUI NE DOIT JAMAIS DEBORDER
   --------------------------------------------------------------------------
   Une page qui defile horizontalement sur telephone est cassee : on perd la
   colonne de gauche des qu'on regarde la droite. Tout ce qui ne peut pas se
   redimensionner defile donc DANS SON PROPRE CADRE.
   -------------------------------------------------------------------------- */
.table-wrapper { overflow-x: auto; -webkit-overflow-scrolling: touch; }
img, video, canvas { max-width: 100%; height: auto; }
pre, code { overflow-wrap: anywhere; }
.main { overflow-x: hidden; }

/* =============================================================================
   MODULE INVENTAIRE
   ========================================================================== */

/* -----------------------------------------------------------------------------
   SOUS-NAVIGATION
   -------------------------------------------------------------------------- */
.subnav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
    margin-bottom: 20px;
    padding-bottom: 2px;
    border-bottom: 1px solid var(--bordure);
    overflow-x: auto;
}
.subnav a {
    padding: 8px 13px;
    font-size: 13.5px;
    color: var(--texte-doux);
    border-bottom: 2px solid transparent;
    white-space: nowrap;
}
.subnav a:hover { color: var(--texte); text-decoration: none; }
.subnav a.active { color: var(--bleu); border-bottom-color: var(--bleu); font-weight: 600; }
.subnav-sep { flex: 1; min-width: 12px; }

/* -----------------------------------------------------------------------------
   BADGES SPECIFIQUES
   -------------------------------------------------------------------------- */
/* Types de catalogue */
.badge-kind-PRODUCT { background: #e6effa; color: #1f5f8b; }
.badge-kind-MACHINE { background: #ede7f6; color: #4a2f83; }
.badge-kind-TOOL    { background: #e7f2ec; color: #256b45; }

/* Statuts de document */
.badge-doc-DRAFT     { background: #eef1f5; color: #5b6b7c; }
.badge-doc-VALIDATED { background: #e3f4ea; color: #1f6b41; }
.badge-doc-CLOSED    { background: #e6effa; color: #1f5f8b; }

/* Localisation des unites */
.badge-eq-IN_STOCK     { background: #e3f4ea; color: #1f6b41; }
.badge-eq-AT_CLIENT    { background: #e6effa; color: #1f5f8b; }
.badge-eq-IN_TRANSPORT { background: #fdf0dd; color: #8a5200; }
.badge-eq-INTERNAL_USE { background: #ede7f6; color: #4a2f83; }
.badge-eq-RETIRED      { background: #eef1f5; color: #5b6b7c; }

/* Cartes de statistiques en alerte */
.stat-warn   { border-color: #f0d9ab; }
.stat-danger { border-color: #f3c7c3; }
.stat-warn::before, .stat-danger::before, .stat-ok::before {
    content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
}
.stat-warn::before   { background: var(--orange); }
.stat-danger::before { background: var(--rouge); }
.stat-warn .stat-value   { color: #8a5200; }
.stat-danger .stat-value { color: var(--rouge); }
.stat-warn .stat-icone   { background: var(--orange-pale); color: var(--orange); }
.stat-danger .stat-icone { background: var(--rouge-pale); color: var(--rouge); }
.stat-ok .stat-icone     { background: var(--vert-pale); color: var(--vert); }

/* -----------------------------------------------------------------------------
   BARRE DE SCAN
   -------------------------------------------------------------------------- */
/* LE SCAN PREND TOUTE LA LARGEUR, la recherche manuelle passe dessous, dans
   un repli. C'etaient deux colonnes de meme poids : un partage faux, puisque
   le scan sert dans la quasi-totalite des cas et la recherche seulement quand
   l'etiquette est abimee ou qu'il n'y a pas de camera. */
.scanbar {
    padding: 16px;
    background: #f7f9fc;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
}
.scanbar label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--texte-doux);
    margin-bottom: 6px;
}
.scanbar-row { display: flex; gap: 8px; }
.scanbar-row .form-control { flex: 1; min-width: 0; }
.scanbar-scan .form-control {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: .04em;
}
.scanbar-scan .scanbar-row { margin-top: 10px; }
.scanbar-manuel { margin-top: 12px; }

/* -----------------------------------------------------------------------------
   LE BLOC REPLIE
   --------------------------------------------------------------------------
   `<details>` habille. On s'en sert partout ou une aide occasionnelle
   poussait vers le bas ce qu'on relit sans arret : la recherche manuelle
   d'un bon, la liste du materiel d'un service.

   Il fonctionne SANS JAVASCRIPT, et le navigateur sait deja le rendre
   accessible au clavier. C'est la raison de ce choix plutot qu'un onglet.
   -------------------------------------------------------------------------- */
.bloc-replie {
    margin-top: 14px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: var(--blanc);
}
.bloc-replie > summary {
    padding: 10px 14px;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--texte-doux);
    cursor: pointer;
    list-style: none;
}
.bloc-replie > summary::-webkit-details-marker { display: none; }
.bloc-replie > summary::before {
    content: "▸ ";
    color: var(--bleu);
}
.bloc-replie[open] > summary::before { content: "▾ "; }
.bloc-replie > summary:hover { color: var(--texte); }
.bloc-replie > summary:focus-visible { outline: 2px solid var(--bleu); outline-offset: -2px; }
.bloc-replie > *:not(summary) { padding: 0 14px 14px; }

/* -----------------------------------------------------------------------------
   L'EN-TETE D'UN BON - quatre valeurs sur une ligne
   --------------------------------------------------------------------------
   C'etaient quatre cartes occupant un quart d'ecran chacune, en haut de la
   page qu'on ouvre pour SAISIR. Quatre valeurs courtes tiennent sur une
   ligne, et une ligne se lit d'un coup d'oeil mieux que quatre cartes.
   -------------------------------------------------------------------------- */
.doc-entete {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 28px;
    margin: 0;
}
.doc-entete div { min-width: 0; }
.doc-entete dt {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--texte-doux);
}
.doc-entete dd { margin: 2px 0 0; font-weight: 600; }

/* -----------------------------------------------------------------------------
   QR CODES
   -------------------------------------------------------------------------- */
.qr-cell { white-space: nowrap; }
.qr-cell img { vertical-align: middle; margin-right: 8px; border: 1px solid var(--bordure); border-radius: 4px; background: #fff; }

.qr-inline { display: flex; gap: 16px; align-items: flex-start; margin-bottom: 16px; }
.qr-inline img { border: 1px solid var(--bordure); border-radius: 6px; background: #fff; padding: 4px; }

.qr-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 14px; }
.qr-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 12px;
    text-align: center;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: #fff;
}
.qr-card code { font-size: 11px; }

/* -----------------------------------------------------------------------------
   FORMATS ET CHECKLISTS
   -------------------------------------------------------------------------- */
.formats-block { margin: 20px 0; padding: 16px; background: #f7f9fc; border-radius: var(--radius); }
.format-table td { padding: 4px 6px; }
.format-table .form-control { padding: 6px 8px; font-size: 13.5px; }

.checklist td { vertical-align: top; }
.radio-inline { display: inline-block; margin-right: 12px; font-size: 13.5px; }
.radio-inline input { margin-right: 4px; }

/* -----------------------------------------------------------------------------
   ACTIONS RAPIDES
   -------------------------------------------------------------------------- */
.quick-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
.quick-action {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 14px 16px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: #fff;
    color: var(--texte);
}
.quick-action:hover { border-color: var(--bleu); background: #f7f9fc; text-decoration: none; }

/* -----------------------------------------------------------------------------
   DETAILS / SUMMARY UTILISES COMME BOUTONS
   -------------------------------------------------------------------------- */
details > summary { list-style: none; display: inline-block; }
details > summary::-webkit-details-marker { display: none; }
details > summary { cursor: pointer; }

/* -----------------------------------------------------------------------------
   PAGE PUBLIQUE (telephone)
   -------------------------------------------------------------------------- */
.layout-public { background: var(--fond); }
.public-wrapper { max-width: 620px; margin: 0 auto; padding: 18px 14px 40px; }
.public-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    margin-bottom: 16px;
    background: var(--bleu-fonce);
    border-radius: var(--radius);
    color: #fff;
}
.public-header .muted { color: #a8bccd; }
.public-actions { display: grid; gap: 10px; margin-bottom: 16px; }
.public-footer { margin-top: 26px; text-align: center; font-size: 12px; color: var(--texte-doux); }

.check-card { padding: 14px 16px; }
.check-choices { display: flex; gap: 16px; margin: 10px 0; }
.check-choices label { display: flex; align-items: center; gap: 6px; font-size: 15px; }
.check-choices input { width: 20px; height: 20px; }

/* -----------------------------------------------------------------------------
   IMPRESSION DES ETIQUETTES
   -------------------------------------------------------------------------- */
.print-page { padding: 20px; }
.print-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 18px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--bordure);
}
.labels-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; }
.label-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    padding: 10px;
    text-align: center;
    border: 1px dashed #999;
    border-radius: 4px;
    background: #fff;
    page-break-inside: avoid;
}
/* LE NOM SOUS LE QR, EN GROS. C'est ce qu'on lit de loin en cherchant une
   etagere ; le QR, lui, ne se lit qu'a dix centimetres avec un telephone. Il
   passe donc devant tout le reste, et il ne se coupe pas - un « Detergent
   surodorant PIN… » tronque ne designe rien. */
.label-nom {
    font-size: 13px;
    line-height: 1.25;
    overflow-wrap: anywhere;
}
.label-card code { font-size: 10px; }
.label-sub { font-size: 12px; color: var(--texte-doux); }
.label-hint { font-size: 9px; color: #999; }

.print-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

@media print {
    .no-print { display: none !important; }
    body { background: #fff; }
    .print-page { padding: 0; }
    .labels-grid { grid-template-columns: repeat(4, 1fr); }
    /* Le gris clair de l'ecran devient illisible a l'impression : sur du
       papier, tout ce qu'on garde doit etre noir. */
    .label-sub, .label-card code { color: #000; }
    .label-hint { display: none; }
}

/* -----------------------------------------------------------------------------
   SCANNER CAMERA
   -------------------------------------------------------------------------- */
.btn-scan {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 15px;
    padding: 11px 18px;
}
.scan-icon { font-size: 18px; line-height: 1; }

.scanner-unsupported {
    margin: 6px 0 0;
    padding: 8px 10px;
    background: #fdf3e3;
    border: 1px solid #eed4a7;
    border-radius: 6px;
    color: #8a5200;
}

/* Plein ecran : sur un telephone, viser une etiquette demande de la place. */
.scanner-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: grid;
    place-items: center;
    padding: 16px;
    background: rgba(12, 20, 28, .82);
}
/* INDISPENSABLE : `display: grid` ci-dessus est plus specifique que le
   `display: none` que le navigateur applique a [hidden]. Sans cette regle, la
   modale reste affichee en permanence et, etant en position fixed sur tout
   l'ecran, intercepte TOUS les clics de la page. */
.scanner-modal[hidden] { display: none; }
.scanner-unsupported[hidden] { display: none; }
.scanner-box {
    width: 100%;
    max-width: 480px;
    background: var(--blanc);
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 10px 40px rgba(0, 0, 0, .3);
}
.scanner-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border-bottom: 1px solid var(--bordure);
}

.scanner-video-wrap { position: relative; background: #000; aspect-ratio: 4 / 3; }
.scanner-video-wrap video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Viseur : aide a cadrer l'etiquette. */
.scanner-reticle {
    position: absolute;
    top: 50%; left: 50%;
    width: 62%; aspect-ratio: 1;
    transform: translate(-50%, -50%);
    border: 3px solid rgba(255, 255, 255, .9);
    border-radius: 14px;
    box-shadow: 0 0 0 100vmax rgba(0, 0, 0, .35);
}

.scanner-status { margin: 0; padding: 12px 14px; text-align: center; }

/* -----------------------------------------------------------------------------
   FICHE TECHNIQUE (fichier joint)
   -------------------------------------------------------------------------- */
.file-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 13px;
    border: 1px solid var(--bordure);
    border-radius: 6px;
    background: #f7f9fc;
    color: var(--texte);
    font-size: 14px;
}
.file-link:hover { border-color: var(--bleu); text-decoration: none; }
.file-icon { font-size: 17px; }

.file-preview {
    max-width: 100%;
    margin-top: 10px;
    border: 1px solid var(--bordure);
    border-radius: 6px;
}

input[type="file"].form-control { padding: 7px 9px; background: #fff; }

/* --------------------------------------------------------------------------
   PHOTO D'UN ELEMENT DE CATALOGUE
   Deux tailles : la vignette des listes et des resultats de recherche, et la
   photo de la fiche. Le format est toujours carre et l'image recadree
   (object-fit: cover) pour que les listes restent alignees quelle que soit la
   photo envoyee par l'utilisateur.
   -------------------------------------------------------------------------- */
.item-thumb {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    object-fit: cover;
    border: 1px solid var(--bordure);
    border-radius: 6px;
    background: #f7f9fc;
}
.item-thumb-empty { font-size: 18px; opacity: .45; }

.item-photo {
    display: block;
    max-width: 240px;
    max-height: 240px;
    margin-bottom: 12px;
    object-fit: cover;
    border: 1px solid var(--bordure);
    border-radius: 8px;
    background: #f7f9fc;
}

/* ==========================================================================
   GLISSER-DEPOSER - commun au calendrier et au tableau des feedbacks
   (voir static/js/dragdrop.js)
   ========================================================================== */
.is-dragging { opacity: .35; }
.is-saving   { opacity: .6; }

.drag-ghost {
    position: fixed;
    z-index: 1000;
    pointer-events: none;
    box-shadow: 0 8px 20px rgba(16, 24, 40, .22);
    transform: rotate(-1deg);
    opacity: .95;
}
/* `touch-action: none` PENDANT LE GLISSER, ET SEULEMENT PENDANT.
 *
 * Renfort de l'annulation du `touchmove` faite dans dragdrop.js : elle traite
 * le doigt deja pose, celle-ci traite un SECOND doigt qui viendrait se poser
 * pendant qu'on deplace un bloc - sur une tablette tenue a deux mains, ca
 * arrive.
 *
 * Elle ne vaut que le temps du glisser : posee en permanence sur les blocs,
 * elle confisquerait le defilement de la grille horaire, qu'on parcourt au
 * doigt pour atteindre la fin de journee. */
body.is-dragging-item { cursor: grabbing; user-select: none; touch-action: none; }

/* ==========================================================================
   LE MENU DU CLIC DROIT, ET LA COPIE EN L'AIR
   (voir static/js/calendarmenu.js)
   ==========================================================================

   C'est ainsi qu'une prestation tient sur plusieurs jours : clic droit sur
   une intervention, « Dupliquer », et la copie suit le curseur jusqu'au jour
   voulu. Les jours n'ont pas besoin d'etre consecutifs. */
.cal-menu {
    position: fixed;
    z-index: 1100;
    min-width: 180px;
    padding: 4px;
    background: #fff;
    border: 1px solid var(--border, #e3e6ec);
    border-radius: 8px;
    box-shadow: 0 10px 28px rgba(16, 24, 40, .18);
    display: flex;
    flex-direction: column;
}

.cal-menu-item {
    display: block;
    width: 100%;
    padding: 8px 12px;
    border: 0;
    border-radius: 6px;
    background: none;
    font: inherit;
    color: inherit;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.cal-menu-item:hover,
.cal-menu-item:focus { background: var(--surface-2, #f3f5f9); }

/* La copie se distingue du bloc d'origine : sans cela, on ne sait plus lequel
   des deux on tient. */
.drag-ghost.is-duplicate {
    transform: rotate(1deg) scale(.96);
    outline: 2px dashed var(--accent, #2f6feb);
    outline-offset: 2px;
}

/* Pendant le placement, le curseur dit qu'on tient quelque chose - et la
   selection de texte ne doit pas s'armer sous lui. */
body.is-duplicating { cursor: copy; user-select: none; }

/* -----------------------------------------------------------------------------
   CE QUI SE DEPLACE NE SE SELECTIONNE PAS
   --------------------------------------------------------------------------

   LE DEFAUT QUE CECI CORRIGE, sur tablette : on pose le doigt sur une
   intervention pour la deplacer, et le navigateur ouvre SON menu d'appui long
   - selection de texte sur Android, bulle « Copier / Rechercher » sur iOS. Il
   reprend alors le pointeur, notre glisser meurt, et il faut s'y reprendre a
   trois fois.

   POURQUOI LA REGLE DU DESSUS NE SUFFISAIT PAS. `body.is-dragging-item` ne
   s'applique QU'UNE FOIS LE GLISSER COMMENCE, c'est-a-dire apres 250 ms. Or
   le navigateur arme sa selection des le `pointerdown` - a 0 ms. La regle
   arrivait toujours trop tard, et ne pouvait pas defaire ce qui etait deja
   arme.

   Elle vit donc SUR LES ELEMENTS EUX-MEMES, en permanence.

   LES SELECTEURS SONT CEUX QUE LE JAVASCRIPT UTILISE COMME POIGNEES
   (`options.handle` dans dragdrop.js) : `[data-place]` pour les cartes a
   placer, `[data-move]` pour les blocs du calendrier, `[data-status-url]`
   pour les tableaux taches et signalements. Les lier ainsi evite qu'un
   nouvel ecran deplacable naisse sans sa regle - c'est le meme nom des deux
   cotes.

   `-webkit-touch-callout` N'EST PAS UN DOUBLON de `user-select` : le premier
   supprime la bulle d'iOS, le second la poignee de selection d'Android. Les
   deux navigateurs n'ecoutent pas la meme propriete.

   ON NE PERD RIEN : il n'y a rien a selectionner dans un bloc de planning ou
   une carte de tableau. Le texte reste copiable sur la FICHE, ou il est
   affiche pour etre lu. */
[data-place],
[data-move],
[data-status-url] {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

.is-drop-target {
    outline: 2px dashed var(--bleu);
    outline-offset: -2px;
    background: #f2f7fe !important;
}

/* ==========================================================================
   CALENDRIER DU PLANNING

   Trois mises en page pour un seul composant de creneau (.cal-slot) :
     .cal-month  une grille de sept colonnes, comme un calendrier mural
     .cal-grid   une grille horaire, comme un agenda : la hauteur d'un bloc
                 EST sa duree
     .cal-list   une liste par jour, pour les periodes libres

   Les prestations se deplacent au glisser (voir static/js/calendar.js).
   ========================================================================== */

/* -- Barre d'outils ------------------------------------------------------- */
.cal-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}
.cal-views {
    display: inline-flex;
    border: 1px solid var(--bordure);
    border-radius: 8px;
    overflow: hidden;
    background: var(--blanc);
}
.cal-view {
    padding: 8px 14px;
    font-size: 13px;
    color: var(--texte-doux);
    border-right: 1px solid var(--bordure);
}
.cal-view:last-child { border-right: 0; }
.cal-view:hover { background: #f5f8fd; text-decoration: none; color: var(--texte); }
.cal-view.is-active { background: var(--bleu); color: #fff; font-weight: 600; }

.cal-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.cal-filters .form-control, .cal-filters .form-select { width: auto; min-width: 130px; }
.cal-check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }
/* « Comparer » s'affiche a cote de « à pourvoir seulement », mais vient
   apres « Afficher » dans le HTML : c'est « Afficher » que declenche Entree. */
.cal-filters .cal-comparer { order: 1; }
.cal-filters .cal-afficher { order: 2; }
.cal-summary { margin: 0 0 12px; }

/* -- Le creneau, commun aux trois mises en page --------------------------- */
.cal-slot {
    display: block;
    padding: 5px 8px;
    border-radius: 5px;
    border-left: 3px solid var(--bleu);
    background: #eef4fc;
    color: var(--texte);
    font-size: 12px;
    line-height: 1.35;
    overflow: hidden;
    touch-action: manipulation;
}
.cal-slot:hover { text-decoration: none; filter: brightness(.97); }
.cal-slot span { display: block; }
.cal-slot-time  { font-weight: 700; }
.cal-slot-title { font-weight: 600; }
.cal-slot-sub, .cal-slot-team { color: var(--texte-doux); }
.cal-slot-team  { font-style: italic; }
.cal-slot-flag {
    margin-top: 3px;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--orange);
}

/* LES CINQ ETATS.
   Le lisere donne l'etat d'un coup d'oeil ; le libelle ecrit sur le creneau
   le donne a ceux pour qui la couleur ne suffit pas. Les deux, jamais l'un
   sans l'autre. L'ordre suit le cycle de vie : orange -> bleu -> violet ->
   vert, du « rien n'est fait » au « c'est prouve ». */
.cal-slot.status-PLANNED    { border-left-color: #d99b1c; background: #fff8ec; }
.cal-slot.status-ASSIGNED   { border-left-color: var(--bleu); background: #eef4fc; }
.cal-slot.status-INPROGRESS { border-left-color: #7a4fbf; background: #f4effc; }
.cal-slot.status-DONE       { border-left-color: #2f9e5f; background: #f1faf5; }
.cal-slot.status-CANCELLED  { border-left-color: #b3b8bf; background: #f5f6f7; opacity: .65; }
.cal-slot.is-short          { box-shadow: inset 0 0 0 1px #eec98a; }

/* L'etat sur SA propre ligne : en flottant a droite de l'heure il la
   percutait des que la colonne se resserrait (« 08:00 -> 10:00PLANIFIEE »). */
.cal-slot-state {
    display: block;
    font-style: normal;
    font-weight: 600;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .03em;
    opacity: .7;
}

/* -- La legende ------------------------------------------------------------
   Obligatoire : jusqu'ici les couleurs existaient mais rien ne les
   expliquait, ce qui revenait a ne pas les avoir. */
.cal-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    align-items: center;
    margin: 0 0 12px;
    font-size: 12px;
    color: var(--texte-doux);
}
.cal-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.cal-legend-chip {
    width: 12px; height: 12px;
    border-radius: 3px;
    border-left: 3px solid;
    flex-shrink: 0;
}
.cal-legend-chip.status-PLANNED    { border-left-color: #d99b1c; background: #fff8ec; }
.cal-legend-chip.status-ASSIGNED   { border-left-color: var(--bleu); background: #eef4fc; }
.cal-legend-chip.status-INPROGRESS { border-left-color: #7a4fbf; background: #f4effc; }
.cal-legend-chip.status-DONE       { border-left-color: #2f9e5f; background: #f1faf5; }
.cal-legend-chip.status-CANCELLED  { border-left-color: #b3b8bf; background: #f5f6f7; }
.cal-legend-item strong { color: var(--texte); font-weight: 600; }

.cal-slot[data-move] { cursor: grab; }

/* -- Vue MOIS ------------------------------------------------------------- */
.cal-month {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    overflow: hidden;
}
.cal-month-head, .cal-month-week { display: grid; grid-template-columns: repeat(7, 1fr); }
.cal-month-head > div {
    padding: 8px;
    text-align: center;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--texte-doux);
    background: #f7f9fc;
    border-bottom: 1px solid var(--bordure);
}
.cal-month-day {
    min-height: 118px;
    padding: 6px;
    border-right: 1px solid var(--bordure);
    border-bottom: 1px solid var(--bordure);
}
.cal-month-day:nth-child(7n) { border-right: 0; }
.cal-month-week:last-child .cal-month-day { border-bottom: 0; }
.cal-month-day.is-weekend { background: #fbfcfd; }
.cal-month-day.is-outside { background: #f6f7f9; }
.cal-month-day.is-outside .cal-month-daynum a { color: #a9b2bc; }
.cal-month-day.is-today { background: #f2f7fe; box-shadow: inset 0 0 0 2px var(--bleu); }

.cal-month-daynum {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 5px;
    font-size: 13px;
    font-weight: 600;
}
.cal-month-daynum a { color: var(--texte); }
.cal-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--orange); }

.cal-month-slots { display: flex; flex-direction: column; gap: 3px; min-height: 24px; }
.cal-month-slots .cal-slot-sub,
.cal-month-slots .cal-slot-state,
.cal-month-slots .cal-slot-team { display: none; }

/* -- Vues SEMAINE et JOURNEE : la grille horaire -------------------------- */
.cal-grid {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    overflow: auto;
    /* La grille defile DANS son cadre plutot que d'etirer la page : l'en-tete
       des jours reste visible, et la barre d'outils ne part pas en haut de
       l'ecran des qu'une journee est chargee. */
    max-height: calc(100vh - 250px);
    min-height: 340px;
}
.cal-grid-head, .cal-grid-body {
    display: grid;
    grid-template-columns: 58px repeat(auto-fit, minmax(0, 1fr));
    min-width: 640px;
}
.cal-grid-head {
    position: sticky;
    top: 0;
    z-index: 3;
    background: #f7f9fc;
    border-bottom: 1px solid var(--bordure);
}
.cal-grid-daylabel { padding: 8px 6px; text-align: center; font-size: 12px; }
.cal-grid-daylabel a { color: var(--texte); }
.cal-grid-daylabel strong { display: block; text-transform: capitalize; }
.cal-grid-daylabel span { color: var(--texte-doux); }
.cal-grid-daylabel.is-today { background: #e9f1fd; box-shadow: inset 0 -2px 0 var(--bleu); }

.cal-grid-body { position: relative; }
.cal-grid-gutter { position: relative; border-right: 1px solid var(--bordure); }
.cal-grid-hour {
    position: absolute;
    right: 6px;
    transform: translateY(-50%);
    font-size: 11px;
    color: var(--texte-doux);
}
/* La premiere heure est a top:0 : centree, elle serait coupee en deux. */
.cal-grid-hour:first-child { transform: none; }
.cal-grid-col {
    position: relative;
    border-right: 1px solid var(--bordure);
}
.cal-grid-col:last-child { border-right: 0; }
.cal-grid-col.is-weekend { background: #fbfcfd; }
.cal-grid-col.is-today { background: #f7fbff; }
.cal-grid-line {
    position: absolute;
    left: 0; right: 0;
    border-top: 1px solid #eef1f5;
}

/* Dans la grille horaire, le bloc est positionne : sa hauteur EST sa duree. */
.cal-grid-col .cal-slot {
    position: absolute;
    z-index: 2;
    /* `left` et `width` viennent du style en ligne : ce sont les couloirs
       calcules par `_assign_lanes`, pour que deux prestations simultanees se
       partagent la colonne au lieu de se recouvrir. La bordure interieure
       tient lieu de gouttiere.

       TROIS COTES, JAMAIS LE QUATRIEME - et c'est tout le sujet.

       Cette regle disait `border: 2px solid transparent`. Le raccourci
       `border` ecrit les QUATRE cotes, donc `border-left-color` aussi : il
       effacait la couleur d'etat posee vingt lignes plus haut par
       `.cal-slot.status-*`. A specificite egale (deux classes de chaque
       cote), c'est la regle la plus BASSE dans le fichier qui gagne - celle-ci.

       Consequence : dans la vue jour et la vue semaine - c'est-a-dire dans le
       planning qu'on regarde tous les jours - tous les creneaux avaient le
       meme lisere invisible. La legende annoncait cinq couleurs, l'ecran n'en
       montrait aucune. Les vues mois et periode, elles, etaient correctes :
       elles n'ont pas de `.cal-grid-col`, ce qui rendait le defaut
       incomprehensible.

       On declare donc les trois cotes separement. Le bord gauche garde ses
       3 px de couleur, qui font aussi tres bien office de gouttiere. */
    border-top: 2px solid transparent;
    border-right: 2px solid transparent;
    border-bottom: 2px solid transparent;
    background-clip: padding-box;
}
.cal-grid-col .cal-slot-sub { display: none; }

/* -- Periode libre : une liste par jour ----------------------------------- */
.cal-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 12px;
}
.cal-list-day {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    padding: 12px;
    min-height: 110px;
}
.cal-list-day.is-today { border-color: var(--bleu); box-shadow: inset 0 0 0 1px var(--bleu); }
.cal-list-day.is-weekend { background: #fafbfc; }
.cal-list-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding-bottom: 8px;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--bordure);
    font-size: 13px;
}
.cal-list-slots { display: flex; flex-direction: column; gap: 6px; min-height: 24px; }
.cal-empty { color: var(--texte-doux); font-size: 13px; margin: 0; }

.conflict { color: #8a5200; }

/* Apercu des dates produites par une frequence. */
.date-chips { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.date-chips li {
    padding: 4px 9px;
    border: 1px solid var(--bordure);
    border-radius: 999px;
    background: #f7f9fc;
    font-size: 12.5px;
}

@media (max-width: 720px) {
    /* Sur telephone, le mois devient une pile de journees : sept colonnes de
       120 px de large ne sont lisibles nulle part. */
    .cal-month-head { display: none; }
    .cal-month-week { grid-template-columns: 1fr; }
    .cal-month-day { min-height: 0; border-right: 0; }
    .cal-month-day.is-outside { display: none; }
    .cal-month-slots .cal-slot-sub { display: block; }

    /* Une journee vide se reduit a sa date : sur un mois complet, cela evite
       un millier de pixels de defilement pour rien. Elle reste une cible de
       depot - on doit pouvoir y glisser une prestation. */
    .cal-month-day:not(:has(.cal-slot)) { padding: 2px 6px; opacity: .55; }
    .cal-month-day:not(:has(.cal-slot)) .cal-month-slots { min-height: 0; }

    .cal-toolbar { flex-direction: column; align-items: stretch; }
    .cal-views { overflow-x: auto; }
    .cal-filters .form-control, .cal-filters .form-select { flex: 1 1 140px; }

    /* SUR TELEPHONE LE PANNEAU NE FLOTTE PLUS. Un panneau de 300 px pose en
       absolu sortirait de l'ecran par la droite, et la barre fait de toute
       facon toute la largeur : il se range simplement en dessous. */
    .cal-salaries { width: 100%; }
    .cal-salaries > summary { min-width: 0; }
    .cal-salaries-panneau {
        position: static;
        min-width: 0;
        max-width: none;
        margin-top: 6px;
        box-shadow: none;
    }
}

/* ==========================================================================
   BON D'INTERVENTION
   Mis en page pour etre lu par le client, et imprimable tel quel.
   ========================================================================== */
.voucher {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    padding: 24px;
}
.voucher-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding-bottom: 14px;
    margin-bottom: 18px;
    border-bottom: 2px solid var(--texte);
}
.voucher-head h2 { margin: 0; letter-spacing: .08em; }
.voucher h3 {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--texte-doux);
    margin: 18px 0 6px;
}
.voucher-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 4px 18px;
}
.voucher-grid h3 { margin-top: 10px; }
.voucher-grid p { margin: 0; }

.voucher-tasks { list-style: none; margin: 0; padding: 0; }
.voucher-tasks li { padding: 4px 0; border-bottom: 1px solid var(--bordure); }
.voucher-tasks li.done { color: var(--texte); }
.voucher-tasks li.undone { color: var(--texte-doux); }

.voucher-signatures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 24px;
    margin-top: 26px;
    padding-top: 18px;
    border-top: 1px solid var(--bordure);
}

.signature-pad {
    display: block;
    width: 100%;
    height: 160px;
    border: 1px dashed var(--bordure);
    border-radius: 6px;
    background: #fff;
    touch-action: none; /* sinon le doigt fait defiler la page au lieu de signer */
}
.signature-actions { margin: 8px 0; }
.signature-image {
    display: block;
    max-width: 100%;
    height: 120px;
    object-fit: contain;
    border-bottom: 1px solid var(--texte);
}

/* Photos d'intervention et documents illustres. */
.photo-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
}
.photo-item { margin: 0; }
.photo-item img {
    width: 100%;
    height: 110px;
    object-fit: cover;
    border: 1px solid var(--bordure);
    border-radius: 6px;
}
.photo-item figcaption { font-size: 12px; color: var(--texte-doux); margin-top: 4px; }

/* Statuts d'un feedback : la meme couleur que la colonne du tableau. */
.badge-status-RECEIVED    { background: #fdf0dd; color: #8a5200; }
.badge-status-IN_PROGRESS { background: #e6effa; color: #1f5f8b; }
.badge-status-DONE        { background: #e3f4ea; color: #1f6b41; }

/* Frise de l'historique : on ajoute, on n'efface jamais. */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li {
    display: grid;
    grid-template-columns: 118px 1fr;
    gap: 10px;
    padding: 9px 0;
    border-bottom: 1px solid var(--bordure);
    font-size: 13px;
}
.timeline li:last-child { border-bottom: 0; }
.timeline-when { color: var(--texte-doux); font-size: 12px; }

/* Statuts commerciaux d'un client. */
.badge-status-PROSPECT  { background: #eef2f7; color: #445; }
.badge-status-ACTIVE    { background: #e3f4ea; color: #1f6b41; }
.badge-status-SUSPENDED { background: #fdf0dd; color: #8a5200; }
.badge-status-ENDED     { background: #fae8e7; color: #8f201a; }

/* A l'impression, on ne garde que le bon. */
@media print {
    .sidebar, .menu-bascule, .topbar-actions, .subnav, .messages, .form-actions { display: none !important; }
    .voucher { border: 0; padding: 0; }
    .main, .content { padding: 0; }
}

/* ==========================================================================
   TABLEAU DES FEEDBACKS

   Trois colonnes, des cartes qu'on deplace au glisser. Le deplacement change
   le STATUT : ce n'est pas un rangement visuel.
   ========================================================================== */
.kanban {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    align-items: start;
}
.kanban-col {
    background: #f0f3f7;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    padding: 12px;
    min-height: 220px;
}
.kanban-col-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 10px;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--texte-doux);
}
/* Le liseré de tete dit d'un coup d'oeil ou l'on en est. */
.kanban-col[data-column="RECEIVED"]    { box-shadow: inset 0 3px 0 #d99b1c; }
.kanban-col[data-column="IN_PROGRESS"] { box-shadow: inset 0 3px 0 var(--bleu); }
.kanban-col[data-column="DONE"]        { box-shadow: inset 0 3px 0 #2f9e5f; }

.kanban-cards { display: flex; flex-direction: column; gap: 10px; min-height: 60px; }

.kanban-card {
    display: block;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: 6px;
    box-shadow: var(--ombre);
    padding: 11px 12px;
    color: var(--texte);
    font-size: 13px;
    cursor: grab;
    /* `pan-y` ET NON `none`, ET C'EST TOUT LE SUJET.
     *
     * Sans regle, le navigateur reclamait le geste des que le doigt bougeait :
     * il annulait le pointeur, et le glisser mourait avant d'avoir commence.
     * C'est pour ca qu'il ne marchait qu'a la souris.
     *
     * `none` l'aurait repare - en rendant la page impossible a faire defiler
     * des qu'un doigt se pose sur une carte, c'est-a-dire presque partout sur
     * ce tableau.
     *
     * `pan-y` partage : le defilement VERTICAL reste au navigateur, le
     * mouvement HORIZONTAL nous revient. Or d'une colonne a l'autre, on va
     * justement de cote. Sur telephone, ou les colonnes s'empilent, c'est le
     * bouton de deplacement qui prend le relais - voir `.kanban-deplacer`. */
    touch-action: pan-y;
}
/* Le lien porte le contenu ; la carte porte la boite et le glisser. Ils
 * etaient un seul element, mais un bouton ne peut pas vivre dans une ancre. */
.kanban-card-lien {
    display: block;
    color: inherit;
    font: inherit;
}
.kanban-card-lien:hover { text-decoration: none; }
.kanban-card:hover { border-color: var(--bleu); }

/* -- Deplacer sans glisser -------------------------------------------------
   Le seul chemin qui marche sur tous les appareils, et le seul qui marche au
   clavier. Discret - une ligne de mots sous la carte - parce qu'on ne s'en
   sert pas a chaque coup d'oeil, mais toujours la quand on en a besoin. */
.kanban-deplacer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 9px;
    padding-top: 8px;
    border-top: 1px dashed var(--bordure);
    font-size: 11px;
}
.kanban-vers {
    padding: 4px 9px;
    border: 1px solid var(--bordure);
    border-radius: 999px;
    background: var(--blanc);
    color: var(--bleu);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    /* Le doigt doit atteindre le bouton, pas la carte qui est dessous. */
    touch-action: manipulation;
}
.kanban-vers:hover { background: #eaf2fd; border-color: var(--bleu); }
.kanban-vers:active { background: #dce9fb; }

/* Sur un ecran tactile, la cible doit etre attrapable sans viser. */
@media (hover: none) {
    .kanban-vers { padding: 7px 12px; font-size: 12px; }
}
.kanban-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 5px;
}
.kanban-card-ref { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; color: var(--texte-doux); }
.kanban-card-title { display: block; font-weight: 600; margin-bottom: 3px; }
.kanban-card-meta { display: block; color: var(--texte-doux); font-size: 12px; }
.kanban-card-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 7px;
    font-size: 11px;
    color: var(--texte-doux);
}
.kanban-card.is-stale { border-left: 3px solid var(--orange); }
.kanban-card-photos { color: var(--texte-doux); }

.kanban-empty {
    padding: 18px 8px;
    text-align: center;
    color: var(--texte-doux);
    font-size: 12.5px;
    border: 1px dashed var(--bordure);
    border-radius: 6px;
}

@media (max-width: 860px) {
    /* Trois colonnes de 110 px ne se lisent pas : on empile. */
    .kanban { grid-template-columns: 1fr; }
}

/* ==========================================================================
   FORMULAIRE PUBLIC DE FEEDBACK

   Vu sur un telephone, debout, souvent d'une main. Grands champs, gros
   bouton, aucune colonne.
   ========================================================================== */
.public-form { max-width: 560px; margin: 0 auto; }
.public-form .field label { font-size: 14px; }
.public-form .form-control, .public-form .form-select { padding: 12px 13px; font-size: 16px; }
.public-form textarea.form-control { min-height: 130px; }

/* Le champ photo, habille.
   Le champ fichier natif affiche « Choose Files / No file chosen » : trois
   mots en anglais sur une page que lit le personnel du client, avec un bouton
   gris qui ne ressemble a rien du reste. On masque l'entree et on habille son
   label - le clic sur le label ouvre le selecteur, sans JavaScript. */
.public-file { display: block; cursor: pointer; }
/* Double classe : le widget porte aussi `.form-control`, qui lui donnerait
   sinon un padding et une taille de police - donc une zone cliquable
   fantome decalee sous le label. */
.public-form .public-file input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    opacity: 0;
}
.public-file span {
    display: block;
    padding: 13px;
    text-align: center;
    border: 1px dashed var(--bordure);
    border-radius: 8px;
    font-size: 15px;
    color: var(--texte-doux);
    background: var(--blanc);
}
.public-file:hover span,
.public-file input:focus-visible + span { border-color: var(--bleu); color: var(--bleu); }

/* Les vignettes de ce qu'on vient de choisir.
   Le champ etant masque, rien ne disait qu'une photo etait jointe : on
   photographiait la fuite, la page ne bougeait pas, et on recommencait. */
.public-thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}
.public-thumb {
    position: relative;
    width: 72px;
    height: 72px;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--bordure);
    background: var(--blanc);
}
.public-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* La croix de retrait.
   Les photos se cumulent : sans elle, une photo ratee ne se corrige qu'en
   rechargeant la page - et en perdant le texte deja ecrit. Dimensionnee pour
   le pouce (26 px), pas pour la souris. */
.public-thumb-del {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(20, 26, 33, .72);
    color: #fff;
    font-size: 17px;
    line-height: 26px;
    text-align: center;
    cursor: pointer;
}
.public-thumb-del:hover { background: var(--rouge); }

/* Le piege a robots : invisible a l'oeil, present pour un script. */
.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* L'affiche a coller sur le site. */
.poster {
    max-width: 620px;
    margin: 0 auto;
    padding: 32px;
    text-align: center;
    background: var(--blanc);
    border: 2px solid var(--texte);
    border-radius: var(--radius);
}
.poster h2 { font-size: 26px; margin-bottom: 6px; }
.poster-site { font-size: 17px; font-weight: 600; margin-bottom: 18px; }
.poster img { width: 260px; height: 260px; }
.poster-url {
    margin-top: 14px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    word-break: break-all;
    color: var(--texte-doux);
}

@media print {
    .sidebar, .menu-bascule, .topbar-actions, .subnav, .messages, .form-actions, .no-print { display: none !important; }
    .poster { border: 0; }
    .main, .content { padding: 0; }
}

/* -----------------------------------------------------------------------------
   CONTACTS D'UN CLIENT
   Chaque contact est un bloc : ses actions - ouvrir un acces, rattacher un
   compte existant, suspendre - ne tiennent pas dans une cellule de tableau.
   -------------------------------------------------------------------------- */
.contact-row {
    padding: 12px 0;
    border-bottom: 1px solid var(--bordure);
}
.contact-row:last-of-type { border-bottom: 0; }

.contact-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
}

.contact-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
}

.contact-grant { margin-top: 12px; }
.contact-grant .btn { margin-right: 8px; }

/* -----------------------------------------------------------------------------
   SE DEPLACER DANS LE TEMPS

   Deux fleches et « Aujourd'hui », AU CONTACT du calendrier. Elles etaient en
   haut a droite de la page, loin de la grille, et le seul moyen evident de
   changer de semaine restait le petit champ date - il fallait ouvrir un
   calendrier pour en parcourir un autre.

   Les listes de pastilles employe / client qui vivaient ici ont ete retirees :
   elles repetaient les menus deroulants et, avec vingt salaries, repoussaient
   le calendrier sous la ligne de flottaison.
   -------------------------------------------------------------------------- */
.cal-period {
    display: flex;
    align-items: center;
    gap: 4px;
}
.cal-arrow,
.cal-today {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 34px;
    border: 1px solid var(--bordure);
    border-radius: 6px;
    background: var(--blanc);
    color: var(--texte);
    font-size: 15px;
    line-height: 1;
    text-decoration: none;
}
/* Larges : on vise ces fleches vingt fois par jour, parfois au doigt. */
.cal-arrow { width: 40px; font-size: 18px; }
.cal-today { padding: 0 12px; font-size: 13px; }
.cal-arrow:hover,
.cal-today:hover {
    background: var(--bleu);
    border-color: var(--bleu);
    color: #fff;
    text-decoration: none;
}

.cal-active-filters { margin: 0 0 8px; }
.cal-active-filters a { margin-right: 10px; }

/* -----------------------------------------------------------------------------
   VUE PAR EMPLOYE
   Meme grille horaire, mais les colonnes sont des gens. Elle defile
   horizontalement : dix agents ne tiennent pas dans une largeur d'ecran, et
   les tasser les rendrait illisibles.
   -------------------------------------------------------------------------- */
.cal-team {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre);
    overflow: auto;
    max-height: 78vh;
}
.cal-team-head {
    display: flex;
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--blanc);
    border-bottom: 1px solid var(--bordure);
}
.cal-team-name {
    flex: 1 0 150px;
    min-width: 150px;
    padding: 8px 10px;
    text-align: center;
    border-left: 1px solid var(--bordure);
    font-size: 12px;
}
.cal-team-name strong { display: block; font-size: 13px; }
.cal-team-name span { display: block; color: var(--texte-doux); font-size: 11px; }
.cal-team-name.is-unassigned { background: #fff8ec; }

.cal-team-body { display: flex; position: relative; }
.cal-team-head .cal-grid-gutter,
.cal-team-body .cal-grid-gutter {
    flex: 0 0 58px;
    width: 58px;
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--blanc);
}
.cal-team-body .cal-grid-col {
    flex: 1 0 150px;
    min-width: 150px;
}
.cal-team-body .cal-grid-col.is-unassigned { background: #fffdf7; }
.cal-team-empty {
    position: absolute;
    top: 8px;
    left: 0; right: 0;
    text-align: center;
    font-size: 11px;
    color: #b6c0ca;
    margin: 0;
}

/* -----------------------------------------------------------------------------
   LE TABLEAU « A PLACER »
   A droite du calendrier sur grand ecran, en dessous sur telephone : un
   panneau lateral de 260px sur un mobile ecraserait le calendrier, qui est
   l'essentiel.
   -------------------------------------------------------------------------- */
.cal-with-backlog {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 268px;
    gap: 16px;
    align-items: start;
}
.cal-with-backlog-main { min-width: 0; }

@media (max-width: 1100px) {
    .cal-with-backlog { grid-template-columns: minmax(0, 1fr); }
}

.cal-backlog {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre);
    padding: 14px 16px;
    max-height: 78vh;
    overflow-y: auto;
}
.cal-backlog-head { display: flex; align-items: center; gap: 8px; }
.cal-backlog-head h2 { margin: 0; }
.cal-backlog-empty { font-size: 13px; color: var(--texte-doux); }
.cal-backlog-empty span { display: block; margin-top: 6px; }

.backlog-card {
    display: block;
    padding: 9px 11px;
    margin-top: 10px;
    border-radius: 6px;
    border-left: 3px solid #6b4fbf;
    background: #f5f2fc;
    font-size: 12px;
    line-height: 1.35;
}

/* AU DOIGT, `manipulation` CONFISQUAIT LE GESTE.
 *
 * La carte portait `touch-action: manipulation`, qui laisse au navigateur le
 * defilement dans LES DEUX sens : des que le doigt bougeait, il reclamait le
 * geste pour faire defiler la page et annulait le pointeur avant que le
 * deplacement n'existe. On appuyait, la fiche s'ouvrait comme sur un appui
 * long - exactement le defaut des tableaux taches et signalements.
 *
 * `pan-y` partage : le defilement VERTICAL reste au navigateur, le mouvement
 * HORIZONTAL nous revient. Or le tableau est A DROITE du calendrier : on tire
 * vers la gauche, donc de cote.
 *
 * SUR ECRAN ETROIT, LE TABLEAU PASSE SOUS LE CALENDRIER et le glisser devrait
 * alors remonter - verticalement, c'est-a-dire dans le sens qu'on vient de
 * rendre au navigateur. C'est pourquoi chaque carte porte aussi un
 * FORMULAIRE de secours (`.backlog-poser`) : une date, un bouton, aucun
 * glisser. Meme reponse que les boutons « Deplacer » des tableaux. */
.backlog-card[data-place] { cursor: grab; touch-action: pan-y; }
.backlog-card span { display: block; }
.backlog-card-title { font-weight: 700; }
.backlog-card-sub, .backlog-card-meta { color: var(--texte-doux); }
.backlog-card-quota { margin-top: 4px; }
.backlog-card-quota em { font-style: normal; color: var(--texte-doux); font-size: 11px; }

/* Engagement tenu : la carte reste visible - savoir que c'est fait vaut
   mieux que de la voir disparaitre sans explication - mais elle s'efface. */
.backlog-card.is-done {
    border-left-color: #2f9e5f;
    background: #f4f8f5;
    opacity: .6;
}
.backlog-card.is-saving { opacity: .5; }

/* -----------------------------------------------------------------------------
   LE CAHIER DES CHARGES - L'ATELIER EN FEUILLE
   On ecrit SUR le document, comme dans un tableur : chaque case est un champ
   sans cadre, le cadre bleu marque la case ou l'on ecrit, et la derniere
   ligne, en pointilles, sert a en ajouter une. Le formulaire de gauche et la
   page « Modifier » ont disparu.
   -------------------------------------------------------------------------- */
.cdcf { min-width: 880px; }
.cdcf-carte .table-wrapper { position: relative; }
.cdcf td { padding: 0; border: 1px solid #e9edf2; vertical-align: top; }
.cdcf td.cdc-num { padding: 9px 8px; }
.cdcf .cdcf-zone { width: 160px; }
.cdcf .cdcf-rythme { width: 240px; }
.cdcf .cdcf-jours { width: 186px; }
.cdcf .cdcf-commandes { width: 1%; white-space: nowrap; }
.cdcf td.cdcf-jours, .cdcf td.cdcf-commandes { padding: 7px 8px; }

.cdcf .cdcf-case {
    display: block;
    width: 100%;
    min-height: 36px;
    margin: 0;
    padding: 8px 10px;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    font: inherit;
    font-size: 13px;
    color: var(--texte);
}
.cdcf .cdcf-case:hover { background: #f6f8fb; }
.cdcf .cdcf-case:focus { outline: 2px solid var(--bleu); outline-offset: -2px; background: var(--blanc); }
.cdcf .cdcf-case::placeholder { color: #a9b3c1; }
.cdcf .cdcf-intitule { font-weight: 600; resize: none; overflow: hidden; line-height: 1.45; }
.cdcf .cdcf-precision {
    min-height: 0;
    padding-top: 0;
    resize: none;
    overflow: hidden;
    font-size: 12px;
    line-height: 1.45;
    color: var(--texte-doux);
}
/* La precision ne s'affiche que si elle est remplie, ou quand on travaille
   sur la ligne : trente « Précision (facultatif) » grises noyaient la feuille. */
.cdcf .cdcf-precision:placeholder-shown { display: none; }
.cdcf .cdcf-ligne:focus-within .cdcf-precision,
.cdcf .cdcf-nouvelle .cdcf-precision { display: block; }
.cdcf select.cdcf-case { cursor: pointer; font-size: 12.5px; padding-right: 2px; }

/* Les jours : de vraies cases a cocher, habillees comme la bande du document. */
.cdcf-bande { display: inline-flex; gap: 3px; }
.cdcf-bande[hidden], .cdcf-jours .jours-aucun[hidden] { display: none; }
.cdcf-jour { position: relative; display: inline-flex; cursor: pointer; }
.cdcf-jour input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.cdcf-jour input:checked + .jour { border-color: var(--bleu); background: var(--bleu); color: #fff; }
.cdcf-jour input:focus-visible + .jour { outline: 2px solid var(--bleu); outline-offset: 1px; }
.cdcf-jour:hover .jour { border-color: var(--bleu); }
/* « Comme la prestation » : les jours de la prestation, en gris - la ligne
   les suit, on ne les coche pas pour elle. */
.cdcf-bande.est-heritee { opacity: .45; }
.cdcf-bande.est-heritee .cdcf-jour { cursor: default; }
.cdcf-bande.est-heritee .cdcf-jour:hover .jour { border-color: var(--bordure); }
.cdcf-bande.est-heritee .cdcf-jour input:checked + .jour { border-color: var(--bleu); }

.cdcf-outils { display: inline-flex; gap: 4px; }
.cdcf-outils form { display: inline; margin: 0; }
.cdcf-commandes .feuille-outil { padding: 2px 9px; font-size: 13px; }

/* Ce que devient une ligne : en cours d'envoi, enregistree, refusee. */
.cdcf-ligne.est-en-cours .cdc-num { color: var(--bleu); }
.cdcf-ligne.est-enregistree .cdc-num { animation: cdcf-enregistree 1.4s ease-out; }
@keyframes cdcf-enregistree { from { background: #dff3e7; } to { background: transparent; } }
.cdcf-ligne.est-erreur td { background: #fdf0ef; }
.cdcf-erreur { display: block; padding: 0 10px 6px; font-size: 12px; color: var(--rouge); }
.cdcf-erreur:empty { display: none; }
.cdcf-ligne.est-ajoutee td { animation: cdcf-ajoutee 2.6s ease-out; }
@keyframes cdcf-ajoutee { from { background: #fff1cc; } to { background: transparent; } }

/* La ligne vide du bas. */
.cdcf-nouvelle td { background: #fafbfd; border-top: 2px dashed #cfd7e2; }
.cdcf-nouvelle .cdc-num { color: var(--bleu); font-weight: 700; }

.cdcf-etat { font-size: 12px; color: var(--texte-doux); }
.cdcf-etat.est-erreur { color: var(--rouge); font-weight: 600; }

/* -----------------------------------------------------------------------------
   LE DOCUMENT - mise en page d'imprimeur
   Il s'imprime tel quel : le navigateur sait l'enregistrer en PDF, ce qui
   evite une bibliotheque de rendu cote serveur.
   -------------------------------------------------------------------------- */
.cdc {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre);
    padding: 40px 44px;
    max-width: 900px;
    /* Un document se lit, il ne se parcourt pas : un peu plus d'air et une
       ligne un peu plus haute qu'ailleurs dans le logiciel. */
    line-height: 1.5;
}

/* -- En-tete ---------------------------------------------------------------- */
.cdc-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 24px;
    padding-bottom: 18px;
    border-bottom: 2px solid var(--bleu-fonce);
}
.cdc-kicker {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .12em;
    color: var(--texte-doux);
}
.cdc-head h1 {
    font-size: 26px;
    margin: 2px 0 0;
    line-height: 1.2;
}
.cdc-where { margin: 6px 0 0; font-size: 14px; color: var(--texte-doux); }
.cdc-issuer { text-align: right; font-size: 12px; white-space: nowrap; }
.cdc-issuer strong { display: block; font-size: 14px; }
.cdc-issuer span { color: var(--texte-doux); }

/* -- Le bandeau d'identite --------------------------------------------------
   Une <dl> en grille plutot qu'un tableau : quatre couples libelle/valeur ne
   sont pas un tableau de donnees, et la <dl> se replie proprement en une
   colonne sur un ecran etroit. */
.cdc-identity {
    display: grid;
    /* Deux colonnes au maximum : a trois, « Lundi, Mardi, Mercredi, Jeudi,
       Vendredi » se casse sur trois lignes et le bandeau devient un pave. */
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 2px 32px;
    margin: 22px 0 30px;
    padding: 16px 18px;
    background: #f7f9fb;
    border-radius: 6px;
    font-size: 13px;
}
.cdc-identity div { display: flex; gap: 10px; padding: 3px 0; }
.cdc-identity dt {
    min-width: 92px;
    color: var(--texte-doux);
    font-size: 12px;
}
.cdc-identity dd { margin: 0; font-weight: 600; }

/* -- Les prestations -------------------------------------------------------- */
.cdc-section { margin-top: 8px; }
.cdc-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    border-bottom: 1px solid var(--bordure);
    padding-bottom: 8px;
    margin-bottom: 14px;
}
.cdc-section-head h2 {
    margin: 0;
    font-size: 15px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--bleu-fonce);
}
.cdc-count { color: var(--texte-doux); font-size: 12px; }
.cdc-table { font-size: 13px; border-collapse: collapse; width: 100%; }
.cdc-table thead th {
    background: transparent;
    border-bottom: 1px solid var(--bordure);
    padding: 0 10px 6px;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--texte-doux);
    text-align: left;
}
.cdc-table td { padding: 9px 10px; border-bottom: 1px solid #eef1f5; vertical-align: top; }

/* Le bandeau de zone : une ligne de la table, pas un titre au-dessus. Les
   colonnes restent donc alignees d'un bout a l'autre du document. */
.cdc-zone th {
    text-align: left;
    padding: 16px 10px 6px;
    border-bottom: 2px solid var(--bleu);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--bleu-fonce);
}
.cdc-zone th span {
    float: right;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--texte-doux);
}
.cdc-table tbody tr:first-child .cdc-zone th,
.cdc-zone:first-child th { padding-top: 4px; }

.cdc-num { width: 38px; color: var(--texte-doux); text-align: right; }

/* Les deux colonnes qui remplacent « Frequence particuliere ».

   Le RYTHME et les JOURS sont separes parce qu'un tableau se lit
   verticalement : on compare une colonne, on ne relit pas trente phrases.
   Largeurs fixes pour que les bandes de jours s'alignent exactement d'une
   ligne a l'autre - c'est cet alignement qui permet de les comparer d'un
   coup d'oeil, et il disparait des que la colonne respire. */
.cdc-rythme { width: 150px; font-size: 12px; color: var(--texte-doux); white-space: nowrap; }
.cdc-jours { width: 172px; }
.cdc-commandes { width: 1%; white-space: nowrap; }

/* La ligne qui a SA PROPRE frequence. La seule chose que le tableau ne montre
   pas tout seul : deux lignes peuvent afficher le meme rythme, l'une parce
   qu'elle suit le service, l'autre parce qu'on l'a decide pour elle. */
.cdc-propre {
    display: inline-block;
    margin-left: 6px;
    padding: 0 5px;
    border-radius: 3px;
    background: #eaf1f7;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--bleu);
}

.cdc-label { display: block; font-weight: 600; }
.cdc-details {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--texte-doux);
}
.cdc-optional {
    display: inline-block;
    margin-left: 6px;
    padding: 0 6px;
    border-radius: 3px;
    background: #f1f3f7;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--texte-doux);
}
/* -- La bande des sept jours ------------------------------------------------
   Sept cases, dont les actives sont pleines. Une phrase - « Lundi, Mercredi,
   Vendredi » - se lit ligne par ligne ; une bande se COMPARE d'une ligne a
   l'autre sans rien lire. C'est le principe d'un calendrier mural, et c'est
   ce qui rend un cahier de trente lignes parcourable.

   Les deux « M » et les deux « S » se distinguent par leur POSITION, jamais
   par leur lettre. La phrase complete reste dans l'infobulle et dans
   l'`aria-label`. */
.jours { display: inline-flex; gap: 3px; }
.jour {
    display: grid;
    place-items: center;
    width: 21px; height: 21px;
    border: 1px solid var(--bordure);
    border-radius: 4px;
    background: var(--blanc);
    font-size: 11px;
    font-weight: 600;
    color: #c4ccd8;
}
.jour.is-on {
    border-color: var(--bleu);
    background: var(--bleu);
    color: #fff;
}
/* Une frequence mensuelle n'a sincerement aucun jour de semaine : sept cases
   vides laisseraient croire a une information manquante. */
.jours-aucun { color: #c4ccd8; }

/* A l'impression, les aplats de couleur ne sortent pas sur toutes les
   imprimantes : la case active reste reconnaissable par sa bordure epaisse et
   son texte noir, meme en noir et blanc. */
@media print {
    .jour { width: 19px; height: 19px; color: #b9c2ce; }
    .jour.is-on {
        background: #fff;
        border: 2px solid #000;
        color: #000;
    }
}

/* -- Signatures ------------------------------------------------------------- */
.cdc-foot { margin-top: 36px; padding-top: 18px; border-top: 1px solid var(--bordure); }
.cdc-foot-note { margin: 0 0 20px; font-size: 12px; color: var(--texte-doux); }
.cdc-signs { display: flex; gap: 40px; }
.cdc-sign { flex: 1; font-size: 12px; }
.cdc-sign-who { display: block; font-weight: 600; }
.cdc-sign-date { display: block; color: var(--texte-doux); font-size: 11px; }
.cdc-sign-box {
    height: 96px;
    margin-top: 8px;
    border: 1px solid var(--bordure);
    border-radius: 4px;
    background: #fcfdfe;
}

@media print {
    .sidebar, .topbar, .no-print, .cal-toolbar { display: none !important; }
    .content { padding: 0; }
    .cdc { border: 0; box-shadow: none; padding: 0; max-width: none; }
    .cdc-identity { background: #f7f9fb !important; -webkit-print-color-adjust: exact; }
    .cdc-table { page-break-inside: auto; }
    .cdc-table tr { page-break-inside: avoid; }
    /* L'en-tete de colonnes se repete en haut de chaque page imprimee : sans
       ca, la deuxieme page presente trois colonnes sans nom. */
    .cdc-table thead { display: table-header-group; }
    .cdc-foot { page-break-inside: avoid; }
}

/* -----------------------------------------------------------------------------
   INSPECTIONS
   -------------------------------------------------------------------------- */
.score-pill {
    display: inline-block;
    padding: 3px 12px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 700;
}
.score-good { background: #e3f4ea; color: #1f6b41; }
.score-fair { background: #fdf0dd; color: #8a5200; }
.score-bad  { background: #fae8e7; color: #8f201a; }
.score-none { background: #eef1f5; color: var(--texte-doux); }

.inspection-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 20px;
}
.inspection-head table { flex: 1; }
.inspection-head th { width: 120px; }

.inspection-score {
    flex-shrink: 0;
    text-align: center;
    padding: 16px 22px;
    border-radius: var(--radius);
    min-width: 130px;
}
.inspection-score.score-good { background: #e3f4ea; }
.inspection-score.score-fair { background: #fdf0dd; }
.inspection-score.score-bad  { background: #fae8e7; }
.inspection-score.score-none { background: #eef1f5; }
.inspection-score-value { display: block; font-size: 30px; font-weight: 700; line-height: 1.1; }
.inspection-score-label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--texte-doux); }

.inspection-tally { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 14px; font-size: 12px; }
.tally { color: var(--texte-doux); }
.tally strong { font-size: 15px; color: var(--texte); }
.tally-COMPLIANT strong     { color: #1f6b41; }
.tally-PARTIAL strong       { color: #8a5200; }
.tally-NON_COMPLIANT strong { color: #8f201a; }

.result-badge-COMPLIANT     { background: #e3f4ea; color: #1f6b41; }
.result-badge-PARTIAL       { background: #fdf0dd; color: #8a5200; }
.result-badge-NON_COMPLIANT { background: #fae8e7; color: #8f201a; }
.result-badge-NOT_CHECKED   { background: #eef1f5; color: var(--texte-doux); }

/* -- L'identite, en <dl> plutot qu'en tableau ------------------------------- */
.inspection-identity { flex: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 2px 24px; margin: 0; }
.inspection-identity div { display: flex; gap: 10px; padding: 3px 0; font-size: 13px; }
.inspection-identity dt { min-width: 86px; color: var(--texte-doux); font-size: 12px; }
.inspection-identity dd { margin: 0; font-weight: 600; }

/* ==========================================================================
   LA GRILLE D'INSPECTION, ZONE PAR ZONE

   ON INSPECTE UNE PIECE, PAS UNE LISTE. Sur le terrain on entre dans les
   sanitaires, on regarde tout ce qui les concerne, on passe aux bureaux. Un
   tableau par zone se remplit en marchant.

   La version precedente posait une CARTE par ligne : sur un cahier de trente
   lignes, ca faisait une page sans fin ou l'on ne savait plus ou l'on en
   etait - et trente formulaires a enregistrer un par un.
   ========================================================================== */
.insp-zone { padding: 0; overflow: hidden; }
.insp-zone-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    background: #f7f9fb;
    border-bottom: 1px solid var(--bordure);
}
.insp-zone-head h2 {
    margin: 0;
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--bleu-fonce);
}
.insp-zone-count { font-size: 12px; color: var(--texte-doux); }
.insp-zone-count.is-complete { color: #1f6b41; font-weight: 600; }
/* Une zone entierement controlee s'efface visuellement : ce qui reste a
   faire doit ressortir dans une page qui en compte cinq. */
.insp-zone.is-complete .insp-zone-head { background: #f2f8f4; }

.insp-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.insp-table thead th {
    padding: 8px 12px;
    background: transparent;
    border-bottom: 1px solid var(--bordure);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--texte-doux);
    text-align: left;
}
.insp-table td { padding: 8px 12px; border-bottom: 1px solid #eef1f5; vertical-align: top; }
.insp-table tbody tr:last-child td { border-bottom: 0; }

.insp-num { width: 34px; text-align: right; color: var(--texte-doux); }
.insp-etat { width: 250px; }
.insp-note { width: 26%; }
.insp-photo { width: 130px; }

.insp-label { display: block; font-weight: 600; }
.insp-freq { display: block; margin-top: 2px; font-size: 11px; color: var(--texte-doux); }
.insp-comment { display: block; padding-left: 8px; border-left: 2px solid var(--bordure); }

/* Le lisere de la ligne donne son etat sans avoir a lire la pastille. */
.insp-row { box-shadow: inset 3px 0 0 transparent; }
.insp-row.result-COMPLIANT     { box-shadow: inset 3px 0 0 #2f9e5f; }
.insp-row.result-PARTIAL       { box-shadow: inset 3px 0 0 #d99b1c; }
.insp-row.result-NON_COMPLIANT { box-shadow: inset 3px 0 0 #c0392b; background: #fffafa; }
.insp-row.result-NOT_CHECKED   { box-shadow: inset 3px 0 0 #dde3ea; }

/* -- Les quatre etats, en pastilles ----------------------------------------
   Un <select> demanderait deux clics et cacherait la reponse une fois
   choisie. En pastilles, on lit la colonne entiere d'un coup d'oeil. */
.insp-choices { display: flex; flex-wrap: wrap; gap: 4px; }
.insp-choice {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border: 1px solid var(--bordure);
    border-radius: 999px;
    font-size: 12px;
    line-height: 1.2;
    cursor: pointer;
    background: var(--blanc);
    white-space: nowrap;
}
/* Le bouton radio lui-meme est masque : c'est la pastille qu'on clique.
   `appearance: none` plutot que `display: none` - un champ retire du flux
   n'est plus atteignable au clavier, et la grille deviendrait inutilisable
   sans souris. */
.insp-choice input {
    appearance: none;
    width: 0;
    margin: 0;
    outline-offset: 6px;
}
.insp-choice:hover { border-color: var(--bleu); }
.insp-choice.is-active { font-weight: 600; }
.insp-choice.choice-COMPLIANT.is-active     { background: #e3f4ea; border-color: #2f9e5f; color: #1f6b41; }
.insp-choice.choice-PARTIAL.is-active       { background: #fdf0dd; border-color: #d99b1c; color: #8a5200; }
.insp-choice.choice-NON_COMPLIANT.is-active { background: #fae8e7; border-color: #c0392b; color: #8f201a; }
.insp-choice.choice-NOT_CHECKED.is-active   { background: #eef1f5; color: var(--texte-doux); }
.insp-choice:has(input:focus-visible) { outline: 2px solid var(--bleu); outline-offset: 2px; }

/* -- Photos ----------------------------------------------------------------- */
.insp-thumbs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.insp-thumbs:empty { margin-bottom: 0; }
.insp-thumb { position: relative; display: inline-block; }

/* LA PHOTO QU'ON VIENT DE CHOISIR, pas encore enregistree.

   Elle se distingue de celles qui sont deja en base : un liseré et un fond
   pointillés. Sans cette difference, on ne saurait pas laquelle disparaitrait
   si l'on quittait la page sans enregistrer - et on croirait avoir enregistre
   ce qui n'est qu'affiche. */
.insp-thumb-neuve img {
    border: 2px dashed var(--bleu);
    opacity: .9;
}
.insp-thumb img {
    width: 42px;
    height: 42px;
    object-fit: cover;
    border-radius: 4px;
    border: 1px solid var(--bordure);
    display: block;
}
.insp-thumb-del {
    position: absolute;
    top: -5px;
    right: -5px;
    width: 17px;
    height: 17px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #c0392b;
    color: #fff;
    font-size: 12px;
    line-height: 17px;
    cursor: pointer;
}
/* Le champ fichier natif affiche « Choose File / no file selected » : trois
   fois trop large pour une colonne de tableau, et en anglais. On masque le
   champ et on habille son label - le clic sur le label ouvre le selecteur,
   sans une ligne de JavaScript. */
.insp-file { display: inline-block; cursor: pointer; }
.insp-file input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.insp-file span {
    display: inline-block;
    padding: 3px 9px;
    border: 1px dashed var(--bordure);
    border-radius: 999px;
    font-size: 11px;
    color: var(--texte-doux);
    white-space: nowrap;
}
.insp-file:hover span { border-color: var(--bleu); color: var(--bleu); }
/* Un fichier choisi ne se voit pas autrement : le champ est masque, et rien
   ne dirait qu'une photo partira au prochain enregistrement. */
.insp-file:has(input:valid:not(:placeholder-shown)) span,
.insp-file input:focus-visible + span { border-color: var(--bleu); color: var(--bleu); }

/* -- La barre d'enregistrement, collee en bas -------------------------------
   Sur un cahier de trente lignes, un bouton place apres la derniere zone
   obligerait a faire defiler toute la page pour valider ce qu'on vient de
   cocher trois zones plus haut. */
.insp-savebar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-top: 14px;
    padding: 12px 18px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: 0 -2px 12px rgba(0, 0, 0, .08);
    font-size: 13px;
    color: var(--texte-doux);
}
/* La barre est collee en bas du cadre : sans cette marge, la derniere zone
   passe dessous et ses dernieres lignes deviennent illisibles. */
#grille { padding-bottom: 8px; }

@media print {
    .insp-savebar, .insp-file, .insp-thumb-del,
    .insp-thumb-neuve { display: none !important; }
    .insp-zone { break-inside: auto; }
    .insp-table tr { break-inside: avoid; }
}

/* ==========================================================================
   TACHES

   Le tableau reutilise integralement le kanban des feedbacks (memes valeurs
   de colonnes, donc memes liseres de tete sans une ligne de plus). Ce qui
   suit ne concerne que ce qui est PROPRE aux taches : l'urgence, l'echeance,
   et l'etat de chaque destinataire.
   ========================================================================== */

/* -- Le compteur du menu -------------------------------------------------- */
/* Visible depuis n'importe quelle page : c'est ce qui fait qu'on y pense. */
.nav-badge {
    display: inline-block;
    min-width: 20px;
    padding: 0 6px;
    margin-left: 6px;
    border-radius: 999px;
    background: var(--bleu-pale);
    color: var(--bleu-fonce);
    font-size: 11px;
    font-weight: 700;
    text-align: center;
    line-height: 18px;
}
/* Rouge des qu'il y a du retard : le nombre seul ne dit pas s'il presse. */
.nav-badge-late { background: var(--rouge); color: #fff; }

/* -- L'urgence ------------------------------------------------------------ */
/*
 * Quatre niveaux, quatre couleurs, et un liseré a gauche de la carte. La
 * couleur seule ne suffirait pas - le libelle reste ecrit en toutes lettres,
 * pour que la carte reste lisible en noir et blanc comme pour un daltonien.
 */
.badge-urgency-LOW      { background: #eef1f5; color: #5b6b7c; }
.badge-urgency-NORMAL   { background: #e6effa; color: #1f5f8b; }
.badge-urgency-HIGH     { background: #fdf0dd; color: #8a5200; }
.badge-urgency-CRITICAL { background: #fae8e7; color: #8f201a; }

.task-card { border-left: 3px solid transparent; }
.task-urgency-HIGH     { border-left-color: #d99b1c; }
.task-urgency-CRITICAL { border-left-color: #c0392b; }
.task-card.is-late     { border-left-color: #c0392b; background: #fffafa; }

/* -- L'echeance ----------------------------------------------------------- */
.task-due { font-size: 11.5px; color: var(--texte-doux); }
.is-late { color: #b3261e; font-weight: 600; }
.is-soon { color: #8a5200; font-weight: 600; }
.row-late td { background: #fffafa; }

/* -- L'etat d'un destinataire --------------------------------------------- */
/* Memes couleurs que les colonnes du tableau : un etat se reconnait au meme
 * endroit du spectre, qu'on le lise sur une carte ou dans un tableau. */
.badge-state-RECEIVED    { background: #fdf0dd; color: #8a5200; }
.badge-state-IN_PROGRESS { background: #e6effa; color: #1f5f8b; }
.badge-state-DONE        { background: #e3f4ea; color: #1f6b41; }

/*
 * Le suivi de l'expediteur : une pastille par personne.
 *
 * C'est la colonne qui justifie tout le modele - avec un statut unique par
 * tache, elle ne pourrait afficher qu'un seul mot pour trois personnes.
 */
.who-list { display: flex; flex-wrap: wrap; gap: 6px; }
.who {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: 12px;
    white-space: nowrap;
}
.who em { font-style: normal; opacity: .75; }
.who-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 7px;
}

/* -- Le choix des destinataires, en cases a cocher ------------------------ */
/*
 * « Maintenir Ctrl enfonce pour choisir plusieurs personnes » est la
 * fonctionnalite la moins decouverte de l'histoire des formulaires - et sur
 * telephone elle n'existe pas. Des cases a cocher rendent le choix multiple
 * evident ; il restait a les empecher de deborder de l'ecran.
 */

/* -- La zone de destinataires, qui defile -----------------------------------
   Django rend le widget en <div class="checkbox-scroll"> contenant un <div>
   par option : la classe est posee sur le widget (forms.py) plutot que visee
   par un selecteur large, qui attraperait les autres formulaires.

   Des cases a cocher posees a la suite deroulaient tout l'effectif entre
   l'echeance et le client : avec quarante salaries, le formulaire faisait
   quatre ecrans de haut et le bouton d'envoi disparaissait de l'horizon.

   Un cadre de hauteur fixe le ramene a la taille d'un champ ordinaire. Le
   `max-height` en `rem` (et non en `vh`) garantit qu'on voit toujours environ
   six lignes, quelle que soit la hauteur de l'ecran - sur un telephone,
   `vh` aurait donne une zone de deux lignes. */
.checkbox-scroll {
    max-height: 13.5rem;
    overflow-y: auto;
    padding: 5px;
    border: 1px solid var(--bordure);
    border-radius: 8px;
    background: var(--blanc);
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 2px 10px;
    /* Le defilement s'arrete a cette zone : sans cela, arriver en bas de la
       liste continue de faire defiler la page entiere, et on perd le
       formulaire de vue au moment ou l'on cochait quelqu'un. */
    overscroll-behavior: contain;
}
.checkbox-scroll label {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 9px;
    border-radius: 6px;
    font-weight: 400;
    cursor: pointer;
}
.checkbox-scroll label:hover { background: #f2f5f8; }
.checkbox-scroll input { width: 16px; height: 16px; margin: 0; flex: none; }
/* Ce qui est coche doit se retrouver sans relire toute la liste. */
.checkbox-scroll label:has(input:checked) {
    background: #eaf2fd;
    color: var(--bleu);
    font-weight: 500;
}

/* Case a cocher isolee dans une barre de filtres. */
.check {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 10px;
    font-weight: 400;
    white-space: nowrap;
}
.check input { width: 16px; height: 16px; margin: 0; }

/* -- Etat d'une demande de produits --------------------------------------- */
/* Memes teintes que partout : en attente = orange, accepte = vert, refuse =
 * rouge. Un etat se reconnait a la meme couleur d'un bout a l'autre du
 * logiciel. */
.badge-req-PENDING  { background: #fdf0dd; color: #8a5200; }
.badge-req-DONE     { background: #e3f4ea; color: #1f6b41; }
.badge-req-REFUSED  { background: #fae8e7; color: #8f201a; }

/* =============================================================================
   HORAIRES SOUPLES : la bande « a definir » et l'etirement des blocs
   ========================================================================== */

/* --- La bande « a definir » -----------------------------------------------
   Une prestation sans horaire n'a aucune position juste dans une grille ou la
   hauteur SIGNIFIE une heure. Elle vit donc au-dessus, comme un evenement
   « toute la journee » d'un agenda - visible, mais hors de l'echelle. */
.cal-undated {
    display: grid;
    grid-template-columns: 58px repeat(auto-fit, minmax(0, 1fr));
    min-width: 640px;
    background: #fffbf2;
    border: 1px solid var(--bordure);
    border-bottom: 0;
    border-radius: 6px 6px 0 0;
    /* HORS du cadre qui defile, et non dedans.
       A l'interieur, il aurait fallu la coller sous un en-tete lui-meme
       colle - deux `sticky` empiles dont la hauteur depend du contenu, donc
       un chevauchement des que l'en-tete grandit d'une ligne. Au-dessus, elle
       reste simplement toujours visible, sans calcul. */
    overflow-x: auto;
}
.cal-undated-label {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 4px 6px 4px 0;
    line-height: 1.1;
    text-align: right;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--texte-doux);
}
.cal-undated-col {
    padding: 4px;
    border-left: 1px solid var(--bordure);
    min-height: 30px;
}
.cal-undated-col.is-today { background: #fff7e6; }
.cal-undated-slot {
    display: block;
    padding: 3px 6px;
    margin-bottom: 3px;
    border-radius: 4px;
    /* Le tirete dit « pas encore pose » sans avoir besoin d'une legende : un
       bloc plein aurait l'air d'une decision prise. */
    border: 1px dashed var(--orange, #d98324);
    background: #fff;
    font-size: 11px;
    line-height: 1.3;
    color: var(--texte);
}
.cal-undated-slot:hover { text-decoration: none; filter: brightness(.97); }
.cal-undated-slot strong { display: block; }
.cal-undated-slot span { display: block; color: var(--texte-doux); }
/* Elle se glisse sur une heure de la grille : la main le dit au survol. */
.cal-undated-slot[data-move] { cursor: grab; }
/* L'heure n'apparait que dans le fantome, pendant qu'on la glisse. */
.cal-undated-heure { display: block; font-style: normal; font-weight: 600; color: var(--bleu); }
.cal-undated-heure:empty { display: none; }

/* --- Les poignees d'etirement ---------------------------------------------
   Huit pixels de haut, invisibles au repos. Elles n'apparaissent qu'au survol
   du bloc : affichees en permanence, elles surchargeraient une semaine
   chargee de quarante liseres colores pour une action qu'on fait rarement. */
.cal-slot-grip {
    position: absolute;
    left: 0;
    right: 0;
    height: 8px;
    z-index: 3;
    opacity: 0;
    transition: opacity .12s;
}
.cal-slot-grip-top    { top: 0; cursor: ns-resize; }
.cal-slot-grip-bottom { bottom: 0; cursor: ns-resize; }
.cal-slot-grip::after {
    content: "";
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    width: 26px;
    height: 3px;
    border-radius: 2px;
    background: var(--bleu);
}
.cal-slot-grip-top::after    { top: 1px; }
.cal-slot-grip-bottom::after { bottom: 1px; }

.cal-grid-col .cal-slot:hover .cal-slot-grip,
.cal-team-col .cal-slot:hover .cal-slot-grip { opacity: .85; }
.cal-slot.is-resizing .cal-slot-grip { opacity: 1; }

/* Pendant l'etirement : pas de selection de texte parasite, et un bloc qui
   passe au-dessus de ses voisins pour qu'on voie ce qu'on fait. */
.cal-slot.is-resizing {
    z-index: 10;
    user-select: none;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .18);
}

/* Les poignees n'ont de sens que dans une grille horaire : ailleurs, la
   hauteur ne represente aucune duree. */
.cal-list .cal-slot-grip,
.cal-month .cal-slot-grip { display: none; }

@media print {
    .cal-slot-grip { display: none !important; }
}

/* =============================================================================
   L'ECRAN DE REGLAGE DES DROITS
   =============================================================================
   Une soixantaine de cases a cocher tiennent sur une page a condition qu'on
   les organise : un interrupteur par module, ses capacites en colonnes en
   dessous. Une liste verticale de soixante lignes aurait fait defiler trois
   ecrans et personne n'aurait vu la fin.
   ========================================================================== */
.module-acces { padding-bottom: 14px; }

.module-switch {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 1.02rem;
    cursor: pointer;
    margin-bottom: 6px;
}
.module-switch input { width: 18px; height: 18px; cursor: pointer; }

.perm-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 8px 18px;
    margin-top: 12px;
}

.perm {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    cursor: pointer;
    line-height: 1.35;
}
.perm input { margin-top: 3px; flex-shrink: 0; cursor: pointer; }

/* Grise sans desactiver : un champ `disabled` ne serait pas envoye, et
   l'enregistrement effacerait les cases d'un module qu'on vient de fermer.
   On veut precisement l'inverse - les retrouver en le rouvrant. */
.perm-grid.desactive,
#liste-clients.desactive {
    opacity: .4;
    pointer-events: none;
}

/* Le texte qui explique un module ferme : masque par le script quand il est
   ouvert. Visible par defaut pour que la page reste juste sans JavaScript. */
.module-ferme { margin-top: 10px; font-style: italic; }

/* =============================================================================
   LE SUIVI D'UNE INTERVENTION - UN FIL DE DISCUSSION
   =============================================================================
   C'ETAIT UNE PILE DE CARTES IDENTIQUES, du plus recent au plus ancien,
   chacune repetant le nom de l'auteur et la date complete. On ne voyait ni
   qui parlait, ni dans quel ordre les choses s'etaient passees.

   C'est maintenant une conversation :

       le plus ancien en haut       un suivi est un recit, il se lit dans le
                                    sens ou il s'est ecrit ;
       une bulle par message        les siennes a droite, celles des autres a
                                    gauche - c'est ce qui rend un fil lisible
                                    sans lire les noms ;
       une pastille d'initiales     on reconnait un interlocuteur a sa
                                    pastille, pas a son nom relu quinze fois ;
       un separateur par journee    « Aujourd'hui », « Hier », « mardi 10
                                    mars » : une date par jour au lieu d'une
                                    date par message ;
       la saisie en bas             la ou elle est dans toutes les
                                    messageries, apres le dernier message.

   TOUT EST EN FLUX NORMAL, sans hauteur fixe ni zone qui defile a l'interieur
   de la page. Un fil de discussion enferme dans un cadre de 400 pixels est
   une prison sur un telephone : ici on fait defiler LA PAGE, comme partout
   ailleurs dans le logiciel.
   ========================================================================== */

/* -- L'en-tete de la conversation ----------------------------------------- */
/* Un bandeau et non une carte : il dit ou l'on est, il n'est pas du contenu. */
.fil-entete {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    margin-bottom: 18px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre);
}

/* -- Le fil ---------------------------------------------------------------- */
.fil { display: flex; flex-direction: column; gap: 14px; }

/* -- Le separateur de journee ---------------------------------------------
   Un filet qui traverse, avec le libelle pose dessus. C'est le repere
   universel des messageries, et il remplace quinze dates repetees par une. */
.fil-jour {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 10px 0 2px;
    color: var(--texte-doux);
    font-size: 12px;
}
.fil-jour::before,
.fil-jour::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--bordure);
}
.fil-jour span {
    padding: 3px 12px;
    border-radius: 999px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    white-space: nowrap;
    text-transform: capitalize;
}

/* -- Un message ------------------------------------------------------------ */
.fil-message {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    /* La bulle ne prend jamais toute la largeur : c'est cette marge libre a
       droite (ou a gauche) qui fait LIRE le fil comme une conversation. Sur
       un ecran large, une bulle pleine largeur redevient un paragraphe. */
    max-width: min(760px, 100%);
}

/* SES PROPRES MESSAGES PARTENT A DROITE. C'est la signature visuelle d'une
   messagerie, et elle vaut mieux que n'importe quelle etiquette : on sait qui
   parle sans lire. `margin-left:auto` pousse le bloc entier, `row-reverse`
   met la pastille du bon cote. */
.fil-message.est-moi {
    margin-left: auto;
    flex-direction: row-reverse;
}

/* -- La pastille d'initiales ----------------------------------------------- */
.fil-pastille {
    display: grid;
    place-items: center;
    flex: 0 0 34px;
    width: 34px;
    height: 34px;
    margin-top: 2px;
    border-radius: 50%;
    background: #e6effa;
    color: var(--bleu);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .02em;
}
.fil-message.est-moi .fil-pastille { background: var(--bleu); color: #fff; }

/* -- La bulle -------------------------------------------------------------- */
.fil-bulle {
    min-width: 0;              /* sans quoi une longue URL deborde du fil */
    padding: 9px 13px 11px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    /* Le coin coupe du cote de la pastille : le detail qui fait « bulle »
       plutot que « carte ». */
    border-radius: 14px 14px 14px 4px;
    box-shadow: var(--ombre);
}
.fil-message.est-moi .fil-bulle {
    background: #eaf2fd;
    border-color: #cfe0f5;
    border-radius: 14px 14px 4px 14px;
}

.fil-auteur {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 4px;
    font-size: 12.5px;
}
.fil-auteur strong { font-size: 13px; }
/* La croix de suppression se pousse au bout de la ligne, quel que soit le
   cote ou la bulle est posee. */
.fil-auteur form { margin-left: auto; line-height: 1; }
.fil-retirer {
    border: 0;
    background: none;
    color: var(--texte-doux);
    font-size: 17px;
    line-height: 1;
    padding: 0 2px;
    cursor: pointer;
    opacity: .5;
}
.fil-retirer:hover { opacity: 1; color: var(--rouge); }
/* Sur un ecran tactile il n'y a pas de survol : invisible en permanence, la
   croix serait introuvable. */
@media (hover: none) { .fil-retirer { opacity: .8; } }

/* `linebreaksbr` cote gabarit conserve les retours a la ligne ; la mesure de
   lecture est bornee ici, une note de terrain pouvant faire dix lignes. */
.fil-texte { margin: 0; max-width: 62ch; overflow-wrap: anywhere; }

/* -- Les photos d'un message ----------------------------------------------
   Une mosaique serree, comme dans une messagerie. Des vignettes plus petites
   que dans le reste du logiciel : ici elles sont DANS le message, et la
   visionneuse est a un clic pour les regarder vraiment. */
.fil-photos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 6px;
    margin-top: 8px;
}
.fil-photos .photo-item { margin: 0; }
.fil-photos img {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 8px;
}

/* -- Le fil vide ------------------------------------------------------------ */
.fil-vide {
    padding: 18px;
    text-align: center;
    background: var(--blanc);
    border: 1px dashed var(--bordure);
    border-radius: var(--radius);
}

/* -- La zone d'ecriture, en bas -------------------------------------------- */
.fil-composer {
    margin-top: 20px;
    padding: 14px 16px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre);
    /* Le fil s'arrete visuellement au-dessus : un filet plus marque separe ce
       qu'on lit de ce qu'on ecrit. */
    border-top: 2px solid var(--bleu);
}
.fil-composer .field:last-of-type { margin-bottom: 6px; }

/* -- La croix sur une vignette --------------------------------------------
   Posee SUR la photo : une colonne de boutons a cote de trente vignettes
   aurait double la hauteur du message. */
.suivi-photo { position: relative; }
.suivi-photo-del {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 24px;
    height: 24px;
    line-height: 1;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    font-size: 16px;
    cursor: pointer;
    opacity: 0;
    transition: opacity .12s;
}
.suivi-photo:hover .suivi-photo-del,
.suivi-photo:focus-within .suivi-photo-del { opacity: 1; }

@media (hover: none) {
    .suivi-photo-del { opacity: .8; }
}

/* DANS L'APERCU AVANT ENVOI, la croix est TOUJOURS visible.
   Les photos s'y cumulent choix apres choix : retirer celle qu'on vient
   d'ajouter par erreur est un geste courant, pas une correction rare. La
   cacher derriere un survol la rendrait introuvable au moment ou l'on en a
   le plus besoin. */
#suivi-apercu .suivi-photo-del { opacity: .85; }
#suivi-apercu .suivi-photo:hover .suivi-photo-del { opacity: 1; }
.photo-ajout-apercu .suivi-photo-del { opacity: .85; }

/* -- « Ajouter des photos » : un bouton, pas un champ fichier ----------------
   Voir templates/includes/photos_ajout.html. Le champ reste dans la page,
   accessible au clavier, mais invisible : c'est la grande zone qui s'offre au
   doigt. */
.photo-ajout { margin: 4px 0 12px; }
.photo-ajout input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
    pointer-events: none;
}
.photo-ajout-boutons { display: flex; flex-wrap: wrap; gap: 10px; align-items: stretch; }
.photo-ajout-boutons .photo-ajout-bouton { flex: 1 1 260px; }
.photo-ajout-boutons .bouton-appareil {
    flex: 1 1 160px;
    margin-top: 0;
    justify-content: center;
    border: 2px solid var(--bleu);
    border-radius: var(--radius);
    color: var(--bleu);
    font-weight: 600;
}
.photo-ajout-bouton {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    border: 2px dashed var(--bordure-forte);
    border-radius: var(--radius);
    background: var(--fond-doux);
    color: var(--texte);
    cursor: pointer;
    transition: border-color .12s, background .12s;
}
.photo-ajout-bouton:hover,
.photo-ajout input[type="file"]:focus-visible + .photo-ajout-etat,
.photo-ajout:focus-within .photo-ajout-bouton {
    border-color: var(--bleu);
    background: var(--bleu-pale);
}
.photo-ajout-icone {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--bleu);
    color: #fff;
}
.photo-ajout-icone .icone { width: 22px; height: 22px; }
.photo-ajout-texte { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.photo-ajout-texte strong { font-size: 15px; }
.photo-ajout-texte span { font-size: 13px; color: var(--texte-doux); }
.photo-ajout-plus { margin-left: auto; color: var(--bleu); }
.photo-ajout-etat { font-size: 13px; color: var(--texte-doux); margin: 8px 0; }
.photo-ajout-apercu:empty { display: none; }

/* Les photos deja enregistrees d'un bon : vignettes avec leur croix. */
.bon-photos { margin-bottom: 16px; }
.bon-photos .photo-item figcaption { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bon-photos-vide {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    border-radius: var(--radius);
    background: var(--fond-doux);
    color: var(--texte-doux);
    font-size: 14px;
    margin-bottom: 12px;
}
.bon-photos-envoi {
    border-top: 1px solid var(--bordure);
    padding-top: 14px;
}
.bon-photos-envoi .form-actions { margin-top: 8px; }

/* A L'IMPRESSION : le fil se lit, il ne s'ecrit pas. */
@media print {
    .suivi-photo-del, .fil-retirer, .fil-composer { display: none !important; }
    .fil-message.est-moi { margin-left: 0; flex-direction: row; }
    .fil-bulle { box-shadow: none; }
}

/* =============================================================================
   LA VISIONNEUSE
   =============================================================================
   Une photo en grand, par-dessus la page, avec des fleches pour parcourir la
   serie. Elle remplace l'ouverture dans un nouvel onglet : pour regarder les
   vingt-cinq photos d'une note, il fallait vingt-cinq onglets - ou vingt-cinq
   allers-retours, en perdant sa place dans le fil a chaque fois.
   ========================================================================== */
.visionneuse {
    position: fixed;
    inset: 0;
    z-index: 2000;          /* au-dessus de tout, barre laterale comprise */
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 16px;
    /* Presque opaque : a .92, le formulaire et le fil restaient lisibles
       derriere la photo et tiraient l'oeil. On vient regarder UNE image. */
    background: rgba(12, 18, 26, .96);
}
.visionneuse[hidden] { display: none; }

/* Le fond ne defile pas derriere le calque : sur un telephone, le balayage
   vertical emporterait la page sous la photo. */
body.visionneuse-ouverte { overflow: hidden; }

.visionneuse-cadre {
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    max-width: 100%;
    max-height: 100%;
    min-width: 0;           /* sinon l'image deborde du flex sur mobile */
}
.visionneuse-cadre img {
    max-width: 100%;
    /* On reserve la place de la legende et des marges : sans ce calcul, une
       photo en hauteur pousse le compteur hors de l'ecran. */
    max-height: calc(100vh - 110px);
    object-fit: contain;
    border-radius: 6px;
    background: #0c121a;
}
.visionneuse-cadre figcaption {
    display: flex;
    gap: 14px;
    align-items: baseline;
    color: rgba(255, 255, 255, .82);
    font-size: 13px;
    text-align: center;
}
.visionneuse-compteur { color: rgba(255, 255, 255, .6); }

/* Les commandes. Grandes : on les vise avec un pouce, parfois ganté. */
.visionneuse-fleche,
.visionneuse-fermer {
    flex-shrink: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    cursor: pointer;
    line-height: 1;
    transition: background .12s;
}
.visionneuse-fleche:hover,
.visionneuse-fermer:hover { background: rgba(255, 255, 255, .24); }
.visionneuse-fleche:focus-visible,
.visionneuse-fermer:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.visionneuse-fleche {
    width: 52px;
    height: 52px;
    font-size: 22px;
}
.visionneuse-fleche[hidden] { display: none; }

.visionneuse-fermer {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 44px;
    height: 44px;
    font-size: 28px;
}

/* Sur telephone, les fleches passent SOUS l'image plutot que de la serrer sur
   les cotes : a 390 px de large, deux boutons de 52 px lui prenaient un quart
   de la place. */
@media (max-width: 640px) {
    .visionneuse {
        flex-wrap: wrap;
        align-content: center;
    }
    .visionneuse-cadre {
        order: 1;
        flex-basis: 100%;
    }
    .visionneuse-gauche { order: 2; }
    .visionneuse-droite { order: 3; }
    .visionneuse-cadre img { max-height: calc(100vh - 200px); }
}

/* La vignette qui ouvre la visionneuse : on doit voir que c'est cliquable. */
a[data-photo] { display: block; cursor: zoom-in; }

@media print {
    .visionneuse { display: none !important; }
}

/* =============================================================================
   LE HALL DE L'ADMINISTRATION
   =============================================================================
   Trois portes, et rien d'autre. Chaque carte porte UN chiffre - celui qui
   repond a « y a-t-il quelque chose a regarder de ce cote ? ». Le detail vit
   derriere la porte ; le recopier ici en ferait un quatrieme ecran, et plus
   personne n'irait dans les trois autres.
   ========================================================================== */
.admin-hall {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
    margin-top: 18px;
}

.admin-porte {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 20px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: var(--blanc);
    box-shadow: var(--ombre);
    color: var(--texte);
    /* La carte ENTIERE est le lien : viser un titre de 14 px au doigt est le
       genre de detail qui fait rater une porte deux fois sur trois. */
    text-decoration: none;
    transition: border-color .12s, box-shadow .12s;
}
.admin-porte:hover {
    border-color: var(--bleu);
    box-shadow: 0 2px 10px rgba(16, 24, 40, .1);
    text-decoration: none;
}
.admin-porte:focus-visible { outline: 2px solid var(--bleu); outline-offset: 2px; }

.admin-porte-titre {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
    font-weight: 650;
    color: var(--bleu-fonce);
}
.admin-porte-titre .icone {
    width: 32px; height: 32px; padding: 7px;
    border-radius: 9px;
    background: var(--bleu-pale);
    color: var(--bleu);
}
.admin-porte-chiffre {
    font-size: 30px;
    font-weight: 700;
    line-height: 1.1;
    color: var(--bleu);
}
.admin-porte-sous { font-size: 12px; color: var(--texte-doux); }
.admin-porte-texte {
    margin-top: 8px;
    font-size: 13px;
    color: var(--texte-doux);
    line-height: 1.45;
}
/* Le seul chiffre de la page qui appelle une action : on le voit sans lire. */
.admin-porte-alerte { display: block; margin-top: 6px; color: var(--orange); }

/* =============================================================================
   CHOISIR LE CAHIER DES CHARGES A INSPECTER
   =============================================================================
   Une carte par prestation du site. L'action est A DROITE, sur toute la
   hauteur : on parcourt les noms d'un cote, on clique de l'autre. Les
   remettre a la suite du texte obligeait a relire chaque bloc pour retrouver
   le bouton.
   ========================================================================== */
.insp-choix {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}
.insp-choix-corps { min-width: 0; flex: 1; }
.insp-choix-titre { margin: 0; font-size: 16px; }
.insp-choix-action {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
/* Une prestation sans cahier des charges reste VISIBLE, en retrait. La
   masquer laisserait devant un choix incomplet : « pourquoi la vitrerie
   n'est-elle pas proposee ? ». */
.insp-choix.is-ferme { background: var(--fond); }
.insp-choix.is-ferme .insp-choix-titre { color: var(--texte-doux); }

/* =============================================================================
   L'EQUIPE HABITUELLE
   =============================================================================
   Une ligne par salarie, une colonne par jour de passage. La case est LARGE
   et centree : on coche vingt cases d'affilee, souvent au doigt sur une
   tablette, et une case de 13 px se rate une fois sur trois.
   ========================================================================== */
.equipe-table th.equipe-jour,
.equipe-table td.equipe-jour { text-align: center; width: 96px; }

.equipe-case {
    display: block;
    padding: 6px 0;
    cursor: pointer;
}
.equipe-case input { width: 18px; height: 18px; cursor: pointer; }
/* Toute la cellule est cliquable : viser la case elle-meme, sur une colonne
   de vingt lignes, demande une precision que personne n'a. */
.equipe-table td.equipe-jour:hover { background: var(--fond); }


/* =============================================================================
   L'INVENTAIRE PHYSIQUE - le tableau de comptage
   =============================================================================
   C'est la SEULE page du logiciel dont le telephone est le support principal
   et non un repli : on ne fait pas un inventaire assis devant un ecran. Tout
   ce qui suit part de la - une main tient l'appareil, l'autre pose un bidon.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   L'AVANCEMENT
   --------------------------------------------------------------------------
   Le seul chiffre qui compte pendant le comptage : combien il en reste. Il
   est en haut, il ne defile pas avec le tableau, et il tient sur une ligne.
   -------------------------------------------------------------------------- */
.count-progress {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: 14px;
    padding: 12px 14px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
}
.count-progress strong { font-size: 20px; }
.count-progress-bar {
    flex: 1;
    min-width: 120px;
    height: 8px;
    border-radius: 4px;
    background: #e8edf3;
    overflow: hidden;
}
.count-progress-bar span {
    display: block;
    height: 100%;
    background: var(--vert);
    transition: width .2s;
}

/* -----------------------------------------------------------------------------
   SCANNER, CHERCHER, FILTRER
   -------------------------------------------------------------------------- */
.count-toolbar {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-bottom: 14px;
    padding: 14px;
    background: #f7f9fc;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
}
.count-toolbar-todo {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    font-size: 13px;
    color: var(--texte-doux);
}

/* La ligne qu'on vient de scanner, sortie du tableau et posee en haut. C'est
   ce qui evite de la chercher du regard dans trois cents lignes - et donc ce
   qui rend le scan reellement utile. */
.count-scanned { border-color: var(--bleu); }
.count-scanned-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 10px;
}

/* -----------------------------------------------------------------------------
   LE TABLEAU
   -------------------------------------------------------------------------- */
.count-table td, .count-table th { vertical-align: middle; }
.count-input {
    width: 88px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* L'ETAT SE LIT A LA COULEUR DU BORD, PAS A UNE COLONNE DE PLUS. En comptant,
   on balaie le tableau du regard pour trouver ce qui n'est pas encore fait :
   une teinte se voit sans etre lue. */
.count-row-ok  td:first-child { box-shadow: inset 3px 0 0 var(--vert); }
.count-row-gap td:first-child { box-shadow: inset 3px 0 0 var(--orange); }

.count-gap-plus  { color: var(--vert); font-weight: 600; }
.count-gap-minus { color: var(--rouge); font-weight: 600; }

/* -----------------------------------------------------------------------------
   LA BARRE D'ENREGISTREMENT, COLLEE EN BAS
   --------------------------------------------------------------------------
   Un bouton pose apres trois cents lignes est un bouton qu'on n'atteint
   jamais : il faudrait faire defiler tout le tableau apres chaque etagere.
   Il reste donc au bas de l'ecran, quel que soit le defilement.
   -------------------------------------------------------------------------- */
.count-actions {
    position: sticky;
    bottom: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 -12px -12px;
    padding: 12px;
    background: var(--blanc);
    border-top: 1px solid var(--bordure);
    box-shadow: 0 -2px 8px rgba(16, 24, 40, .06);
}

/* Une carte qui appelle l'attention sans crier : un filet bleu a gauche. */
.card-accent { border-left: 3px solid var(--bleu); }

/* Les colonnes de nombres s'alignent a droite et gardent des chiffres de
   meme largeur : sans cela, une colonne de quantites ne se compare pas. */
.num { text-align: right; font-variant-numeric: tabular-nums; }

@media (max-width: 640px) {
    .count-toolbar { grid-template-columns: 1fr; }

    /* LE CHAMP DE SAISIE PREND TOUTE LA LARGEUR DE SA CARTE. Un champ de
       88 px au milieu d'une carte se vise mal quand on tient l'appareil
       d'une main. */
    .table-stack .count-input { width: 100%; max-width: 140px; }
    .count-progress strong { font-size: 18px; }
    .count-actions { margin: 0 -14px -14px; }
    .count-actions .btn { flex: 1 1 100%; }

    /* Le liseré d'etat passe en haut de la carte : sur le cote gauche d'une
       carte empilee, il ne marquerait qu'une cellule. */
    .count-row-ok  { border-left: 3px solid var(--vert); }
    .count-row-gap { border-left: 3px solid var(--orange); }
    .count-row-ok td:first-child,
    .count-row-gap td:first-child { box-shadow: none; }
}


/* -----------------------------------------------------------------------------
   LE RESUME DE LA QUALITE
   --------------------------------------------------------------------------
   Une pastille de score et une phrase, sur une ligne. C'etait un bandeau de
   titre avec deux badges empiles dans un `<h2>` : il fallait le lire pour
   comprendre qu'il resumait, alors qu'un resume doit se voir.
   -------------------------------------------------------------------------- */
.qualite-resume {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 0 18px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--bordure);
}
.qualite-resume .score-pill { font-size: 17px; padding: 6px 12px; }


/* =============================================================================
   LA CARTE DES CLIENTS
   =============================================================================
   Une hauteur FIXE, et c'est volontaire. Une carte qui s'adapte a son contenu
   n'existe pas : Leaflet a besoin d'une hauteur pour calculer son cadrage, et
   un conteneur sans hauteur donne une carte de zero pixel - le defaut le plus
   courant de cette bibliotheque, et celui qui ne dit rien dans la console.
   ========================================================================== */
.carte-clients {
    height: 380px;
    border-radius: var(--radius);
    border: 1px solid var(--bordure);
    /* Le fond gris SE VOIT quand les tuiles ne chargent pas - reseau coupe,
       entreprise qui les bloque. Les epingles, elles, restent posees dessus :
       la forme du semis reste lisible sans le fond. */
    background: #e8edf3;
    /* Sous la barre laterale en tiroir et sous le voile : une carte qui
       passerait au-dessus du menu ouvert serait cliquable a travers lui. */
    z-index: 0;
}
.carte-mention { margin: 8px 0 0; }

/* Leaflet pose ses propres liens dans les bulles ; on aligne leur taille sur
   celle du reste du logiciel plutot que de garder ses valeurs par defaut. */
.leaflet-popup-content { font-size: 13.5px; line-height: 1.5; }
.leaflet-container { font: inherit; }

@media (max-width: 640px) {
    .carte-clients { height: 300px; }
}

@media print {
    /* Une carte ne s'imprime pas : les tuiles ne sont pas dans le flux et la
       plupart des navigateurs rendent un cadre vide. */
    .carte-clients { display: none !important; }
}


/* =============================================================================
   LA REPRISE DU STOCK INITIAL
   =============================================================================
   Un tableau qu'on remplit au clavier, du haut vers le bas. Les champs y sont
   plus compacts qu'ailleurs : on en voit huit d'un coup, et l'on passe de
   l'un a l'autre a la tabulation.
   ========================================================================== */
.init-table td { padding: 4px 6px; }
.init-table .form-control,
.init-table .form-select { padding: 6px 8px; font-size: 13.5px; }
.init-table input.num { text-align: right; }

/* LES CHAMPS QUI NE S'APPLIQUENT PAS SONT GRISES, PAS CACHES. Un tableau dont
   les colonnes disparaissent d'une ligne a l'autre ne se lit plus, et
   l'alignement des en-tetes n'aurait plus de sens. */
.init-table .form-control:disabled,
.init-table .form-select:disabled {
    background: #f2f5f8;
    color: #9aa8b6;
    cursor: not-allowed;
}
.init-ligne-materiel { background: #fbfcfd; }

@media (max-width: 640px) {
    /* En mode carte, un champ desactive n'apporte rien : il occupe une ligne
       pour dire qu'il ne sert pas. On le retire, l'intitule avec. */
    .init-table td:has(.form-control:disabled) { display: none; }
    .init-table .form-control, .init-table .form-select { font-size: 16px; }
}

/* =============================================================================
   « PRENDRE UNE PHOTO »
   =============================================================================

   LE BOUTON N'EXISTE QUE LA OU IL SERT. `capture` est ignore sur un
   ordinateur : le bouton y ouvrirait exactement le meme selecteur de fichiers
   que le champ d'a cote, et un bouton qui ment est pire que pas de bouton.

   `pointer: coarse` veut dire « on designe au doigt » - telephone, tablette.
   C'est precisement la ou l'on prend des photos sur place, et c'est de la ou
   le manque a ete signale. Aucune detection de navigateur, aucun JavaScript :
   la regle est ici, elle se lit, et elle ne se trompe pas de modele.

   Il est cache PAR DEFAUT et montre par exception : un navigateur qui ne
   comprendrait pas la requete media ne montre donc rien, plutot qu'un bouton
   sans effet. */
.bouton-appareil { display: none; }

@media (pointer: coarse) {
    .bouton-appareil {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        margin-top: 8px;
        padding: 11px 18px;
        font: inherit;
        font-size: 15px;
        font-weight: 500;
        border: 1px solid var(--bordure);
        border-radius: 6px;
        background: var(--blanc);
        color: var(--texte);
        cursor: pointer;
    }
    .bouton-appareil::before { content: "\1F4F7"; font-size: 18px; line-height: 1; }
    .bouton-appareil:active { background: #f2f5f8; }
}

/* =============================================================================
   LES HEURES
   ============================================================================= */
.heures-filtres { display: grid; gap: 12px; }
.heures-periode { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.heures-periode label { font-size: 13px; color: var(--texte-doux); }
.heures-periode .form-control { width: auto; }
.heures-raccourcis { display: flex; flex-wrap: wrap; gap: 6px; }

/* LES CASES A COCHER, EN COLONNES QUI SE REORGANISENT.
   Trente salaries en une colonne feraient une page a faire defiler avant
   d'atteindre le bouton ; en grille, ils tiennent en quelques lignes, et sur
   telephone la grille retombe naturellement a une colonne. */
.heures-salaries > summary { cursor: pointer; font-weight: 600; font-size: 14px; }
.heures-cases {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 4px 12px;
    margin: 10px 0 4px;
}
.heures-cases .case { display: flex; align-items: center; gap: 7px; font-size: 13px; }
/* Une cible tactile decente : au doigt, une case de 13 px ne se coche pas. */
.heures-cases input[type="checkbox"] { width: 17px; height: 17px; flex: none; }

/* -- La ligne d'un salarie : un LIEN vers son releve ------------------------
   Elle etait depliable, elle ne l'est plus. Deplier gardait le detail sur la
   page du total : deux fiches ouvertes et la troisieme passait sous la ligne
   de flottaison, sur l'ecran meme ou l'on venait comparer. Le releve a
   maintenant sa page, donc cette ligne n'a plus qu'un role : y conduire.

   TOUTE LA LIGNE EST CLIQUABLE, pas un « voir le detail » de 60 px a droite.
   Au doigt, la cible d'un lien est ce qui decide s'il est utilisable. */
.fiche-salarie {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    /* PLUS SERRE QU'UNE CARTE ORDINAIRE : ce n'est plus une fiche, c'est une
       LIGNE DE LISTE. L'espacement des cartes (18 px) etalait trente salaries
       sur trois ecrans. */
    margin-top: 8px;
    margin-bottom: 0;
    padding: 13px 16px;
    color: inherit;
    text-decoration: none;
}
.fiche-salarie:hover,
.fiche-salarie:focus-visible { border-color: var(--accent); background: #fbfdff; }
.fiche-nom { font-weight: 700; }
.fiche-chiffres { display: flex; align-items: baseline; gap: 10px; }
/* Le chevron dit « ca ouvre quelque chose » sans ajouter un mot a lire. */
.fiche-fleche { color: var(--texte-doux); font-size: 18px; line-height: 1; }
.fiche-corps { padding: 14px 16px; }

.fiche-repartition { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.repartition-part {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 4px 9px;
    border: 1px solid var(--bordure);
    border-radius: 999px;
    font-size: 12px;
}
.repartition-part em { font-style: normal; font-size: 11px; }

/* L'ECART SE VOIT SANS LE CHERCHER. Trente lignes conformes n'apprennent rien ;
   les deux qui debordent expliquent le mois. */
.texte-ecart { color: #8a5200; font-weight: 600; }
.ligne-ecart { background: #fffcf6; }

/* -- Le filtre par salaries du calendrier ---------------------------------- */
/* Replie par defaut : trente noms deployes repousseraient la grille sous la
   ligne de flottaison, sur l'ecran dont on vient justement voir le calendrier. */
/* -- LE MENU DES COLLABORATEURS A L'AIR D'UN MENU ------------------------------
   IL N'EN AVAIT PAS L'AIR, ET C'EST TOUT LE DEFAUT. A cote du menu deroulant
   des clients - une vraie boite avec son cadre et son chevron - celui-ci
   n'etait qu'un mot souligne : « Collaborateurs ». Rien ne disait qu'on
   pouvait cliquer dessus, ni que c'etait le pendant du menu d'a cote.

   CE N'EST TOUJOURS PAS UN `<select>`, ET C'EST VOULU. Il faut pouvoir en
   cocher PLUSIEURS - une prestation glissee sur le calendrier revient a tous
   les coches - et une liste deroulante multiple ne laisse selectionner qu'une
   ligne au doigt. On garde donc les cases a cocher, et on leur donne
   l'apparence exacte de la barre voisine. */
.cal-salaries { position: relative; }

.cal-salaries > summary {
    display: flex;
    align-items: center;
    gap: 8px;
    /* La place a droite est reservee au chevron. */
    padding: 9px 30px 9px 11px;
    min-width: 190px;
    font: inherit;
    font-size: 13px;
    color: var(--texte);
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: 6px;
    cursor: pointer;
    white-space: nowrap;
    /* Retire le triangle que le navigateur pose de lui-meme : il ne ressemble
       a rien d'autre dans la barre, et on en dessine un propre juste apres. */
    list-style: none;
}
.cal-salaries > summary::-webkit-details-marker { display: none; }

/* Le chevron, dessine plutot qu'ecrit : un caractere « ▾ » change de forme et
   de taille d'une police a l'autre, et ne s'aligne jamais deux fois pareil. */
.cal-salaries > summary::after {
    content: "";
    position: absolute;
    right: 12px;
    top: 50%;
    width: 7px;
    height: 7px;
    border-right: 2px solid var(--texte-doux);
    border-bottom: 2px solid var(--texte-doux);
    transform: translateY(-70%) rotate(45deg);
}
.cal-salaries[open] > summary::after { transform: translateY(-20%) rotate(-135deg); }

/* Ouvert, la barre se marque comme un champ actif - meme trait que
   `.form-select:focus`, pour que les deux menus reagissent pareil. */
.cal-salaries[open] > summary {
    border-color: var(--bleu);
    box-shadow: 0 0 0 3px rgba(31, 95, 139, .12);
}

/* LE PANNEAU FLOTTE AU-DESSUS DU CALENDRIER au lieu de s'inserer dans la
   barre. Insere, il poussait les boutons voisins a la ligne et deplacait
   toute la grille vers le bas - ouvrir le filtre faisait sauter l'ecran
   qu'on venait consulter. */
.cal-salaries-panneau {
    position: absolute;
    z-index: 30;
    top: calc(100% + 4px);
    left: 0;
    min-width: 300px;
    max-width: 440px;
    padding: 10px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: 6px;
    box-shadow: var(--ombre);
}
/* La hauteur bornee et le defilement viennent de `.liste-zone`, partagee avec
   les autres longues listes du logiciel. Ici on ne regle que la grille. */
.cal-salaries-cases {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: 4px 12px;
    margin-top: 8px;
    padding: 6px 8px;
}
.cal-salaries-cases .case { display: flex; align-items: center; gap: 7px; font-size: 13px; }
.cal-salaries-cases input[type="checkbox"] { width: 17px; height: 17px; flex: none; }

/* -- Poser une prestation sans la glisser ---------------------------------- */
/* VISIBLE SEULEMENT AU DOIGT, comme les boutons « Deplacer » des tableaux.
   Sur ordinateur le glisser marche et il est plus rapide ; y ajouter un champ
   de date encombrerait chaque carte pour rien. */
.backlog-poser { display: none; }

@media (pointer: coarse) {
    .backlog-poser {
        display: flex;
        gap: 6px;
        align-items: center;
        margin-top: 8px;
    }
    .backlog-poser .form-control { font-size: 15px; padding: 7px 8px; flex: 1; min-width: 0; }
    .backlog-poser .btn { flex: none; }
}

/* -----------------------------------------------------------------------------
   LE GROUPE, ET LE FIL D'ACTUALITES DU CLIENT
   -------------------------------------------------------------------------- */

/* Le badge du groupe est un LIEN : il doit se voir cliquable sans crier plus
   fort que le nom du client a cote duquel il se trouve. */
.badge-groupe {
    background: #e6effa;
    color: var(--bleu);
    text-decoration: none;
    text-transform: none;
    letter-spacing: 0;
}
.badge-groupe:hover { background: #d6e4f4; }

/* -- Le fil ---------------------------------------------------------------- */
.note-form { margin-bottom: 16px; }
.note-form textarea {
    width: 100%;
    font: inherit;
    padding: 8px 10px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    resize: vertical;
}
.note-form-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 8px;
}

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

.fil-item {
    padding: 12px 0;
    border-top: 1px solid var(--bordure);
}
.fil-item:first-child { border-top: none; }

/* L'EPINGLE SE VOIT AU BORD, PAS AU FOND. Un aplat de couleur sur toute la
   carte ferait crier chaque consigne d'acces plus fort que le texte voisin ;
   une barre a gauche suffit a la retrouver en balayant la colonne. */
.fil-epingle {
    border-left: 3px solid var(--orange);
    padding-left: 10px;
    margin-left: -13px;
}

.fil-texte { margin-bottom: 4px; }
.fil-texte .badge { margin-right: 6px; }

.fil-pied { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* -- « A savoir sur ce client » : une information = une ligne encadree ------
   Le fil d'avant separait ses entrees par un simple filet, et l'on ne voyait
   ni ou finissait une information ni laquelle etait « a retenir ». */
.asavoir-titre {
    display: block;
    margin: 18px 0 8px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--texte-doux);
}
.asavoir-titre-retenir { color: #9a5b00; }
.asavoir { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.asavoir-ligne {
    border: 1px solid var(--bordure);
    border-left: 4px solid #c7d0db;
    border-radius: var(--radius);
    padding: 10px 14px;
    background: #fff;
}
.asavoir-retenir {
    border-color: #f3d9b1;
    border-left-color: var(--orange);
    background: var(--orange-pale);
}
.asavoir-texte { overflow-wrap: anywhere; line-height: 1.5; }
.asavoir-pied {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 6px;
}
.asavoir-actions { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.asavoir-actions .btn { width: auto; padding: 2px 8px; font-size: 12px; }
#actualites .note-form { margin: 18px 0 0; padding-top: 14px; border-top: 1px solid var(--bordure); }
#actualites .note-form .asavoir-titre { margin-top: 0; }

/* Un formulaire qui ne doit pas casser la ligne : le bouton « supprimer » d'un
   POST ne peut pas etre un simple lien (un GET qui efface est le debut d'un
   autre probleme), mais il doit s'y ressembler. */
.inline { display: inline; margin: 0; }

.lien-bouton {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 12px;
    color: var(--texte-doux);
    text-decoration: underline;
    cursor: pointer;
}
.lien-bouton:hover { color: var(--bleu); }
.lien-danger:hover { color: var(--rouge); }

/* -----------------------------------------------------------------------------
   LE LOGO
   -------------------------------------------------------------------------- */
.auth-logo { display: block; margin: 0 auto 10px; }

.auth-footer-mark {
    vertical-align: -3px;
    margin-right: 5px;
    opacity: .75;
}

/* -----------------------------------------------------------------------------
   LE POINTAGE
   -------------------------------------------------------------------------- */
/* Une alerte SOS concerne une PERSONNE, pas une machine : c'est la seule
   carte du logiciel qui a le droit d'etre bruyante. */
.card-alerte { border-left: 4px solid var(--rouge); }
.card-alerte h2 { color: var(--rouge); }

.ligne-anomalie { background: #fdf8ef; }

.alerte-item {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: flex-start;
    justify-content: space-between;
    padding: 12px 0;
    border-top: 1px solid var(--bordure);
}
.alerte-item:first-of-type { border-top: none; }

.alerte-form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.alerte-form .form-control { min-width: 220px; }

.inline-form { display: flex; gap: 6px; align-items: center; }
.form-select-sm { padding: 3px 6px; font-size: 13px; }

@media (max-width: 720px) {
    .alerte-item { flex-direction: column; }
    .alerte-form { width: 100%; }
    .alerte-form .form-control { flex: 1; min-width: 0; }
}

/* =============================================================================
   UNE LONGUE LISTE QUI TIENT DANS UN CADRE
   =============================================================================
   Plusieurs ecrans affichent TOUT l'effectif, ou TOUS les clients, dans la
   page : l'affectation d'une intervention, le filtre du calendrier, celui des
   heures, le perimetre d'un collaborateur.

   Avec huit salaries c'est agreable ; avec soixante, la page mesure quatre
   ecrans de haut et le bouton qu'on cherchait est passe sous la ligne de
   flottaison. Le cadre ci-dessous borne la hauteur : la liste s'allonge vers
   l'interieur, jamais vers le bas de la page.

   LE CADRE EST EN CSS, PAS EN JAVASCRIPT, et c'est delibere : il tient meme
   si le script de recherche ne se charge pas. `listefiltrable.js` n'ajoute
   que la recherche par-dessus.

   `--liste-hauteur` se redefinit au cas par cas : un tableau d'affectation a
   besoin de plus de place que des cases a cocher sur deux colonnes.
   ========================================================================== */
.liste-zone {
    --liste-hauteur: 260px;
    max-height: var(--liste-hauteur);
    overflow-y: auto;
    /* La barre de defilement ne doit pas recouvrir le texte. */
    padding-right: 4px;
    /* Un liseré discret : sans lui, rien ne dit que la zone defile, et on
       croit que la liste s'arrete la ou l'ecran la coupe. */
    border: 1px solid var(--bordure);
    border-radius: 6px;
}

/* Un tableau dans le cadre : l'en-tete reste visible pendant qu'on defile,
   sans quoi on perd le sens des colonnes des la troisieme ligne. */
.liste-zone table { margin: 0; }
.liste-zone thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--blanc);
}

.liste-recherche { margin: 8px 0; width: 100%; }

/* Pose par `listefiltrable.js`. `!important` parce que les elements masques
   sont souvent des `display: flex` declares plus loin dans ce fichier. */
.est-masque { display: none !important; }

/* Une liste filtrable qui garde toute sa hauteur : le tableau des droits
   d'acces. On ne veut que la recherche, pas le cadre qui defile. */
.liste-zone.liste-zone-libre { --liste-hauteur: none; border: 0; padding-right: 0; }
.droits-recherche { max-width: 360px; margin-bottom: 12px; }

.liste-vide { margin: 8px 0 0; font-style: italic; }

/* Le compteur a cote du titre d'une liste : « 62 collaborateurs ». Il dit
   pourquoi la zone defile, ce qu'une barre de defilement seule ne dit pas. */
.liste-compte { font-weight: normal; }

/* Le tableau d'affectation d'une intervention : deux lignes de texte par
   collaborateur quand il y a un conflit, d'ou un cadre plus haut que pour des
   cases a cocher. Six a sept noms visibles : assez pour choisir sans defiler
   dans le cas courant, assez court pour que le reste de la fiche reste a
   l'ecran. */
.liste-zone-affectation { --liste-hauteur: 340px; }

/* Le tableau « equipe habituelle » : une ligne par salarie, courte. Plus haut
   que le cadre par defaut parce que voir les jours de plusieurs personnes a la
   fois est tout l'interet de ce tableau. */
.liste-zone-equipe { --liste-hauteur: 420px; }

/* La phrase sous les cases : « plusieurs choix possibles ». Elle est la parce
   que la barre ressemble maintenant a un menu deroulant ordinaire - et qu'un
   menu deroulant ordinaire ne laisse choisir qu'une chose. */
.cal-salaries-aide { margin: 8px 0 0; }

/* La phrase « 12 collaborateurs ont deja travaille chez X », sous les cases.
   Elle est ce qui rend le tri VISIBLE : reduire de 28 a 26 ne se remarque pas
   autrement, et un tri qu'on ne voit pas passe pour un tri en panne. */
.cal-salaries-compte {
    margin: 8px 0 0;
    padding-top: 8px;
    border-top: 1px solid var(--bordure);
}
.cal-salaries-compte .lien-bouton { margin-left: 6px; }


/* =============================================================================
   LA FLOTTE
   =============================================================================
   UNE COULEUR PAR ETAT, ET LA MEME PARTOUT : sur la carte, dans la liste, sur
   la fiche. Vert = roule, bleu = gare, orange = on ne sait plus, gris = pas
   de boitier. Le muet n'est PAS rouge : ne pas avoir de nouvelles n'est pas
   une panne, c'est une question a poser.
   ========================================================================== */
.etat {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    font-weight: 600;
    white-space: nowrap;
}
.etat::before {
    content: "";
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 9px;
}
.etat-EN_ROUTE     { color: #1f7a45; }
.etat-A_L_ARRET    { color: var(--bleu); }
.etat-MUET         { color: var(--orange); }
.etat-SANS_BOITIER { color: #8a96a3; }

/* La carte et la liste, cote a cote sur un grand ecran : on lit une ligne et
   on voit ou elle est sans faire defiler. L'une sous l'autre sur un
   telephone. */
.flotte-grille {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: 16px;
    align-items: start;
}
.flotte-carte {
    height: 440px;
    border-radius: var(--radius);
    border: 1px solid var(--bordure);
    background: #e8edf3;
    z-index: 0;
}
.trajet-carte { height: 420px; }

.flotte-liste { list-style: none; margin: 0; padding: 0; }
.flotte-liste li {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--bordure);
}
.flotte-liste li:last-child { border-bottom: 0; }
.flotte-nom { font-weight: 600; }
.flotte-immat {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    color: var(--texte-doux);
    margin-left: 6px;
}
.flotte-sous { grid-column: 1 / -1; font-size: 13px; color: var(--texte-doux); }

/* LA JAUGE : une barre, pas un nombre seul. « 18 % » se lit ; une barre au
   quart se voit de loin. */
.jauge {
    display: inline-block;
    width: 46px;
    height: 7px;
    border-radius: 4px;
    background: #e5eaf0;
    vertical-align: middle;
    overflow: hidden;
    margin-right: 4px;
}
.jauge > span { display: block; height: 100%; background: var(--vert); }
.jauge-basse > span { background: var(--orange); }

/* Les alertes : une ligne par chose a faire, la couleur dit l'urgence. */
.flotte-alertes { list-style: none; margin: 0; padding: 0; }
.flotte-alertes li {
    padding: 9px 12px;
    margin-bottom: 6px;
    border-left: 4px solid var(--bordure);
    background: #fafbfc;
    border-radius: 0 6px 6px 0;
}
.flotte-alertes .niveau-danger { border-left-color: var(--rouge); background: #fffafa; }
.flotte-alertes .niveau-warn   { border-left-color: var(--orange); background: #fffcf6; }
.flotte-alertes .niveau-info   { border-left-color: var(--bleu); }
.flotte-alertes strong { display: block; }

/* La source d'un chiffre : « mesuré », « estimé », « théorique ». Discrete
   mais toujours la - c'est ce qui empeche de lire une estimation comme un
   constat. */
.source {
    display: inline-block;
    font-size: 11px;
    padding: 0 6px;
    border-radius: 4px;
    background: #eef1f5;
    color: var(--texte-doux);
    font-weight: 600;
    vertical-align: middle;
}
.source-MESURE, .source-COMPTEUR { background: #e3f4ea; color: #1f6b41; }
.source-JAUGE, .source-GPS       { background: #e6effa; color: #1f5f8b; }
.source-THEORIQUE                { background: #fdf0dd; color: #8a5200; }

/* Le trajet : depart -> arrivee, lisible d'un coup d'oeil. */
.trajet-parcours { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.trajet-parcours .fleche { color: var(--texte-doux); }

/* Le profil de vitesse, dessine en SVG cote serveur. */
.profil { width: 100%; height: auto; display: block; }
.profil .aire { fill: rgba(31, 95, 139, .12); }
.profil .ligne { fill: none; stroke: var(--bleu); stroke-width: 1.6; }
.profil .grad { stroke: var(--bordure); stroke-width: 1; }
.profil text { font-size: 10px; fill: var(--texte-doux); }

.presence-A_BORD     { color: #1f6b41; }
.presence-LAISSEE    { color: var(--rouge); font-weight: 600; }
.presence-JAMAIS_VUE { color: var(--texte-doux); }

@media (max-width: 900px) {
    .flotte-grille { grid-template-columns: 1fr; }
    .flotte-carte { height: 320px; }
}

@media print {
    .flotte-carte { display: none !important; }
}

/* La fiche d'un vehicule : libelle au-dessus, valeur dessous, en colonnes. */
.flotte-fiche {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px 20px;
    margin: 0;
}
.flotte-fiche dt { font-size: 12px; color: var(--texte-doux); text-transform: uppercase; letter-spacing: .03em; }
.flotte-fiche dd { margin: 2px 0 0; font-weight: 600; }

/* Le chiffre d'une tuile garde sa taille, meme habille de la pastille d'etat. */
.stat-value .etat { font-size: inherit; font-weight: 700; gap: 10px; }
.stat-value .etat::before { width: 12px; height: 12px; flex-basis: 12px; }
/* Les tuiles de la flotte ne collent pas a la carte qui suit. */
.flotte-tuiles { margin-bottom: 18px; }


/* =============================================================================
   LES FILTRES QUI S'APPLIQUENT EN TAPANT (static/js/filtreauto.js)
   =============================================================================
   Le bouton « Filtrer » disparait quand le script tourne : il n'aurait plus
   rien a faire, et un bouton sans effet fait douter de tout le reste. Sans
   JavaScript, il reste la, et tout marche comme avant.
   ========================================================================== */
.filtre-auto button[type="submit"] { display: none; }

/* Pendant que la reponse arrive, la liste s'estompe un instant : on voit que
   la recherche est partie, sans qu'un sablier vienne cacher ce qu'on lisait. */
.filtre-en-cours .content .table-wrapper,
.filtre-en-cours .content .kanban,
.filtre-en-cours .content .pagination {
    opacity: .55;
    transition: opacity .15s;
}


/* =============================================================================
   LA LISTE DEROULANTE A CHOIX MULTIPLE (includes/choix_multiple.html)
   =============================================================================
   FERMEE, ELLE RESSEMBLE TRAIT POUR TRAIT A UNE LISTE DEROULANTE ORDINAIRE :
   meme bordure, meme hauteur, meme chevron que « Client concerne » a cote.
   Ouverte, une liste simple - une ligne par choix, pas une grille : en
   colonnes, les noms se lisaient comme un tableau.
   ========================================================================== */
.choix-multiple { position: relative; }

.choix-multiple > summary {
    position: relative;
    display: block;
    padding: 9px 32px 9px 11px;
    font: inherit;
    color: var(--texte);
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: 6px;
    cursor: pointer;
    list-style: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.choix-multiple > summary::-webkit-details-marker { display: none; }
.choix-multiple-vide > summary { color: var(--texte-doux); }

/* Le chevron, dessine, comme celui du filtre des collaborateurs. */
.choix-multiple > summary::after {
    content: "";
    position: absolute;
    right: 13px;
    top: 50%;
    width: 7px;
    height: 7px;
    border-right: 2px solid var(--texte-doux);
    border-bottom: 2px solid var(--texte-doux);
    transform: translateY(-70%) rotate(45deg);
}
.choix-multiple[open] > summary::after { transform: translateY(-20%) rotate(-135deg); }
.choix-multiple[open] > summary,
.choix-multiple > summary:focus-visible {
    outline: none;
    border-color: var(--bleu);
    box-shadow: 0 0 0 3px rgba(31, 95, 139, .12);
}
.field-error .choix-multiple > summary { border-color: var(--rouge); }

/* LE PANNEAU FLOTTE au-dessus du formulaire, sous la barre : l'inserer
   pousserait les champs suivants et ferait sauter la page a chaque
   ouverture. */
.choix-multiple-panneau {
    position: absolute;
    z-index: 30;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    padding: 8px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: 6px;
    box-shadow: 0 8px 24px rgba(16, 24, 40, .12);
}
.choix-multiple-options {
    --liste-hauteur: 15rem;
    margin-top: 6px;
    padding: 2px;
}
.choix-multiple-options .case {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 8px;
    border-radius: 5px;
    margin: 0;
    cursor: pointer;
    font-size: 14px;
    font-weight: 400;
}
.choix-multiple-options .case:hover { background: #f3f6f9; }
.choix-multiple-options input[type="checkbox"] { width: 17px; height: 17px; flex: none; margin: 0; }
.choix-multiple .liste-vide { margin: 8px 4px 2px; }

/* Au doigt, le panneau s'insere sous la barre au lieu de flotter : un panneau
   flottant sur un petit ecran passe sous le clavier. */
@media (max-width: 640px) {
    .choix-multiple-panneau { position: static; margin-top: 6px; box-shadow: none; }
}

/* =============================================================================
   LES GROUPES DE CLIENTS : chaque groupe, ses clients en dessous
   ========================================================================== */
.groupe-carte .card-title { margin-bottom: 8px; }
.groupe-carte h2 { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.groupe-clients {
    list-style: none;
    margin: 0;
    padding: 0;
    columns: 2 260px;
    column-gap: 28px;
}
.groupe-clients li {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--bordure);
    break-inside: avoid;
}

/* =============================================================================
   LE TABLEAU DE BORD
   ========================================================================== */
.dash-accueil { margin-bottom: 20px; }
.dash-accueil h2 { font-size: 22px; margin: 0 0 2px; }
.dash-accueil p { margin: 0; }

.dash-kpi { margin-bottom: 20px; }

/* Le planning du jour a gauche, ce qui attend un geste a droite. */
.dash-colonnes {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
    gap: 20px;
    align-items: start;
}
.dash-colonnes > .card { margin-bottom: 20px; }
.dash-colonnes > .dash-a-traiter:only-child { grid-column: 1 / -1; }
@media (max-width: 1180px) {
    .dash-colonnes { grid-template-columns: minmax(0, 1fr); }
}

/* -- « A traiter » : une ligne par sujet, son nombre, son lien ------------- */
.liste-actions { list-style: none; margin: -6px -12px; padding: 0; }
.liste-actions li + li { border-top: 1px solid var(--bordure); }
.liste-actions a {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px;
    border-radius: 10px;
    color: var(--texte);
    font-weight: 600;
    font-size: 14px;
}
.liste-actions a:hover { background: var(--fond-doux); text-decoration: none; color: var(--texte); }
.liste-actions-icone {
    display: grid; place-items: center;
    width: 34px; height: 34px; flex-shrink: 0;
    border-radius: 9px;
    background: var(--bleu-pale);
    color: var(--bleu);
}
.liste-actions-texte { flex: 1; min-width: 0; }
.liste-actions-texte small { display: block; margin-top: 1px; font-weight: 400; font-size: 12.5px; color: var(--texte-doux); }
.liste-actions-nombre {
    min-width: 30px;
    padding: 2px 9px;
    border-radius: 999px;
    background: #f0f2f5;
    color: var(--texte-moyen);
    font-size: 13px;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.liste-actions-nombre.est-warn   { background: var(--orange-pale); color: #8a5200; }
.liste-actions-nombre.est-danger { background: var(--rouge-pale); color: var(--rouge); }
.liste-actions li.est-vide .liste-actions-icone { background: var(--fond); color: var(--texte-faible); }
.liste-actions li.est-vide a { color: var(--texte-doux); font-weight: 500; }

/* -- Un ecran vide qui explique pourquoi ----------------------------------- */
.etat-vide { text-align: center; padding: 40px 24px; }
.etat-vide > .icone {
    width: 48px; height: 48px; padding: 12px;
    margin-bottom: 12px;
    border-radius: 14px;
    background: var(--bleu-pale);
    color: var(--bleu);
}
.etat-vide p { max-width: 520px; margin: 0 auto; }

/* =============================================================================
   LES FORMULAIRES SUR DEUX COLONNES (templates/includes/form.html)
   --------------------------------------------------------------------------
   La largeur qui compte est celle du CADRE : un formulaire pose dans une
   carte etroite reste sur une colonne, le meme formulaire en pleine page se
   range sur deux. D'ou la requete de conteneur plutot qu'une requete d'ecran.
   ========================================================================== */
.form-champs { container-type: inline-size; }
@container (min-width: 640px) {
    .form-grille {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 20px;
    }
    .form-grille > .field-large { grid-column: 1 / -1; }
}
/* Un navigateur trop ancien pour les requetes de conteneur garde une colonne :
   c'est le rendu d'avant, rien ne casse. */

.field-case { padding: 2px 0; }
.case {
    display: flex !important;
    align-items: flex-start;
    gap: 10px;
    margin: 0 !important;
    font-weight: 500 !important;
    color: var(--texte) !important;
    cursor: pointer;
}
.case input[type="checkbox"] { margin-top: 2px; }
.field-case .help { margin-left: 26px; }

/* Une fiche a remplir : assez large pour deux colonnes, pas davantage - une
   ligne de saisie de 1 200 px se lit mal. */
.card-formulaire { max-width: 880px; padding: 24px 28px; }

/* =============================================================================
   LE SCAN SUR UNE LIGNE : [camera] [code........] [Ajouter]
   --------------------------------------------------------------------------
   Le petit bouton camera vit au debut de la ligne de saisie. Sans camera (ou
   sans HTTPS), il disparait et la ligne reste un simple champ : on tape le
   code imprime sous le QR.
   ========================================================================== */
.scanbar-row { align-items: stretch; }
.scanbar-row > .btn { flex-shrink: 0; }
.scanner-compact { display: flex; flex: 0 0 auto; }
.scanner-compact .scanner-unsupported { display: none; }
.scanner-compact:has(> [data-scanner-open][hidden]) { display: none; }
.btn-camera {
    width: 42px;
    min-height: 40px;
    padding: 0;
    color: var(--bleu);
}
.btn-camera .icone { width: 20px; height: 20px; }
.scanbar-label, .scanbar .scanbar-scan > label:not(.sr-only) {
    display: block;
    text-transform: none;
    letter-spacing: 0;
    margin-bottom: 6px;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--texte-moyen);
}
.scanbar { background: var(--blanc); }

/* =============================================================================
   LE MENU OU L'ON TAPE POUR CHERCHER (static/js/selectrecherche.js)
   ========================================================================== */
.recherche-select { position: relative; }
.recherche-select > .form-control {
    padding-right: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235d6b7e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
}
.recherche-liste {
    position: absolute;
    z-index: 50;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    max-height: 290px;
    overflow-y: auto;
    margin: 0;
    padding: 4px;
    list-style: none;
    background: var(--blanc);
    border: 1px solid var(--bordure-forte);
    border-radius: 10px;
    box-shadow: var(--ombre-haute);
}
.recherche-liste[hidden] { display: none; }
.recherche-liste li {
    padding: 8px 10px;
    border-radius: 7px;
    font-size: 14px;
    cursor: pointer;
}
.recherche-liste li.actif { background: var(--bleu-pale); color: var(--bleu-fonce); }
.recherche-liste li.choisi { font-weight: 600; }
.recherche-liste li.recherche-vide { color: var(--texte-doux); cursor: default; font-style: italic; }
.filters .recherche-select { min-width: 240px; }
.filters .recherche-select > .form-control { width: 100%; }

/* Livraison de tournee : une quantite et son unite sur une ligne. */
.quantite-mode { display: flex; gap: 8px; align-items: center; }
.quantite-mode input[type="number"] { width: 96px; flex: 0 0 auto; }
.quantite-mode .form-select { width: auto; flex: 0 0 auto; }

/* =============================================================================
   ANALYSE : quoi, lequel, quand - puis « Calculer »
   ========================================================================== */
.segmente {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0 0 18px;
    padding: 4px;
    border: 0;
    border-radius: 10px;
    background: var(--fond);
}
.segmente-choix { position: relative; margin: 0; cursor: pointer; }
.segmente-choix input { position: absolute; opacity: 0; pointer-events: none; }
.segmente-choix span {
    display: block;
    padding: 7px 16px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--texte-doux);
}
.segmente-choix input:checked + span {
    background: var(--blanc);
    color: var(--bleu-fonce);
    box-shadow: var(--ombre-carte);
}
.segmente-choix input:focus-visible + span { outline: 2px solid var(--bleu); outline-offset: 2px; }

.analyse-champs {
    display: grid;
    grid-template-columns: minmax(240px, 2fr) repeat(2, minmax(150px, 1fr)) auto;
    gap: 16px;
    align-items: end;
}
.analyse-champs .field { margin-bottom: 0; }
.analyse-bouton .btn { min-height: 40px; }
.analyse-entreprise { margin: 0; padding: 9px 0; color: var(--texte-doux); }

/* La liste qui ne sert pas disparait. Sans `:has` (navigateur ancien), les
   deux restent visibles : ce n'est que moins net. */
.analyse-form:has(input[value="customer"]:checked) .champ-fournisseur,
.analyse-form:has(input[value="customer"]:checked) .champ-entreprise,
.analyse-form:has(input[value="supplier"]:checked) .champ-client,
.analyse-form:has(input[value="supplier"]:checked) .champ-entreprise,
.analyse-form:has(input[value="company"]:checked) .champ-client,
.analyse-form:has(input[value="company"]:checked) .champ-fournisseur { display: none; }

@media (max-width: 900px) {
    .analyse-champs { grid-template-columns: 1fr 1fr; }
    .analyse-champs > .champ-client,
    .analyse-champs > .champ-fournisseur,
    .analyse-champs > .champ-entreprise,
    .analyse-bouton { grid-column: 1 / -1; }
    .analyse-bouton .btn { width: 100%; }
}

/* =============================================================================
   SAISIE RAPIDE : un tableau qu'on remplit comme une feuille Excel
   ========================================================================== */
.saisie-intro p { margin: 0 0 8px; max-width: 900px; }
.saisie-intro ul { margin: 0 0 18px; padding-left: 18px; max-width: 900px; }
.saisie-entete { max-width: 460px; margin-bottom: 14px; }
.saisie-tableau-cadre { border: 1px solid var(--bordure); border-radius: 10px; }
.saisie-tableau th, .saisie-tableau td { padding: 4px 4px; border-bottom: 1px solid var(--bordure); }
.saisie-tableau th { padding: 9px 6px; }
.saisie-tableau tbody tr:hover { background: transparent; }
.saisie-tableau .form-control,
.saisie-tableau .form-select {
    min-height: 34px;
    padding: 5px 8px;
    border-radius: 6px;
    box-shadow: none;
    font-size: 13.5px;
}
.saisie-tableau .col-num { width: 36px; text-align: center; color: var(--texte-faible); font-size: 12px; }
.saisie-tableau tr.ligne-erreur td { background: var(--rouge-pale); }
.saisie-tableau tr.ligne-erreur-texte td { border-bottom-color: var(--bordure); padding: 2px 8px 8px; background: var(--rouge-pale); }
.saisie-tableau tr.ligne-erreur-texte .error { margin: 0; }
.saisie-tableau tr.ligne-materiel [data-col="format_label"],
.saisie-tableau tr.ligne-materiel [data-col="units_per_lot"],
.saisie-tableau tr.ligne-materiel [data-col="mode"] { opacity: .35; }

/* =============================================================================
   COMMERCIAL : les affaires, les devis, leur signature
   ========================================================================== */
.texte-retard { color: var(--rouge); font-weight: 600; }

/* -- Le pipeline : une colonne par etape, qu'on parcourt de gauche a droite -- */
.pipeline {
    display: grid;
    grid-template-columns: repeat(4, minmax(220px, 1fr));
    gap: 14px;
    overflow-x: auto;
    padding-bottom: 6px;
}
.pipeline-col {
    background: var(--fond-doux);
    border: 1px solid var(--bordure);
    border-radius: var(--radius-lg);
    padding: 10px;
    min-height: 160px;
}
.pipeline-tete {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
    padding: 2px 4px 10px;
}
.pipeline-compte {
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: 999px;
    padding: 0 8px;
    font-size: 12px;
}
.pipeline-montant { margin-left: auto; font-size: 12px; color: var(--texte-doux); }
.pipeline-carte {
    display: flex;
    flex-direction: column;
    gap: 3px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    padding: 10px 12px;
    margin-bottom: 8px;
    color: var(--texte);
    box-shadow: var(--ombre);
}
.pipeline-carte:hover { text-decoration: none; border-color: var(--bleu); }
.pipeline-prix { font-weight: 600; font-size: 13px; }
.pipeline-action {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    color: var(--texte-doux);
}
.pipeline-action svg { width: 13px; height: 13px; flex-shrink: 0; }
.pipeline-action.est-retard { color: var(--rouge); font-weight: 600; }
.pipeline-action.est-jour { color: var(--orange); font-weight: 600; }
.pipeline-action.est-vide { color: var(--texte-faible); font-style: italic; }
.pipeline-vide { text-align: center; color: var(--texte-faible); margin: 18px 0; }

/* -- La fiche d'une affaire --------------------------------------------------- */
.etapes-fil {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    list-style: none;
    margin: 0 0 20px;
    padding: 0;
    gap: 4px;
}
.etapes-fil li {
    min-width: 0;
    text-align: center;
    padding: 8px 6px;
    font-size: 13px;
    line-height: 1.3;
    background: var(--fond-doux);
    border: 1px solid var(--bordure);
    color: var(--texte-doux);
    border-radius: 6px;
}
.etapes-fil li:first-child { border-radius: 999px 6px 6px 999px; }
.etapes-fil li:last-child { border-radius: 6px 999px 999px 6px; }
.etapes-fil li.is-active { background: var(--bleu); border-color: var(--bleu); color: #fff; font-weight: 600; }
.etapes-fil li.is-ok { background: var(--vert); border-color: var(--vert); }
.etapes-fil li.is-off { background: var(--rouge); border-color: var(--rouge); }
@media (max-width: 560px) {
    /* Sur un telephone : trois etapes par rangee, en pastilles. */
    .etapes-fil { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .etapes-fil li, .etapes-fil li:first-child, .etapes-fil li:last-child { border-radius: 999px; font-size: 12px; padding: 6px 4px; }
}

.prochaine-action { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 14px; }
.prochaine-action svg { width: 18px; height: 18px; color: var(--bleu); }


/* -- Prochaine action : l'action, la date, puis la case et les boutons ------ */
.form-relance {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(150px, 190px);
    grid-template-areas:
        "action date"
        "pied pied";
    gap: 12px 14px;
    align-items: end;
}
.form-relance .field { margin: 0; min-width: 0; }
.form-relance .form-control { width: 100%; min-width: 0; }
.form-relance-action { grid-area: action; }
.form-relance-date { grid-area: date; }
.form-relance-pied {
    grid-area: pied;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}
.form-relance-pied .case { margin: 0; }
.form-relance-boutons { display: flex; flex-wrap: wrap; gap: 8px; margin-left: auto; }
.form-relance-boutons .btn-ghost { width: auto; }

/* -- Echanges : le type et le compte rendu cote a cote, etiquettes alignees -- */
.echange-form {
    display: grid;
    grid-template-columns: minmax(150px, 200px) minmax(0, 1fr);
    grid-template-areas:
        "genre texte"
        ". bouton";
    gap: 10px 14px;
    align-items: start;
    margin-bottom: 18px;
}
.echange-form .field { margin: 0; min-width: 0; }
.echange-genre { grid-area: genre; }
.echange-texte { grid-area: texte; }
.echange-bouton { grid-area: bouton; display: flex; justify-content: flex-end; }
.echange-form textarea { min-height: 70px; }

.form-etape .field { margin-bottom: 12px; }

@media (max-width: 640px) {
    .form-relance, .echange-form {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas: none;
    }
    .form-relance > *, .echange-form > * { grid-area: auto; }
    .form-relance-boutons { margin-left: 0; width: 100%; }
    .form-relance-boutons .btn { flex: 1; }
    .echange-bouton .btn { width: 100%; }
}

.historique { list-style: none; margin: 0; padding: 0; }
.historique li { position: relative; padding: 0 0 14px 18px; border-left: 2px solid var(--bordure); margin-left: 6px; }
.historique li::before {
    content: "";
    position: absolute;
    left: -6px;
    top: 4px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--blanc);
    border: 2px solid var(--bordure-forte);
}
.historique li.historique-visite::before,
.historique li.historique-rdv::before { border-color: var(--bleu); }
.historique li.historique-suivi::before { border-color: var(--vert); }
.historique-quand { display: block; font-size: 12px; color: var(--texte-faible); }
.historique-quoi { display: block; font-size: 13px; }
.historique li p { margin: 2px 0 0; }

.fiche-dl { margin: 0; }
.fiche-dl div { display: grid; grid-template-columns: 130px minmax(0, 1fr); gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--bordure); }
.fiche-dl div:last-child { border-bottom: 0; }
.fiche-dl dt { color: var(--texte-doux); font-size: 13px; }
.fiche-dl dd { margin: 0; overflow-wrap: anywhere; }

/* -- L'editeur du devis : ce qu'on vend a gauche, ce que ca rapporte a droite -- */
.devis-editeur {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 20px;
    align-items: start;
}
@media (max-width: 1100px) { .devis-editeur { grid-template-columns: minmax(0, 1fr); } }
.devis-cote { position: sticky; top: 16px; }
.devis-ajout { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--bordure); display: grid; gap: 10px; }
.devis-lignes td { vertical-align: top; }
.devis-lignes td:first-child { min-width: 200px; }
.devis-lignes .num, td.num, th.num { white-space: nowrap; }

.devis-recap-label { display: block; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--texte-doux); }
.devis-recap-prix { display: block; font-size: 28px; line-height: 1.2; margin: 2px 0 6px; font-variant-numeric: tabular-nums; }
.devis-recap-detail { margin: 0; font-size: 13px; }
.devis-recap-detail div { display: flex; justify-content: space-between; gap: 10px; padding: 3px 0; }
.devis-recap-detail dt { color: var(--texte-doux); }
.devis-recap-detail dd { margin: 0; font-variant-numeric: tabular-nums; text-align: right; }
.devis-recap-total { border-top: 1px solid var(--bordure); margin-top: 4px; padding-top: 6px !important; font-weight: 600; }
.devis-recap-marge { font-weight: 700; font-size: 15px; }
.devis-recap hr { border: 0; border-top: 1px solid var(--bordure); margin: 12px 0; }
.devis-recap.card-alerte .devis-recap-marge { color: var(--rouge); }
.devis-recap.est-calcul .devis-recap-prix { opacity: .55; }
.devis-alertes { list-style: none; margin: 10px 0 0; padding: 0; font-size: 12.5px; color: var(--orange); }
.devis-alertes li { display: flex; gap: 6px; align-items: flex-start; margin-bottom: 4px; }
.devis-alertes svg { width: 14px; height: 14px; flex-shrink: 0; margin-top: 2px; }

.ligne-sections { border: 0; margin: 0; padding: 0; min-width: 0; }
.ligne-cahier { margin-top: 32px; }
.ligne-cahier > h2 { margin-bottom: 4px; }
.ligne-retirer { margin-top: 4px; }

.copie-lien { display: flex; gap: 8px; }
.copie-lien .form-control { font-size: 12.5px; min-width: 0; }

.table-compacte { font-size: 13px; }
.table-compacte td { padding: 7px 6px; }

/* -- Le document du devis ------------------------------------------------------ */
.devis-intro { margin: 18px 0 6px; }
.devis-prix tfoot td { border-bottom: 0; padding: 6px 10px; text-align: right; }
.devis-prix tfoot td.num { width: 160px; }
.devis-prix tfoot tr:first-child td { border-top: 2px solid var(--texte); }
.devis-prix .devis-ttc td { font-size: 15px; }
.devis-prix td.num, .devis-prix th.num { text-align: right; white-space: nowrap; }
.devis-cahier-ligne { margin-bottom: 22px; }
.devis-cahier-ligne h3 { font-size: 15px; margin: 14px 0 6px; color: var(--texte); text-transform: none; letter-spacing: 0; }
.devis-cahier-ligne h3 span { font-weight: 400; font-size: 12.5px; color: var(--texte-doux); margin-left: 6px; text-transform: none; letter-spacing: 0; }
@media print {
    .devis-cahier-ligne { page-break-inside: auto; }
    .devis-cahier-ligne h3 { page-break-after: avoid; }
}

/* -- La page publique du devis : plus large que celle d'un signalement -------- */
.public-wrapper.public-large { max-width: 960px; }
.public-signer { margin-top: 20px; }
.public-signer .public-form { max-width: none; }
.public-merci { text-align: center; padding: 34px 24px; }
@media (max-width: 640px) {
    .cdc.devis-doc { padding: 20px 16px; }
    .devis-doc .cdc-head { flex-direction: column; gap: 10px; }
    .devis-doc .cdc-issuer { text-align: left; white-space: normal; }
    .devis-doc .cdc-signs { flex-direction: column; gap: 18px; }
    .devis-doc .cdc-jours { display: none; }
}
@media print {
    .layout-public .public-header, .layout-public .public-footer { display: none; }
    .public-wrapper.public-large { max-width: none; padding: 0; }
}
.devis-doc .cdc-issuer span { display: block; }

/* -- Nouvelle affaire : le charge d'affaires est la personne connectee ------ */
.charge-affaires {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin: 0 0 12px;
    padding: 10px 14px;
    background: var(--fond-doux);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
}

/* =============================================================================
   L'EDITEUR DU DEVIS : ON ECRIT SUR LA FEUILLE
   Les champs ont l'apparence du texte imprime ; ils ne se trahissent qu'au
   survol (un trait pointille) et a la saisie (un fond bleu tres pale).
   ========================================================================== */
.feuille-cadre { min-width: 0; }
.feuille-aide {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    margin: 0 0 12px;
    font-size: 13px;
    color: var(--texte-moyen);
}
.feuille-aide svg { flex-shrink: 0; width: 16px; height: 16px; margin-top: 2px; color: var(--bleu); }
.cdc.feuille { max-width: none; }

.ecrit {
    display: block;
    width: 100%;
    margin: 0;
    padding: 2px 4px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: inherit;
    font: inherit;
    line-height: inherit;
    resize: none;
    overflow: hidden;
    box-shadow: inset 0 -1px 0 transparent;
    transition: background .12s, box-shadow .12s;
    field-sizing: content;
}
.ecrit::placeholder { color: var(--texte-faible); font-style: italic; font-weight: 400; }
.ecrit:hover { box-shadow: inset 0 -1px 0 var(--bordure-forte); }
.ecrit:focus { outline: none; background: var(--bleu-pale); box-shadow: inset 0 -2px 0 var(--bleu); }
.ecrit-titre { font-size: 26px; font-weight: 700; line-height: 1.25; margin: 4px 0 0 -4px; letter-spacing: -.01em; }
.ecrit-designation { font-weight: 600; margin-left: -4px; }
.ecrit-description { font-size: 12.5px; color: var(--texte-doux); margin-left: -4px; min-height: 22px; }
.ecrit-paragraphe { margin-left: -4px; min-height: 26px; }
.ecrit-date { display: inline-block; width: auto; font-weight: 600; padding: 0 4px; }
.ecrit-nombre { display: inline-block; width: 3.6em; text-align: center; font-weight: 600; padding: 0 2px; }
.ecrit-case { display: inline-flex; align-items: center; gap: 4px; }
.ecrit-prix-cadre { display: inline-flex; align-items: baseline; gap: 2px; justify-content: flex-end; }
.ecrit-prix { display: inline-block; width: 6.5em; text-align: right; font-variant-numeric: tabular-nums; }

.feuille-lignes td { position: relative; }
.feuille-prix { white-space: nowrap; }
.feuille-conseil { display: block; font-size: 11px; color: var(--orange); white-space: normal; }
.feuille-a-chiffrer a { font-size: 12px; color: var(--rouge); font-weight: 600; }
.feuille-texte td { padding-top: 12px; padding-bottom: 12px; }
.lien-bouton {
    border: 0;
    background: none;
    padding: 0;
    color: var(--bleu);
    font: inherit;
    text-decoration: underline;
    cursor: pointer;
}

/* Les commandes d'une ligne : discretes, elles apparaissent nettement au survol. */
.feuille-outils {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 6px;
    opacity: .55;
    transition: opacity .12s;
}
tr:hover .feuille-outils, .feuille-outils:focus-within { opacity: 1; }
.feuille-outil {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border: 1px solid var(--bordure);
    border-radius: 999px;
    background: var(--blanc);
    color: var(--texte-moyen);
    font: inherit;
    font-size: 11.5px;
    line-height: 1.6;
    cursor: pointer;
    text-decoration: none;
}
.feuille-outil:hover { border-color: var(--bleu); color: var(--bleu); text-decoration: none; }
.feuille-outil svg { width: 12px; height: 12px; }
.feuille-outil-fort { border-color: var(--bleu); color: var(--bleu); background: var(--bleu-pale); }
.feuille-outil-danger:hover { border-color: var(--rouge); color: var(--rouge); }

.feuille-ajout {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    margin: 12px 0 4px;
    padding: 10px;
    border: 1px dashed var(--bordure-forte);
    border-radius: var(--radius);
    background: var(--fond-doux);
}
.feuille-ajout-choix { display: flex; gap: 8px; flex: 1 1 320px; min-width: 0; }
.feuille-ajout-choix .recherche-select, .feuille-ajout-choix select { flex: 1; min-width: 0; }
.devis-duree { margin-top: 14px; }
.devis-annexe { margin-top: 6px; padding: 8px 12px; background: var(--fond-doux); border-radius: 6px; }
.devis-unique td { font-size: 13.5px; }
.devis-texte-ligne { white-space: normal; }

/* -- L'etat de l'enregistrement, en tete du panneau ------------------------ */
.enregistrement {
    margin: 0 0 10px;
    padding: 6px 10px;
    border-radius: 999px;
    font-size: 12.5px;
    background: var(--vert-pale);
    color: var(--vert);
    text-align: center;
}
.enregistrement.est-en-cours { background: var(--fond-doux); color: var(--texte-doux); }
.enregistrement.est-erreur { background: var(--rouge-pale); color: var(--rouge); }

.hypotheses { display: grid; gap: 8px; margin-bottom: 8px; }
.hypotheses label { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 13px; }
.hypotheses label span { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; color: var(--texte-doux); }
.hypotheses .form-control { width: 5.5em; padding: 4px 8px; min-height: 32px; text-align: right; }

@media print {
    .feuille-outils, .feuille-ajout, .feuille-aide, .feuille-conseil, .feuille-a-chiffrer { display: none !important; }
    .ecrit { box-shadow: none !important; background: none !important; }
}
@media (max-width: 640px) {
    .ecrit-titre { font-size: 21px; }
    .feuille-ajout-choix { flex-basis: 100%; }
}

/* Un element masque par `hidden` le reste, meme quand une regle lui donne un
   `display` (une ligne de recapitulatif en flex, une mention en block). */
.devis-editeur [hidden], .feuille [hidden] { display: none !important; }

/* =============================================================================
   LE TABLEAU DES COUTS (chiffrage d'une prestation, prestation type)
   Une grille plutot qu'une table : sur un ecran etroit, chaque cout passe sur
   deux lignes sans ascenseur horizontal.
   ========================================================================== */
.couts [hidden] { display: none !important; }
/* Trois temps par cout : CE QUE C'EST (nature, article du stock ou
   designation), COMBIEN (quantite - a l'unite ou au lot -, cout, rythme), et
   CE QUE CA FAIT dans le prix - avec, pour un achat, le nombre de mois sur
   lequel il est reparti. */
.cout-ligne {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr) minmax(0, 1.25fr) 34px;
    grid-template-areas:
        "genre article libelle retirer"
        "quantite unitaire rythme ."
        "etalement etalement resultat resultat";
    gap: 8px 10px;
    align-items: end;
    padding: 12px 0;
    border-bottom: 1px solid var(--bordure);
}
.cout-ligne:first-child { border-top: 1px solid var(--bordure); }
.cout-genre { grid-area: genre; }
.cout-article { grid-area: article; }
.cout-libelle { grid-area: libelle; }
.cout-retirer { grid-area: retirer; justify-self: end; }
.cout-quantite { grid-area: quantite; }
.cout-unitaire { grid-area: unitaire; }
.cout-rythme { grid-area: rythme; }
.cout-etalement { grid-area: etalement; }
.cout-resultat { grid-area: resultat; }
.cout-etiquette { display: block; margin-bottom: 3px; font-size: 11px; font-weight: 600; color: var(--texte-doux); }
.cout-ligne .form-control, .cout-ligne .form-select { min-height: 36px; padding: 6px 9px; font-size: 13.5px; width: 100%; }
.cout-euro { display: flex; align-items: center; gap: 4px; }
.cout-euro span { color: var(--texte-doux); }
/* La quantite et, pour un produit vendu en lots, « a l'unite / au lot ». */
.cout-quantite-ligne { display: flex; gap: 6px; }
.cout-quantite-ligne > .form-control { flex: 1 1 3em; min-width: 3em; }
.cout-lot { flex: 0 0 auto; }
.cout-ligne .cout-lot .form-select { width: auto; padding-right: 26px; }
.cout-etalement { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 12.5px; align-self: center; }
.cout-etalement label { margin: 0; font-weight: 600; }
.cout-etalement .form-control { width: 4.5em; min-height: 30px; padding: 3px 6px; }
.cout-resultat { font-weight: 700; font-size: 13.5px; white-space: nowrap; text-align: right; align-self: center; }
.cout-retirer-case {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    border-radius: 50%;
    cursor: pointer;
    color: var(--texte-faible);
}
.cout-retirer-case input { position: absolute; opacity: 0; pointer-events: none; }
.cout-retirer-case:hover { color: var(--rouge); background: var(--rouge-pale); }
.cout-ligne.est-retiree > :not(.cout-retirer) { opacity: .35; text-decoration: line-through; }
.cout-ligne.est-retiree .cout-retirer-case { color: var(--rouge); }
.cout-erreurs { grid-column: 1 / -1; }
.cout-erreur { background: var(--rouge-pale); }
.couts-vide { margin: 12px 0; color: var(--texte-doux); font-size: 13px; }
.couts [data-cout-ajouter] { margin-top: 12px; }
@media (max-width: 700px) {
    .cout-ligne {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 34px;
        grid-template-areas:
            "genre genre retirer"
            "article article article"
            "libelle libelle libelle"
            "quantite quantite quantite"
            "unitaire rythme rythme"
            "etalement etalement etalement"
            "resultat resultat resultat";
    }
}

/* =============================================================================
   LE CAHIER DES CHARGES DU DEVIS - un document a part, fait pour etre lu
   ========================================================================== */
.cahier-doc [hidden] { display: none !important; }
.cahier-sommaire td { vertical-align: middle; }
.cahier-lien { color: inherit; }
.cahier-lecture {
    margin: 12px 0 0;
    padding: 10px 14px;
    border-left: 3px solid var(--bleu);
    background: var(--bleu-pale);
    border-radius: 0 6px 6px 0;
    font-size: 12.5px;
    line-height: 1.6;
}
.cahier-lecture .jour { display: inline-flex; vertical-align: middle; }

.cahier-prestation { margin-top: 30px; page-break-inside: auto; }
.cahier-prestation-tete {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    padding-bottom: 10px;
    border-bottom: 2px solid var(--texte);
    page-break-after: avoid;
}
.cahier-numero {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--bleu);
    color: #fff;
    font-weight: 700;
    font-size: 15px;
}
.cahier-prestation-tete h2 { margin: 2px 0 6px; font-size: 18px; }
.cahier-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; list-style: none; margin: 0; padding: 0; font-size: 13px; color: var(--texte-moyen); }
.cahier-meta li { display: inline-flex; align-items: center; gap: 6px; }
.cahier-meta svg { width: 15px; height: 15px; color: var(--bleu); }
.cahier-texte { margin: 12px 0 0; font-size: 13.5px; }
.cahier-texte-form { margin-top: 10px; position: relative; }
.cahier-texte-form.est-en-cours textarea { background: var(--fond-doux); }
.cahier-texte-form.est-erreur textarea { box-shadow: inset 0 -2px 0 var(--rouge); }

.cahier-zone {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin: 18px 0 4px;
    padding-bottom: 4px;
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--bleu-fonce);
    border-bottom: 1px solid var(--bleu);
    page-break-after: avoid;
}
.cahier-zone span { font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--texte-doux); }
.cahier-taches { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.cahier-taches td { padding: 8px 6px; border-bottom: 1px solid #eef1f5; vertical-align: top; }
.cahier-taches tr { page-break-inside: avoid; }
.cahier-coche { width: 22px; }
.cahier-coche span { display: inline-block; width: 13px; height: 13px; margin-top: 3px; border: 1.5px solid var(--bordure-forte); border-radius: 3px; }
.cahier-tache { width: auto; }
.cahier-rythme { width: 150px; font-size: 12.5px; color: var(--texte-doux); white-space: nowrap; }
.cahier-rythme.est-propre { color: var(--bleu-fonce); font-weight: 600; }
.cahier-commande { width: 1%; white-space: nowrap; }
.cahier-vide { margin: 12px 0; padding: 12px; border: 1px dashed var(--bordure-forte); border-radius: 6px; color: var(--texte-doux); font-size: 13px; }

.cahier-ajout {
    margin-top: 12px;
    padding: 12px;
    border: 1px dashed var(--bordure-forte);
    border-radius: var(--radius);
    background: var(--fond-doux);
    display: grid;
    gap: 10px;
}
.cahier-ajout-ligne { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.cahier-ajout-tache { flex: 2 1 240px; }
.cahier-ajout-zone { flex: 1 1 150px; }
.cahier-ajout-rythme { flex: 1 1 170px; }
.cahier-ajout-precision { flex: 2 1 240px; }
.cahier-ajout .form-control, .cahier-ajout .form-select { min-height: 36px; padding: 6px 9px; font-size: 13.5px; width: 100%; }
.cahier-ajout textarea.form-control { min-height: 36px; }
.cahier-ajout-jours ul, .cahier-ajout-jours div { display: flex; flex-wrap: wrap; gap: 4px 10px; margin: 0; padding: 0; list-style: none; font-size: 12.5px; }
.cahier-ajout-jours label { display: inline-flex; align-items: center; gap: 4px; font-weight: 400; }
.public-retour { display: flex; flex-wrap: wrap; gap: 8px; justify-content: space-between; }

@media print {
    .cahier-ajout, .cahier-commande, .cahier-texte-form textarea::placeholder { display: none !important; }
    .cahier-numero { background: #fff !important; color: #000 !important; border: 2px solid #000; }
    .cahier-lecture { background: #fff !important; }
}
@media (max-width: 640px) {
    .cahier-rythme { width: auto; white-space: normal; }
    .cahier-taches .cdc-jours { display: none; }
}

/* Sur un telephone, une ligne du devis s'empile : la designation, puis la
   frequence et le prix. Trois colonnes de 120 px ne laissaient au prix que
   le bord de l'ecran - c'est pourtant ce que le client cherche. */
@media (max-width: 640px) {
    .devis-doc .devis-prix thead { display: none; }
    .devis-doc .devis-prix,
    .devis-doc .devis-prix tbody,
    .devis-doc .devis-prix tfoot,
    .devis-doc .devis-prix tr,
    .devis-doc .devis-prix td { display: block; width: 100%; }
    .devis-doc .devis-prix tbody tr { padding: 10px 0; border-bottom: 1px solid var(--bordure); }
    .devis-doc .devis-prix tbody td { border: 0; padding: 2px 0; }
    .devis-doc .devis-prix tbody td.num { text-align: left; font-weight: 600; }
    .devis-doc .devis-prix .ecrit-prix-cadre { justify-content: flex-start; }
    .devis-doc .devis-prix .ecrit-prix { text-align: left; }
    .devis-doc .devis-prix tfoot tr { display: flex; justify-content: space-between; gap: 10px; }
    .devis-doc .devis-prix tfoot td { width: auto; padding: 4px 0; border: 0; }
    .devis-doc .devis-prix tfoot tr:first-child { border-top: 2px solid var(--texte); }
    .devis-doc .devis-prix tfoot tr:first-child td { border-top: 0; }
}

/* =============================================================================
   L'ETAT EN DIRECT D'UN AGENT (boitier « intervention »)
   Une pastille : une couleur qui dit quoi faire, une phrase qui dit pourquoi.
   ========================================================================== */
.etat-pastille {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 3px 10px 3px 8px;
    border-radius: 999px;
    font-size: 12.5px; font-weight: 600; line-height: 1.4;
    background: var(--fond-doux); color: var(--texte-moyen);
    border: 1px solid var(--bordure);
    white-space: nowrap;
}
td .etat-pastille { white-space: normal; }
.etat-point { width: 9px; height: 9px; border-radius: 50%; background: var(--texte-faible); flex: none; }
.etat-bouge { background: var(--vert-pale); color: var(--vert); border-color: #b9e2cc; }
.etat-bouge .etat-point { background: var(--vert); }
.etat-arret { background: var(--orange-pale); color: #8a5200; border-color: #f0d9ab; }
.etat-arret .etat-point { background: var(--orange); }
.etat-immobile, .etat-sos, .etat-alarme { background: var(--rouge-pale); color: var(--rouge); border-color: #f3c3bf; }
.etat-immobile .etat-point, .etat-sos .etat-point, .etat-alarme .etat-point {
    background: var(--rouge);
    animation: etat-clignote 1.2s ease-in-out infinite;
}
.etat-silence { background: #2b3240; color: #fff; border-color: #2b3240; }
.etat-silence .etat-point { background: #ff8a80; animation: etat-clignote 1.2s ease-in-out infinite; }
.etat-batterie { background: var(--orange-pale); color: #8a5200; border-color: #f0d9ab; }
.etat-batterie .etat-point { background: var(--orange); }
.etat-pointage, .etat-allumage { background: var(--bleu-pale); color: var(--bleu-fonce); border-color: #c9dcef; }
.etat-pointage .etat-point, .etat-allumage .etat-point { background: var(--bleu); }
@keyframes etat-clignote { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
    .etat-point { animation: none !important; }
}

/* Les agents sur le terrain : une ligne par personne, la pastille d'abord. */
.terrain-liste { list-style: none; margin: 0; padding: 0; }
.terrain-ligne {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) auto minmax(0, 1fr) auto;
    gap: 6px 14px; align-items: center;
    padding: 11px 0; border-top: 1px solid var(--bordure);
}
.terrain-ligne:first-child { border-top: none; }
.terrain-ligne.est-urgent { background: linear-gradient(90deg, var(--rouge-pale), transparent 60%); padding-left: 8px; border-radius: 6px; }
.terrain-qui strong { display: block; }
.terrain-detail { font-size: 12.5px; color: var(--texte-doux); }
.terrain-actions { justify-self: end; }
@media (max-width: 760px) {
    /* Sur un telephone, tout s'empile : le nom, la pastille, le detail. */
    .terrain-ligne { grid-template-columns: minmax(0, 1fr); gap: 6px; }
    .terrain-qui strong { display: inline; margin-right: 6px; }
    .terrain-ligne .etat-pastille { justify-self: start; }
    .terrain-actions { justify-self: start; }
}

/* La legende « que veulent dire ces signaux ? » */
.legende-signaux summary { cursor: pointer; }
.legende-signaux h3 { margin: 16px 0 8px; font-size: 13px; text-transform: uppercase; letter-spacing: .04em; color: var(--texte-doux); }
.legende-liste { margin: 0; display: grid; gap: 8px; }
.legende-liste > div { display: grid; grid-template-columns: minmax(150px, 260px) minmax(0, 1fr); gap: 4px 14px; align-items: start; }
.legende-liste dt { margin: 0; }
.legende-liste dd { margin: 0; font-size: 13px; color: var(--texte-moyen); }
@media (max-width: 640px) {
    .legende-liste > div { grid-template-columns: minmax(0, 1fr); }
}

/* Le fil des signaux d'un boitier */
.fil-signaux { list-style: none; margin: 0; padding: 0; }
.fil-signal {
    display: grid; grid-template-columns: 56px minmax(0, 1fr);
    gap: 4px 14px; padding: 10px 0; border-top: 1px solid var(--bordure);
}
.fil-signal:first-child { border-top: none; }
.fil-heure { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--texte-moyen); padding-top: 3px; }
.fil-texte .etat-pastille { white-space: normal; }
.fil-explication { margin-top: 4px; font-size: 12.5px; color: var(--texte-doux); }

/* =============================================================================
   BARRE DE FILTRES (templates/includes/filtres.html)
   Les champs sur une ligne, alignes PAR LE BAS : libelles au-dessus, champs
   et bouton sur la meme ligne de base, quel que soit le nombre de champs.
   ========================================================================== */
.filtre-carte { padding: 14px 16px; margin-bottom: 16px; }
.filtre-barre {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px 14px;
}
.filtre-champ { display: flex; flex-direction: column; gap: 6px; min-width: 150px; flex: 0 1 180px; }
.filtre-champ > label { font-size: 12px; font-weight: 600; color: var(--texte-doux); text-transform: uppercase; letter-spacing: .03em; margin: 0; }
.filtre-champ .form-control, .filtre-champ .form-select { width: 100%; min-width: 0; height: 40px; }
.filtre-champ.filtre-q { flex: 1 1 260px; }
.filtre-champ input[type="search"] {
    padding-left: 36px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238a96a8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 12px center;
}
.filtre-actions { display: flex; gap: 8px; align-items: center; height: 40px; }
@media (max-width: 640px) {
    .filtre-champ, .filtre-champ.filtre-q { flex: 1 1 100%; }
    .filtre-actions { width: 100%; }
    .filtre-actions .btn { flex: 1; justify-content: center; }
}

/* =============================================================================
   LA LISTE DES BONS
   ========================================================================== */
.bons-resume {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 12px;
    margin-bottom: 16px;
}
.bons-chiffre {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 12px 18px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-left: 4px solid var(--orange);
    border-radius: var(--radius);
    box-shadow: var(--ombre-carte);
}
.bons-chiffre.est-ok { border-left-color: var(--vert); }
.bons-chiffre-valeur { font-size: 24px; font-weight: 700; line-height: 1; }
.bons-chiffre-libelle { color: var(--texte-doux); font-size: 14px; }
.bons-rappel { align-self: center; margin: 0; flex: 1 1 260px; }
.bons-numero { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.bons-date { white-space: nowrap; font-variant-numeric: tabular-nums; }
.bons-actions { white-space: nowrap; text-align: right; }
.bons-actions .btn + .btn { margin-left: 4px; }
.bons-table .badge .icone { width: 12px; height: 12px; }
.card-tableau { padding: 0; overflow: hidden; }
.card-tableau .table-wrapper { margin: 0; }

/* =============================================================================
   LES HEURES (templates/planning/hours*.html)
   ========================================================================== */
.card-tableau > p { padding: 0 16px 14px; margin: 10px 0 0; }
.heures-barre { padding: 14px 16px; margin-bottom: 10px; }
.heures-barre-ligne {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px 18px;
}
.heures-barre .heures-raccourcis { margin: 0; }
.segmente-lien {
    display: block;
    padding: 7px 14px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--texte-doux);
    text-decoration: none;
}
.segmente-lien:hover { color: var(--texte); text-decoration: none; }
.segmente-lien.est-actif { background: var(--blanc); color: var(--bleu-fonce); box-shadow: var(--ombre-carte); }
.heures-dates { display: flex; flex-wrap: nowrap; align-items: flex-end; gap: 10px 12px; flex: 0 0 auto; }
.heures-dates .filtre-champ { flex: 0 0 170px; min-width: 0; }
@media (max-width: 640px) {
    .heures-dates { flex: 1 1 100%; flex-wrap: wrap; }
    .heures-dates .filtre-champ { flex: 1 1 140px; }
    .heures-dates .filtre-actions { width: 100%; }
    .heures-dates .filtre-actions .btn { flex: 1; justify-content: center; }
}
.heures-barre .heures-salaries { margin-top: 12px; }
.heures-barre .heures-salaries summary { cursor: pointer; font-size: 14px; }
.heures-periode-texte { margin: 4px 0 14px; color: var(--texte-doux); font-size: 14px; }

.heures-chiffres {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
    margin-bottom: 14px;
}
.heures-chiffre {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 14px 16px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre-carte);
}
.heures-chiffre.est-principal { border-top: 3px solid var(--bleu); }
.heures-chiffre.est-ecart { border-top: 3px solid var(--orange); }
.heures-chiffre-libelle { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; color: var(--texte-doux); }
.heures-chiffre-valeur { font-size: 26px; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.heures-chiffre-detail { font-size: 13px; color: var(--texte-doux); }

.heures-jauge {
    display: inline-block;
    width: 100%;
    max-width: 140px;
    height: 6px;
    border-radius: 3px;
    background: var(--fond);
    overflow: hidden;
    vertical-align: middle;
}
.heures-jauge > span { display: block; height: 100%; background: var(--vert); border-radius: 3px; }
.heures-pointe { display: inline-flex; align-items: center; gap: 8px; min-width: 140px; }
.heures-pointe .heures-jauge { width: 80px; }

.heures-lecture {
    padding: 12px 16px;
    margin-bottom: 14px;
    border-radius: var(--radius);
    background: var(--bleu-pale);
    color: var(--texte-moyen);
    font-size: 14px;
}
.heures-lecture ul { margin: 6px 0 0; padding-left: 18px; }

.heures-table th.num, .heures-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.heures-table tfoot td { border-top: 2px solid var(--bordure-forte); background: var(--fond-doux); }
@media (max-width: 720px) {
    .heures-table th.num, .heures-table td.num { text-align: left; }
}

/* « A pourvoir » dans la bande « a definir » quand on regarde quelqu'un. */
.cal-undated-libre {
    display: inline-block;
    margin-top: 2px;
    padding: 0 5px;
    border-radius: 3px;
    background: var(--orange-pale);
    color: #8a5200;
    font-style: normal;
    font-size: 10px;
    font-weight: 600;
}

/* =============================================================================
   VUE « EQUIPE » : une ligne par collaborateur, une colonne par jour
   ========================================================================== */
.eqs-cadre {
    overflow: auto;
    max-height: calc(100vh - 230px);
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
}
.eqs {
    width: 100%;
    min-width: 980px;
    border-collapse: separate;
    border-spacing: 0;
    table-layout: fixed;
    margin: 0;
}
.eqs th, .eqs td { border-bottom: 1px solid var(--bordure); border-right: 1px solid var(--bordure); vertical-align: top; }
.eqs thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--fond-doux);
    padding: 8px 6px;
    font-size: 12px;
    text-align: center;
}
.eqs .eqs-coin { width: 170px; text-align: left; left: 0; z-index: 4; }
.eqs-jour span { display: block; color: var(--texte-doux); font-weight: 500; text-transform: capitalize; }
.eqs-jour strong { font-size: 14px; }
.eqs-jour.is-today { background: var(--bleu-pale); color: var(--bleu-fonce); }
.eqs-total-tete, .eqs-total { width: 84px; text-align: center; }
.eqs-nom {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--blanc);
    padding: 8px 10px;
    text-align: left;
    font-size: 13px;
}
.eqs-nom strong { display: block; line-height: 1.25; }
.eqs-nom span { display: block; font-size: 11px; color: var(--texte-doux); font-weight: 400; }
.eqs-ligne.est-a-pourvoir .eqs-nom { background: var(--orange-pale); }
.eqs-ligne.est-a-pourvoir .eqs-case { background: #fffaf1; }
.eqs-case {
    padding: 4px;
    min-height: 64px;
    height: 64px;
    font-size: 11px;
    transition: background .1s;
}
.eqs-case.is-weekend { background: var(--fond-doux); }
.eqs-case.est-absent {
    background: repeating-linear-gradient(135deg, #f5f6f8, #f5f6f8 6px, #eceef2 6px, #eceef2 12px);
}
.eqs-case.is-drop-target { background: var(--bleu-pale); outline: 2px dashed var(--bleu); outline-offset: -3px; }
.eqs-absence {
    display: block;
    margin-bottom: 3px;
    color: var(--texte-doux);
    font-weight: 600;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .03em;
}
.eqs-heures { display: block; margin-top: 2px; text-align: right; color: var(--texte-doux); font-weight: 600; font-size: 11px; }
.eqs-total { padding: 8px 6px; font-size: 13px; vertical-align: middle !important; background: var(--fond-doux); }
.eqs-carte {
    display: block;
    margin-bottom: 4px;
    padding: 4px 6px;
    border-radius: 5px;
    border-left: 3px solid var(--bleu);
    background: #eef4fc;
    color: var(--texte);
    line-height: 1.25;
    overflow: hidden;
    cursor: grab;
    user-select: none;
}
.eqs-carte:hover { text-decoration: none; filter: brightness(.97); }
.eqs-carte:not([data-equipe-move]) { cursor: pointer; }
.eqs-carte strong, .eqs-carte-presta, .eqs-carte-heure {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.eqs-carte-heure { font-weight: 600; color: var(--texte-moyen); font-variant-numeric: tabular-nums; }
.eqs-carte-presta { color: var(--texte-doux); }
.eqs-carte.status-PLANNED { border-left-color: #d99b1c; background: #fff8ec; }
.eqs-carte.status-DONE { border-left-color: #2f9e5f; background: #f1faf5; }
.eqs-carte.is-saving { opacity: .5; }
.eqs-carte.is-dragging { opacity: .35; }
.eqs-carte.status-INPROGRESS { border-left-color: #7a4fbf; background: #f4effc; }

/* =============================================================================
   POINTAGE : la journee, les alertes, les boitiers (retours de novembre)
   ========================================================================== */
.pointage-jour {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 16px;
}
.pointage-jour .form-control { width: auto; min-width: 170px; height: 38px; }
.pointage-chiffres { margin-bottom: 20px; }

/* Une alerte : le texte a gauche, « ce qui a ete fait » a droite. */
.alerte-item { gap: 10px 20px; align-items: center; }
.alerte-texte { flex: 1 1 420px; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.alerte-tete { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 2px; }
.alerte-form { flex: 0 1 420px; flex-wrap: nowrap; }
.alerte-form .form-control { flex: 1 1 auto; min-width: 0; }
.alerte-form .btn { white-space: nowrap; }
@media (max-width: 720px) {
    /* En colonne, une base de 420 px deviendrait une HAUTEUR de 420 px. */
    .alerte-texte { flex: 0 0 auto; }
    .alerte-item { align-items: stretch; }
    .alerte-form { flex: 0 0 auto; flex-wrap: wrap; }
    .alerte-form .btn { width: 100%; justify-content: center; }
}

/* Les pointages manquants : une ligne chacun. */
.oublis { list-style: none; margin: 0; padding: 0; }
.oubli {
    display: grid;
    grid-template-columns: 56px 150px minmax(0, 1fr) minmax(0, 1.2fr) auto;
    gap: 6px 14px;
    align-items: center;
    padding: 9px 12px;
    border-top: 1px solid var(--bordure);
    background: #fdf8ef;
}
.oubli:first-child { border-top: 0; border-radius: 8px 8px 0 0; }
.oubli:last-child { border-radius: 0 0 8px 8px; }
.oubli-heure { font-weight: 700; font-variant-numeric: tabular-nums; }
.oubli-qui, .oubli-ou { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.oubli .badge { justify-self: start; }
.oublis-suite { margin-top: 8px; }
.oublis-suite > summary { cursor: pointer; padding: 8px 0; font-weight: 600; color: var(--bleu); }
@media (max-width: 720px) {
    .oubli {
        grid-template-columns: 48px minmax(0, 1fr) auto;
        grid-template-areas: "heure qui action" "heure badge action" "heure ou action";
        row-gap: 2px;
    }
    .oubli-heure { grid-area: heure; }
    .oubli-qui { grid-area: qui; }
    .oubli .badge { grid-area: badge; }
    .oubli-ou { grid-area: ou; font-size: 13px; }
    .oubli-action { grid-area: action; }
}

/* Boitiers : les deux boutons de la ligne, et la fenetre « Modifier ». */
.affectation-cellule { text-align: right; white-space: nowrap; }
.affectation-actions { display: inline-flex; gap: 6px; }
@media (max-width: 720px) {
    .affectation-cellule { text-align: left; }
}

/* -----------------------------------------------------------------------------
   LA FENETRE (MODALE). Un <dialog> : le navigateur gere le fond grise, la
   touche Echap et le focus. Sur un telephone, elle prend toute la largeur.
   -------------------------------------------------------------------------- */
.modale {
    width: min(520px, calc(100vw - 24px));
    max-height: calc(100vh - 32px);
    padding: 0;
    border: 0;
    border-radius: var(--radius-lg);
    box-shadow: 0 24px 60px rgba(16, 24, 40, .28);
    color: var(--texte);
    overflow: visible;
}
.modale::backdrop { background: rgba(12, 20, 28, .55); }
/* Ouverte sans JavaScript (`open` pose par la page) : on la centre quand meme. */
.modale[open]:not(:modal) {
    position: fixed;
    inset: 0;
    z-index: 1000;
    margin: auto;
    height: fit-content;
}
.modale-boite { display: flex; flex-direction: column; max-height: calc(100vh - 32px); }
.modale-tete {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 18px 20px 12px;
    border-bottom: 1px solid var(--bordure);
}
.modale-tete h2 { margin: 0 0 2px; font-size: 18px; }
.modale-tete p { margin: 0; }
.modale-fermer {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 8px;
    color: var(--texte-doux);
    font-size: 22px;
    line-height: 1;
    text-decoration: none;
}
.modale-fermer:hover { background: var(--fond); color: var(--texte); text-decoration: none; }
.modale-corps {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 16px 20px;
    overflow-y: auto;
}
.modale-etiquette { display: block; margin: 6px 0 2px; font-size: 13.5px; font-weight: 600; color: var(--texte-moyen); }
.modale-choix { display: grid; gap: 8px; margin: 8px 0 0; padding: 0; border: 0; min-width: 0; }
.modale-choix legend { padding: 0; }
.choix-carte {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--bordure-forte);
    border-radius: var(--radius);
    cursor: pointer;
}
.choix-carte:hover { background: var(--fond-doux); }
.choix-carte:has(input:checked) { border-color: var(--bleu); background: var(--bleu-pale); }
.choix-carte input { margin-top: 3px; }
.choix-carte > span { display: flex; flex-direction: column; gap: 2px; }
.modale-site[hidden], .modale-pied .btn[hidden] { display: none; }
.modale-retirer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 10px;
    padding: 10px 12px;
    border: 1px dashed var(--bordure-forte);
    border-radius: var(--radius);
}
.modale-retirer[hidden] { display: none; }
.modale-aide { margin: 10px 0 0; padding: 10px 12px; border-radius: var(--radius); background: var(--fond-doux); }
.modale-pied {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 20px 18px;
    border-top: 1px solid var(--bordure);
}
@media (max-width: 520px) {
    .modale-pied { flex-direction: column-reverse; }
    .modale-pied .btn { width: 100%; justify-content: center; }
}

/* =============================================================================
   RENTABILITE (templates/costing/index.html)
   ========================================================================== */
.renta-choix { padding: 16px 20px; }
.renta-choix-titre { font-size: 15px; margin: 0 0 12px; }
.renta-choix-champs { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 16px; }
.renta-choix-champs .filtre-champ { flex: 1 1 280px; }
.renta-choix-champs .recherche-select { width: 100%; }
.renta-etapes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px;
    margin-bottom: 20px;
}
.renta-etape {
    padding: 16px 18px;
    background: var(--blanc);
    border: 1px dashed var(--bordure-forte);
    border-radius: var(--radius);
}
.renta-etape strong { display: block; margin: 8px 0 4px; }
.renta-etape p { margin: 0; font-size: 13px; color: var(--texte-doux); }
.renta-etape-num {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; border-radius: 50%;
    background: var(--bleu-pale); color: var(--bleu-fonce); font-weight: 700;
}
.renta-entete {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin: 6px 0 12px;
}
.renta-entete h2 { margin: 0; font-size: 22px; }
.renta-entete p { margin: 4px 0 0; }
.renta-chiffres {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 12px;
    margin-bottom: 12px;
}
.renta-chiffre {
    display: flex; flex-direction: column; gap: 4px;
    padding: 14px 16px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre-carte);
}
.renta-chiffre.est-principal { border-top: 3px solid var(--bleu); }
.renta-chiffre-libelle { font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; color: var(--texte-doux); }
.renta-chiffre-valeur { font-size: 22px; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.renta-chiffre-detail { font-size: 13px; color: var(--texte-doux); }
.renta-prevu {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 12px 16px;
    margin-bottom: 20px;
    border-radius: var(--radius);
    background: var(--bleu-pale);
    color: var(--texte-moyen);
    font-size: 14px;
}
.renta-prevu.est-depasse { background: var(--orange-pale); }
.renta-prevu .icone { flex: 0 0 auto; margin-top: 2px; }
.renta-deux {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    gap: 0 20px;
    align-items: start;
}
.renta-estime { margin-left: 6px; font-size: 11px; font-weight: 600; color: #8a5200; white-space: nowrap; }
.renta-table { width: 100%; margin: 0; }
.renta-table th.num, .renta-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.renta-table tfoot td { border-top: 2px solid var(--bordure-forte); background: var(--fond-doux); }
.renta-table tr.est-vide td { color: var(--texte-faible); }
.renta-part { display: flex; align-items: center; gap: 8px; min-width: 110px; font-size: 12px; color: var(--texte-doux); }
.renta-jauge { flex: 1 1 auto; height: 6px; border-radius: 3px; background: var(--fond); overflow: hidden; }
.renta-jauge > span { display: block; height: 100%; background: var(--bleu); border-radius: 3px; }
.renta-tableau-titre { padding: 16px 16px 4px; margin: 0; }
.renta-section { margin: 26px 0 12px; font-size: 17px; }
.renta-detail { padding: 0; }
.renta-detail > summary {
    display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 14px;
    padding: 14px 18px; cursor: pointer;
}
.renta-detail[open] > summary { border-bottom: 1px solid var(--bordure); }
.renta-detail > :not(summary) { margin-left: 18px; margin-right: 18px; }
.renta-detail > h3 { margin-top: 16px; font-size: 14px; }
.renta-detail > :last-child { margin-bottom: 16px; }
.renta-detail-resume { color: var(--texte-doux); font-size: 13px; font-variant-numeric: tabular-nums; }
.renta-a-savoir {
    margin-top: 24px;
    padding: 16px 20px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: var(--fond-doux);
    font-size: 14px;
    color: var(--texte-moyen);
}
.renta-a-savoir h3 { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; font-size: 14px; }
.renta-a-savoir ul { margin: 0; padding-left: 18px; }
.renta-a-savoir li + li { margin-top: 6px; }
@media (max-width: 640px) {
    .renta-deux { grid-template-columns: 1fr; }
    .renta-entete { flex-direction: column; }
    .renta-table th.num, .renta-table td.num { text-align: left; }
}

/* Pointage : le boitier dont le message du bouton n'arrive pas. */
.bouton-muet { display: flex; flex-direction: column; gap: 4px; margin: 6px 0; color: #8a5200; max-width: 280px; }

/* Eteint HORS intervention : calme, rien a faire (le gris, pas l'alerte). */
.etat-eteint { background: var(--fond); color: var(--texte-moyen); border-color: var(--bordure-forte); }
.etat-eteint .etat-point { background: var(--texte-faible); }

/* UN CADRE QUI DEFILE : les listes qui s'allongent (fil des signaux, appuis
   recus) gardent une hauteur fixe ; on fait defiler dedans. */
.zone-defilante {
    max-height: 440px;
    overflow-y: auto;
    border: 1px solid var(--bordure);
    border-radius: 8px;
    padding: 4px 12px;
    overscroll-behavior: contain;
}
.zone-defilante.table-wrapper { padding: 0; }
.zone-defilante thead th { position: sticky; top: 0; z-index: 1; background: var(--fond-doux); }

/* =============================================================================
   LE SUIVI DU BOITIER SUR LA FICHE D'UNE INTERVENTION
   ========================================================================== */
.suivi-intervention h2 { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.suivi-boitiers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.suivi-boitier {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 8px 14px;
    align-items: center;
    padding: 10px 14px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: var(--fond-doux);
    color: var(--texte);
    text-decoration: none;
}
.suivi-boitier:hover { border-color: var(--bleu); background: var(--bleu-pale); text-decoration: none; }
.suivi-boitier-qui { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 100%; }
.suivi-boitier-etat { flex: 1 1 auto; }
.suivi-boitier-lien { color: var(--bleu); font-size: 13px; font-weight: 600; white-space: nowrap; }
.suivi-titre { margin: 4px 0 8px; font-size: 14px; }
.suivi-vide {
    padding: 14px 16px;
    border: 1px dashed var(--bordure-forte);
    border-radius: var(--radius);
    color: var(--texte-moyen);
    margin: 0 0 10px;
}
.suivi-intervention .zone-defilante { max-height: 320px; }


/* -----------------------------------------------------------------------------
   LES ABSENCES A REMPLACER
   La zone « urgent » du tableau de bord du planning, et la page d'une
   absence : les dates encore au nom de quelqu'un qui ne viendra pas.
   -------------------------------------------------------------------------- */
.badge-danger { background: var(--rouge); color: #fff; }
.carte-urgente { border: 1px solid #f1b7b2; border-left: 4px solid var(--rouge); }
.urgences { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.urgence {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    padding: 10px 12px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: var(--blanc);
    color: var(--texte);
    text-decoration: none;
}
.urgence:hover { border-color: var(--rouge); text-decoration: none; }
.urgence-qui { display: flex; flex-direction: column; min-width: 190px; }
.urgence-quoi { flex: 1 1 260px; }
.urgence .btn { margin-left: auto; }

.abs-remplacer { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; }
.abs-remplacer .form-select { width: auto; min-width: 220px; max-width: 100%; }
.abs-restee td { background: #fffaf0; }

/* Dans le calendrier : une date au nom d'un absent se voit, et se lit. */
.cal-slot.est-absent { box-shadow: inset 0 0 0 2px var(--rouge); }
.cal-slot-absent { background: var(--rouge-pale); color: #8f201a; }
.eqs-carte.est-absent { box-shadow: inset 0 0 0 2px var(--rouge); }
.cal-absences {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0 0 12px;
    padding: 10px 14px;
    border: 1px solid #f1b7b2;
    border-left: 4px solid var(--rouge);
    border-radius: var(--radius);
    background: var(--rouge-pale);
    font-size: 13.5px;
}
.cal-absences p { margin: 0; }

/* -----------------------------------------------------------------------------
   LA VUE « COMPARER »
   Pour chaque jour, une ligne par personne et les heures de gauche a droite :
   la meme echelle pour tout le monde, si bien qu'une prestation de 8 h est a
   la meme place chez chacun. Une ligne hachuree : la personne est absente.
   -------------------------------------------------------------------------- */
.cmp { display: flex; flex-direction: column; gap: 14px; }
.cmp-defile { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cmp-jour {
    min-width: 760px;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    overflow: hidden;
}
.cmp-jour.is-today { border-color: var(--bleu); }
.cmp-jour-tete {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 14px;
    background: var(--fond-doux, #f7f9fb);
    border-bottom: 1px solid var(--bordure);
}
.cmp-jour-tete strong { font-size: 14px; }
.cmp-ligne {
    display: grid;
    grid-template-columns: 170px minmax(0, 1fr) 90px;
    align-items: stretch;
    border-bottom: 1px solid #eef1f5;
}
.cmp-ligne:last-child { border-bottom: none; }
.cmp-nom { padding: 8px 12px; font-size: 13px; font-weight: 600; overflow-wrap: anywhere; }
.cmp-nom .muted { display: block; font-weight: 400; }
.cmp-total { padding: 8px 10px; font-size: 12px; text-align: right; color: var(--texte-doux); }
.cmp-total strong { display: block; color: var(--texte); font-size: 13px; }
.cmp-piste { position: relative; min-height: 38px; border-left: 1px solid #eef1f5; border-right: 1px solid #eef1f5; }
.cmp-trait { position: absolute; top: 0; bottom: 0; width: 1px; background: #f0f2f6; }
.cmp-regle { min-height: 22px; }
.cmp-regle .cmp-heure {
    position: absolute;
    top: 4px;
    transform: translateX(-50%);
    font-size: 10.5px;
    color: var(--texte-doux);
    white-space: nowrap;
}
.cmp-barre {
    position: absolute;
    height: 28px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 0 6px;
    overflow: hidden;
    border-radius: 5px;
    border-left: 3px solid var(--bleu);
    background: #eef4fc;
    color: var(--texte);
    font-size: 11px;
    line-height: 1.2;
    white-space: nowrap;
    text-decoration: none;
}
.cmp-barre:hover { text-decoration: none; filter: brightness(.97); z-index: 2; }
.cmp-barre strong { overflow: hidden; text-overflow: ellipsis; }
.cmp-barre.status-PLANNED    { border-left-color: #d99b1c; background: #fff8ec; }
.cmp-barre.status-INPROGRESS { border-left-color: #7a4fbf; background: #f4effc; }
.cmp-barre.status-DONE       { border-left-color: #2f9e5f; background: #f1faf5; }
.cmp-barre.est-chevauche { box-shadow: inset 0 0 0 2px #e0a33a; }
.cmp-ligne.est-absent .cmp-piste {
    background: repeating-linear-gradient(135deg, #fbe9e7 0 8px, #fff 8px 16px);
}
.cmp-absence {
    position: absolute;
    left: 8px;
    top: 50%;
    transform: translateY(-50%);
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--blanc);
    color: #8f201a;
    font-size: 11.5px;
    font-weight: 600;
}
.cmp-sans-heure { display: block; font-size: 11px; color: #8a5200; }

/* -----------------------------------------------------------------------------
   UN SIGNALEMENT CONFIE PAR UNE TACHE : la liste des taches qui en sont nees.
   -------------------------------------------------------------------------- */
.taches-liees { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.taches-liees li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    padding: 8px 12px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
}
.taches-liees a { font-weight: 600; }


/* -----------------------------------------------------------------------------
   LE SUIVI D'UN CLIENT : une frise de haut en bas, du plus recent au plus
   ancien. Un fil, des reperes de mois, une pastille par entree.

   SUR UN CADRE LARGE, les entrees s'alternent de part et d'autre du fil : on
   parcourt l'histoire d'un coup d'oeil, comme un arbre. SUR UN CADRE ETROIT
   (telephone, colonne), le fil passe a gauche et tout se range a droite.
   C'est la largeur du CADRE qui decide (requete de conteneur), pas celle de
   l'ecran : la meme frise sert sur la fiche et sur la page du suivi.

   UN GROUPE (plusieurs photos sous la meme legende) se reconnait a sa pile :
   deux feuilles decalees derriere la couverture, le nombre de photos dessus,
   et les suivantes en petit dessous.
   -------------------------------------------------------------------------- */
.frise-cadre { container-type: inline-size; }
.frise {
    position: relative;
    list-style: none;
    margin: 18px 0 0;
    padding: 0;
}
.frise::before {
    content: "";
    position: absolute;
    top: 6px;
    bottom: 0;
    left: 15px;
    width: 2px;
    border-radius: 2px;
    background: linear-gradient(to bottom, var(--bleu) 0, #b9cfe6 60%, var(--bordure) 100%);
}

.frise-mois { position: relative; padding: 0 0 14px 40px; }
.frise-mois span {
    position: relative;
    display: inline-block;
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--bleu-pale);
    color: var(--bleu-fonce);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    box-shadow: 0 0 0 4px var(--blanc);
}
.frise-entree + .frise-mois { padding-top: 8px; }

.frise-entree { position: relative; padding: 0 0 22px 40px; }
.frise-point {
    position: absolute;
    top: 16px;
    left: 9px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--blanc);
    border: 3px solid var(--bleu);
    box-shadow: 0 0 0 4px var(--blanc);
    z-index: 1;
}

.frise-carte {
    position: relative;
    background: var(--blanc);
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    box-shadow: var(--ombre-carte);
    padding: 12px 14px 12px;
    transition: box-shadow .15s;
}
.frise-carte:hover { box-shadow: var(--ombre-haute); }
.frise-tete {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 2px 10px;
    margin-bottom: 10px;
}
.frise-tete time { font-weight: 650; color: var(--texte); font-size: 14px; }

.frise-photos.est-groupe {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 6px;
}
.frise-couverture {
    position: relative;
    display: block;
    grid-column: 1 / -1;
    border-radius: 8px;
}
.frise-photos.est-groupe .frise-couverture { margin: 0 12px 14px 0; }
.frise-couverture img {
    position: relative;
    z-index: 2;
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    max-height: 340px;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid var(--bordure);
    background: var(--fond);
}
.frise-couverture:hover img { filter: brightness(.96); }
.frise-pile {
    position: absolute;
    inset: 0;
    border-radius: 8px;
    border: 1px solid var(--bordure-forte);
    background: var(--fond-doux);
}
.frise-pile-1 { z-index: 1; transform: translate(6px, 6px); }
.frise-pile-2 { z-index: 0; transform: translate(12px, 12px); background: var(--fond); }
.frise-nombre {
    position: absolute;
    z-index: 3;
    right: 10px;
    bottom: 10px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    border-radius: 999px;
    background: rgba(17, 24, 39, .78);
    color: #fff;
    font-size: 12.5px;
    font-weight: 600;
}
.frise-nombre .icone { width: 15px; height: 15px; }

.frise-mini { position: relative; display: block; border-radius: 6px; overflow: hidden; }
.frise-mini img {
    display: block;
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    border: 1px solid var(--bordure);
    border-radius: 6px;
}
.frise-mini:hover img { filter: brightness(.92); }
.frise-mini-plus {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    background: rgba(17, 24, 39, .55);
    color: #fff;
    font-size: 15px;
    font-weight: 700;
}

.frise-legende {
    margin: 10px 0 0;
    font-size: 14px;
    line-height: 1.5;
    color: var(--texte-moyen);
    overflow-wrap: anywhere;
}

.frise-gerer { margin-top: 8px; }
.frise-gerer > summary { font-size: 12.5px; color: var(--texte-faible); }
.frise-gerer > summary:hover { color: var(--texte-doux); text-decoration: underline; }
.frise-gerer[open] { padding-top: 8px; border-top: 1px dashed var(--bordure); }
.frise-gerer-photos { grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 6px; margin-bottom: 8px; }
.frise-gerer-photos img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 6px; }

.frise-suite { margin: 4px 0 0 40px; }
.frise-vide { margin-top: 12px; }

.suivi-ajout { margin: 4px 0 6px; }
.suivi-ajout[open] > summary { margin-bottom: 12px; }
.suivi-ajout-form {
    padding: 14px 16px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
    background: var(--fond-doux);
}
.suivi-ajout-form .form-actions { margin-top: 4px; }

/* Le cadre est large : le fil au milieu, les entrees de part et d'autre. */
@container (min-width: 760px) {
    .frise::before { left: 50%; margin-left: -1px; }
    .frise-mois { padding: 0 0 18px; text-align: center; }
    .frise-entree + .frise-mois { padding-top: 4px; }
    .frise-entree { width: 50%; padding: 0 34px 26px 0; }
    .frise-entree.frise-droite { margin-left: 50%; padding: 0 0 26px 34px; }
    .frise-entree .frise-point { left: auto; right: -8px; }
    .frise-entree.frise-droite .frise-point { right: auto; left: -8px; }
    /* Le petit trait qui relie la carte a sa pastille. */
    .frise-carte::after {
        content: "";
        position: absolute;
        top: 22px;
        right: -27px;
        width: 26px;
        height: 2px;
        background: #b9cfe6;
    }
    .frise-droite .frise-carte::after { right: auto; left: -27px; }
    .frise-suite { margin-left: 0; text-align: center; }
}

@media print {
    .suivi-ajout, .frise-gerer { display: none; }
    .frise-carte { box-shadow: none; break-inside: avoid; }
}

/* -----------------------------------------------------------------------------
   LE FIL D'ACTUALITES, MIS EN PAGE COMME UN JOURNAL.

   Un bandeau de titre a l'ancienne (le nom en caracteres de journal, un
   double filet, la date du jour), des rubriques en pastilles, la UNE en
   grand, puis les dernieres nouvelles en cartes.

   CHAQUE GENRE A SA COULEUR, posee une fois ici en variables (--genre,
   --genre-pale, --genre-fonce) : la carte, la pastille, la rubrique active et
   la tuile du formulaire la relisent. On reconnait une reclamation a sa
   couleur avant d'en lire le titre.

   Le caractere de titre est celui du systeme (Georgia, Times...) : aucune
   police telechargee, donc rien qui parte chez un fournisseur de polices.
   -------------------------------------------------------------------------- */
.genre-bonne_nouvelle    { --genre: #12805c; --genre-pale: #e7f6ee; --genre-fonce: #0b5c41; }
.genre-information       { --genre: #1d64a3; --genre-pale: #ebf3fb; --genre-fonce: #154b7a; }
.genre-note              { --genre: #6941c6; --genre-pale: #f1ecfb; --genre-fonce: #4b2d93; }
.genre-reclamation       { --genre: #b3261e; --genre-pale: #fdecea; --genre-fonce: #8f201a; }
.genre-mauvaise_nouvelle { --genre: #b26a00; --genre-pale: #fdf3e1; --genre-fonce: #7a4a00; }

.journal { max-width: 1180px; }
.journal-titrage,
.journal-nom,
.journal-une-titre,
.journal-carte-titre,
.journal-article-titre { font-family: Georgia, "Times New Roman", Times, serif; }

/* -- Le bandeau ------------------------------------------------------------ */
.journal-bandeau {
    margin-bottom: 14px;
    padding: 16px 24px 10px;
    border-radius: var(--radius-lg);
    background: var(--blanc);
    box-shadow: var(--ombre-carte);
    text-align: center;
}
.journal-surtitre {
    margin: 0;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--texte-faible);
}
.journal-nom {
    margin: 2px 0 10px;
    font-size: clamp(28px, 4.2vw, 44px);
    font-weight: 700;
    line-height: 1.05;
    letter-spacing: -.01em;
    color: var(--texte);
}
.journal-du-jour {
    margin: 0;
    padding-top: 6px;
    border-top: 3px double var(--texte);
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: .04em;
    color: var(--texte-moyen);
}

/* -- Les rubriques --------------------------------------------------------- */
.journal-rubriques {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
    padding: 2px 2px 6px;
    overflow-x: auto;
    scrollbar-width: thin;
}
.journal-rubrique {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border: 1px solid var(--bordure);
    border-radius: 999px;
    background: var(--blanc);
    color: var(--texte-moyen);
    font-size: 13.5px;
    font-weight: 600;
    white-space: nowrap;
}
.journal-rubrique:hover { border-color: var(--bordure-forte); color: var(--texte); text-decoration: none; }
.journal-rubrique.est-active { background: var(--texte); border-color: var(--texte); color: #fff; }
.journal-rubrique[class*="genre-"].est-active { background: var(--genre); border-color: var(--genre); }

/* -- Les pastilles et marques ---------------------------------------------- */
.journal-carte-haut { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.genre-pastille {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--genre-pale, var(--fond));
    color: var(--genre-fonce, var(--texte-moyen));
    font-size: 12px;
    font-weight: 700;
}
.genre-pastille-lg { padding: 5px 12px; font-size: 13px; }
.journal-nouveau {
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--rouge);
    color: #fff;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.journal-restreinte {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    color: var(--texte-doux);
}
.journal-restreinte .icone { width: 14px; height: 14px; }
.journal-une-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    color: var(--rouge);
    font-size: 11.5px;
    font-weight: 800;
    letter-spacing: .14em;
    text-transform: uppercase;
}
.journal-une-label .icone { width: 15px; height: 15px; }
.journal-client {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    font-size: 13px;
    color: var(--texte-doux);
}
.journal-client .icone { width: 15px; height: 15px; }
.journal-photos-nombre {
    position: absolute;
    right: 10px;
    bottom: 10px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(17, 24, 39, .75);
    color: #fff;
    font-size: 12px;
    font-weight: 600;
}
.journal-photos-nombre .icone { width: 14px; height: 14px; }

/* -- La une ----------------------------------------------------------------- */
.journal-une {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    margin-bottom: 22px;
    overflow: hidden;
    border-top: 5px solid var(--genre);
    border-radius: var(--radius-lg);
    background: var(--blanc);
    box-shadow: var(--ombre-carte);
}
.journal-une.sans-photo { grid-template-columns: 1fr; }
.journal-une-photo { position: relative; display: block; min-height: 300px; background: var(--fond); }
.journal-une-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.journal-une-texte { display: flex; flex-direction: column; gap: 10px; padding: 22px 26px; }
.journal-une-titre { margin: 0; font-size: clamp(23px, 2.6vw, 31px); line-height: 1.15; letter-spacing: -.01em; }
.journal-une-titre a, .journal-carte-titre a { color: var(--texte); }
.journal-une-titre a:hover, .journal-carte-titre a:hover { color: var(--genre-fonce); text-decoration: none; }
.journal-chapo { margin: 0; font-size: 15.5px; line-height: 1.6; color: var(--texte-moyen); }

/* -- Les cartes ------------------------------------------------------------- */
.journal-section {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 4px 0 14px;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--texte-moyen);
}
.journal-section::after { content: ""; flex: 1; height: 1px; background: var(--bordure-forte); }
.journal-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 18px;
}
.journal-carte {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-top: 4px solid var(--genre);
    border-radius: var(--radius-lg);
    background: var(--blanc);
    box-shadow: var(--ombre-carte);
    transition: transform .15s ease, box-shadow .15s ease;
    scroll-margin-top: 80px;
}
.journal-carte:hover { transform: translateY(-2px); box-shadow: var(--ombre-haute); }
.journal-carte:target { box-shadow: 0 0 0 3px var(--genre-pale), var(--ombre-haute); }
.journal-carte-photo { position: relative; display: block; aspect-ratio: 16 / 9; background: var(--fond); }
.journal-carte-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.journal-carte-bandeau {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 112px;
    background:
        repeating-linear-gradient(135deg, transparent 0 14px, rgba(255, 255, 255, .35) 14px 28px),
        linear-gradient(135deg, var(--genre-pale), #fff);
    font-size: 46px;
    line-height: 1;
}
.journal-carte-bandeau:hover { text-decoration: none; }
.journal-carte-bandeau span { filter: drop-shadow(0 4px 6px rgba(16, 24, 40, .15)); transition: transform .15s; }
.journal-carte:hover .journal-carte-bandeau span { transform: scale(1.08) rotate(-4deg); }
.journal-carte-corps { display: flex; flex: 1; flex-direction: column; gap: 8px; padding: 14px 16px 12px; }
.journal-carte-titre {
    margin: 0;
    font-size: 19px;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: 0;
    text-transform: none;
    color: var(--texte);
}
.journal-extrait { margin: 0; font-size: 14px; line-height: 1.55; color: var(--texte-moyen); overflow-wrap: anywhere; }
.journal-carte-pied {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: auto;
    padding-top: 10px;
    border-top: 1px solid var(--bordure);
}

/* -- Qui, quand ------------------------------------------------------------- */
.journal-signature { display: flex; align-items: center; gap: 9px; min-width: 0; }
.journal-avatar { width: 30px; height: 30px; font-size: 11.5px; }
.journal-signature-texte { display: flex; flex-direction: column; min-width: 0; font-size: 13px; line-height: 1.3; }
.journal-signature-texte strong { font-weight: 600; color: var(--texte); }
.journal-signature-texte time { font-size: 12.5px; color: var(--texte-doux); }

/* -- Les reactions ------------------------------------------------------------ */
.journal-reactions { display: flex; flex-wrap: wrap; gap: 4px; }
.journal-reactions form { margin: 0; }
.journal-reaction {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 30px;
    padding: 0 9px;
    border: 1px solid var(--bordure);
    border-radius: 999px;
    background: var(--blanc);
    color: var(--texte-moyen);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background .12s, border-color .12s, transform .12s;
}
.journal-reaction:hover { background: var(--fond); transform: scale(1.06); }
.journal-reaction:focus-visible { outline: 2px solid var(--bleu); outline-offset: 2px; }
.journal-reaction-emoji { font-size: 15px; line-height: 1; }
.journal-reaction.est-vide .journal-reaction-emoji { filter: grayscale(.6); opacity: .7; }
.journal-reaction.est-vide:hover .journal-reaction-emoji { filter: none; opacity: 1; }
.journal-reaction.est-mienne { border-color: #9cc1e6; background: var(--bleu-pale); color: var(--bleu-fonce); }

/* -- Le fil vide, les pages ---------------------------------------------------- */
.journal-vide {
    padding: 40px 24px;
    border-radius: var(--radius-lg);
    background: var(--blanc);
    box-shadow: var(--ombre-carte);
    text-align: center;
}
.journal-vide-emoji { margin: 0 0 6px; font-size: 44px; }
.journal-vide h2 { font-family: Georgia, "Times New Roman", Times, serif; font-size: 22px; }
.journal-vide p { max-width: 520px; margin: 0 auto 16px; }
.journal-pages { display: flex; justify-content: center; align-items: center; gap: 14px; margin: 22px 0 6px; }

/* -- L'article ---------------------------------------------------------------- */
.journal-article {
    max-width: 820px;
    margin: 0 auto 20px;
    padding: 26px 32px;
    border-top: 6px solid var(--genre);
    border-radius: var(--radius-lg);
    background: var(--blanc);
    box-shadow: var(--ombre-carte);
}
.journal-article-tete .journal-signature { margin-top: 4px; }
.journal-article-titre {
    margin: 12px 0 14px;
    font-size: clamp(26px, 3.4vw, 36px);
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -.01em;
}
.journal-article-infos {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 22px;
    margin: 14px 0 0;
    padding: 12px 0 0;
    border-top: 1px solid var(--bordure);
    list-style: none;
    font-size: 13.5px;
    color: var(--texte-moyen);
}
.journal-article-infos li { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.journal-article-infos .icone { width: 16px; height: 16px; color: var(--texte-faible); }
.journal-article-photos { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 20px 0 6px; }
.journal-article-photo { position: relative; }
.journal-article-photo a { display: block; }
.journal-article-photo img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 8px; }
.journal-article-photo.est-premiere { grid-column: 1 / -1; }
.journal-article-photo.est-premiere img {
    aspect-ratio: auto;
    max-height: 520px;
    object-fit: contain;
    background: #f1f3f6;
}
.journal-article-texte {
    margin-top: 18px;
    font-size: 16.5px;
    line-height: 1.75;
    color: var(--texte);
    overflow-wrap: anywhere;
}
.journal-article-texte p { margin: 0 0 14px; }
.journal-article-pied {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--bordure);
}
.journal-article-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.journal-article-actions .icone { width: 15px; height: 15px; }

.journal-vues { max-width: 820px; margin: 0 auto 20px; }
.journal-vues h2 { margin: 0; }
.journal-vues-jauge { flex: 0 1 180px; height: 8px; overflow: hidden; border-radius: 999px; background: var(--fond); }
.journal-vues-jauge span { display: block; height: 100%; border-radius: 999px; background: var(--vert); }
.journal-vues-titre { margin-top: 6px; }
.journal-vues-pas-vu { margin-bottom: 14px; }
.journal-vues-liste.journal-vues-pas-vu li { background: var(--orange-pale); }
.journal-vues-liste.journal-vues-pas-vu li.journal-vues-tous { background: var(--vert-pale); color: var(--vert); font-weight: 600; }
.journal-vues-detail { border: 1px solid var(--bordure); border-radius: var(--radius); }
.journal-vues-liste { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; font-size: 14px; }
.journal-vues-liste li {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 10px;
    border-radius: 8px;
    background: var(--fond-doux);
}

/* -- Publier ------------------------------------------------------------------- */
.journal-form { max-width: 880px; }
.journal-form-bloc { min-width: 0; margin: 0 0 22px; padding: 0; border: 0; }
.journal-form-bloc legend { margin-bottom: 10px; padding: 0; font-size: 15px; font-weight: 650; }
.journal-genres { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.journal-genre {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px;
    border: 2px solid var(--bordure);
    border-radius: 12px;
    background: var(--blanc);
    cursor: pointer;
    transition: border-color .12s, background .12s, box-shadow .12s;
}
.journal-genre input { position: absolute; opacity: 0; pointer-events: none; }
.journal-genre:hover { border-color: var(--genre); }
.journal-genre:has(input:checked) {
    border-color: var(--genre);
    background: var(--genre-pale);
    box-shadow: 0 0 0 3px var(--genre-pale);
}
.journal-genre:has(input:focus-visible) { outline: 2px solid var(--genre); outline-offset: 2px; }
.journal-genre-embleme { font-size: 24px; line-height: 1; }
.journal-genre-nom { font-size: 14px; font-weight: 700; color: var(--genre-fonce); }
.journal-genre-aide { font-size: 12.5px; line-height: 1.4; color: var(--texte-doux); }
.journal-audiences { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; margin-bottom: 12px; }
.journal-audience {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border: 2px solid var(--bordure);
    border-radius: 12px;
    background: var(--blanc);
    cursor: pointer;
}
.journal-audience:has(input:checked) { border-color: var(--bleu); background: var(--bleu-pale); }
.journal-audience input { margin-top: 3px; }
.journal-audience > span { display: flex; flex-direction: column; gap: 2px; }
.journal-form .case .icone { width: 15px; height: 15px; }

.nav-badge-info { background: var(--rouge); color: #fff; }

@media (max-width: 860px) {
    .journal-une { grid-template-columns: 1fr; }
    .journal-une-photo { min-height: 0; aspect-ratio: 16 / 9; }
    .journal-une-texte { padding: 18px; }
}
@media (max-width: 640px) {
    .journal-article { padding: 18px 16px; }
    .journal-article-photos { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .journal-bandeau { padding: 12px 14px 8px; }
}
@media print {
    .journal-reactions, .journal-article-actions, .journal-rubriques { display: none; }
}

/* La derniere actualite, en une ligne sur le tableau de bord. */
.dash-actu {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 18px;
    padding: 12px 16px;
    border-left: 5px solid var(--genre);
    border-radius: var(--radius);
    background: var(--blanc);
    box-shadow: var(--ombre-carte);
    color: var(--texte);
}
.dash-actu:hover { text-decoration: none; box-shadow: var(--ombre-haute); color: var(--texte); }
.dash-actu-embleme { font-size: 26px; line-height: 1; }
.dash-actu-texte { display: flex; flex: 1; flex-direction: column; gap: 2px; min-width: 0; }
.dash-actu-label {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--genre-fonce);
}
.dash-actu-texte strong {
    overflow: hidden;
    font-family: Georgia, "Times New Roman", Times, serif;
    font-size: 17px;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dash-actu-fleche { color: var(--texte-faible); }

/* Le suivi du client sur sa fiche : un resume et un bouton, la frise est
   sur sa propre page. */
.suivi-resume {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 20px;
}
.suivi-resume h2 { margin: 0 0 2px; }
.suivi-resume p { margin: 0; }
/* 320px avant de passer a la ligne : sur un telephone, le bouton descend sous
   le texte au lieu de l'ecraser en colonne etroite. */
.suivi-resume-corps { display: flex; align-items: center; gap: 14px; min-width: 0; flex: 1 1 320px; }
.suivi-resume-icone {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    flex-shrink: 0;
    border-radius: 12px;
    background: var(--bleu-pale);
    color: var(--bleu);
}

/* Les cases de l'acces client. */
.parties-portail { display: grid; gap: 6px; margin: 4px 0 10px; padding: 0; border: 0; min-width: 0; }
.parties-portail legend { margin-bottom: 4px; padding: 0; font-weight: 600; color: var(--texte-moyen); }
.contact-droits { margin-top: 8px; }

/* -----------------------------------------------------------------------------
   LE TEST D'UN BOITIER (templates/attendance/essai.html)
   -------------------------------------------------------------------------- */
.essai-grille { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 16px; align-items: start; }
@media (max-width: 900px) { .essai-grille { grid-template-columns: minmax(0, 1fr); } }
.essai-grille > .card { margin: 0; }
.essai-gestes { margin: 0 0 12px; padding-left: 20px; display: grid; gap: 6px; }
.essai-rassure { margin: 0 0 12px; padding: 10px 12px; border-radius: var(--radius); background: var(--vert-pale); color: #0d5c41; font-size: 14px; }
.essai-bandeau {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border-radius: var(--radius);
    background: var(--fond-doux);
    border: 1px solid var(--bordure);
}
.essai-bandeau > div { flex: 1 1 200px; }
.essai-bandeau-actif { background: var(--bleu-pale); border-color: #c4dcf1; color: var(--bleu-fonce); }
.essai-pastille {
    width: 10px;
    height: 10px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--bleu);
    animation: essai-pouls 1.4s ease-in-out infinite;
}
@keyframes essai-pouls { 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) { .essai-pastille { animation: none; } }
.essai-titre { margin: 18px 0 8px; font-size: 15px; }
.essai-etapes { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.essai-etape {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--bordure);
    border-radius: var(--radius);
}
.essai-coche {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    border: 2px solid var(--bordure-forte);
    border-radius: 50%;
    font-size: 13px;
    font-weight: 700;
}
.essai-etape-ok { border-color: #b7e2cc; background: #f0faf5; }
.essai-etape-ok .essai-coche { border-color: var(--vert); background: var(--vert); color: #fff; }
.essai-etape-off { opacity: .6; }
.essai-materiel { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 14px; color: var(--texte-doux); }
.essai-signaux { display: grid; gap: 2px; max-height: 320px; overflow-y: auto; margin: 0; padding: 0; list-style: none; }
.essai-signal { display: flex; gap: 12px; padding: 6px 8px; border-radius: 6px; font-size: 14px; }
.essai-signal:nth-child(odd) { background: var(--fond-doux); }
.essai-heure { flex-shrink: 0; font-variant-numeric: tabular-nums; color: var(--texte-doux); }
.essai-signal-ok { color: #0d5c41; }
.essai-signal-attention { color: #7a4800; font-weight: 600; }

/* -----------------------------------------------------------------------------
   PROSPECTION (templates/prospection/)
   -------------------------------------------------------------------------- */
.prospects .prospect-etape { margin-top: 2px; max-width: 520px; }
.prospects tr.prospect-a-reprendre td:first-child { box-shadow: inset 3px 0 0 var(--orange); }
.prospect-grille { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 16px; align-items: start; }
@media (max-width: 900px) { .prospect-grille { grid-template-columns: minmax(0, 1fr); } }
.prospect-grille > .card { margin: 0; }
.prospect-notes { margin: 0 0 12px; padding: 10px 12px; border-radius: var(--radius); background: var(--fond-doux); }
.prospect-gestes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.prospect-gestes + p { margin: 8px 0 0; }
.prospect-noter { margin-bottom: 18px; padding-bottom: 18px; border-bottom: 1px solid var(--bordure); }
.prospect-dates { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0 12px; }
.prospect-frise { position: relative; display: grid; gap: 14px; margin: 0; padding: 0 0 0 22px; list-style: none; }
.prospect-frise::before { content: ""; position: absolute; left: 6px; top: 6px; bottom: 6px; width: 2px; background: var(--bordure); }
.prospect-jalon { position: relative; }
.prospect-jalon::before {
    content: "";
    position: absolute;
    left: -21px;
    top: 5px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--blanc);
    border: 2px solid var(--bordure-forte);
}
.prospect-jalon-actuel::before { border-color: var(--bleu); background: var(--bleu); }
.prospect-jalon-tete { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.prospect-jalon-texte { margin: 4px 0; white-space: normal; }
.prospect-jalon-retirer { margin-top: 2px; }
.prospect-retirer {
    padding: 0;
    border: 0;
    background: none;
    color: var(--texte-faible);
    font: inherit;
    font-size: 12.5px;
    cursor: pointer;
}
.prospect-retirer:hover { color: var(--rouge); text-decoration: underline; }
.prospect-formulaire { max-width: 820px; }

/* -----------------------------------------------------------------------------
   LES TRAJETS ENTRE DEUX CLIENTS (planning/_trajet.html, docs/TRAJETS_PLANNING.md)
   Une couleur a eux - violet hachure - pour ne jamais les prendre pour une
   intervention. En rouge quand le trajet ne tient pas entre les deux.
   -------------------------------------------------------------------------- */
.cal-trajets {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    margin: 0 0 10px;
    padding: 8px 12px;
    border: 1px solid #ddd3f0;
    border-radius: var(--radius);
    background: #f7f3fd;
}
.cal-trajets .cal-check strong { color: #4a2c8a; }
.cal-trajets .trajets-courts { color: var(--rouge); }
.cal-trajet {
    position: absolute;
    left: 4px;
    right: 4px;
    /* Le temps libre entre deux interventions, pas plus (services/trajets.py) :
       ce qui ne tient pas s'ouvre au survol, par-dessus le reste. */
    height: var(--hauteur);
    overflow: hidden;
    z-index: 3;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 2px 6px;
    padding: 1px 5px;
    border-radius: 5px;
    border-left: 3px solid #7e57c2;
    background: repeating-linear-gradient(135deg, #efe8fa 0 6px, #e6dcf6 6px 12px);
    color: #4a2c8a;
    font-size: 11px;
    line-height: 1.3;
    pointer-events: auto;
}
.cal-trajet em { font-style: normal; font-weight: 700; color: var(--rouge); }
.cal-trajet.est-court {
    border-left-color: var(--rouge);
    background: repeating-linear-gradient(135deg, #fdecea 0 6px, #f9dcd8 6px 12px);
    color: #8f201a;
}
.cal-trajet.est-inconnu { border-left-style: dashed; opacity: .85; }
.cal-trajet.est-mince { padding-top: 0; padding-bottom: 0; }
.cal-trajet.est-mince > * { visibility: hidden; }
.cal-trajet:hover,
.cal-trajet:focus-within,
.cal-trajet:focus {
    height: auto;
    min-height: var(--hauteur);
    overflow: visible;
    z-index: 6;
    padding: 2px 5px;
    outline: none;
    box-shadow: 0 4px 14px rgba(40, 20, 80, .22);
}
.cal-trajet:hover > *,
.cal-trajet:focus-within > *,
.cal-trajet:focus > * { visibility: visible; }
.cal-trajet-caler { margin: 0; }
.cal-trajet-caler button {
    max-width: 100%;
    padding: 0 4px;
    border: 1px solid #b9a5e2;
    border-radius: 4px;
    background: #fff;
    color: #4a2c8a;
    font: inherit;
    font-size: 10px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}
.cal-trajet-caler button:hover { background: #f3eefc; }
.cmp-trajet {
    position: absolute;
    top: 3px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: 5px;
    border-left: 3px solid #7e57c2;
    background: repeating-linear-gradient(135deg, #efe8fa 0 6px, #e6dcf6 6px 12px);
    color: #4a2c8a;
    font-size: 10.5px;
    font-weight: 600;
    white-space: nowrap;
}
.cmp-trajet.est-court { border-left-color: var(--rouge); background: #fdecea; color: #8f201a; }
.cmp-trajet.est-inconnu { border-left-style: dashed; }
.heures-table tr.ligne-trajet td { background: #f7f3fd; color: #4a2c8a; }
.heures-table tr.ligne-trajet td:first-child { box-shadow: inset 3px 0 0 #7e57c2; }
