/* Typographie : pile système Arial / Helvetica (charte InTenz). Aucune police web à charger
   → 1er rendu immédiat, zéro requête tierce (confidentialité/RGPD). */
:root{
    --teal:#048B9A;--teal-dark:#0A6A73;--link:#0A6A73;--teal-deeper:#0A3A42;--ink:#1D2A2E;--ink-2:#254046;
    --gold:#E3AC2B;--green:#36806E;--green-soft:#EAF6F2;--champagne:#EEDEC6;--light:#F0F6FC; /* Zomp assombri : glyphe/label blanc sur « au poste » = 4,70:1 (WCAG AA, mesuré), aligné sur le Zomp #49AD95 de la charte (inutilisable tel quel : 2,7:1) */
    --maybe:#9A6410;--maybe-soft:#FBEFD8;--shared:#3667C9;--shared-soft:#E6ECFA; /* peut-être (ambre) · espace partagé (bleu) — ambre foncé pour un texte blanc lisible (AA) */
    --line:#E2E9ED;--grey:#5A6A71;--danger:#D9534F;--radius:18px;--shadow:0 10px 30px rgba(10,58,66,.10);
    /* DEUX rouges, et le choix n'est pas décoratif :
       --danger    (#D9534F) = TRAITS et GLYPHES posés sur une surface claire — 3,96:1, au-dessus du
                   seuil 3:1 des éléments non textuels (WCAG 1.4.11), mais SOUS le 4,5:1 du texte.
       --danger-bg (#C33F3B) = tout FOND rouge qui porte du texte ou un glyphe BLANC : bouton
                   « danger », pastille « journée bloquée », pastille « ! » d'un créneau à retirer.
                   Blanc sur #C33F3B = 5,13:1 (mesuré) → AA tenu, y compris à 10 px (.up-blocked),
                   taille à laquelle la tolérance « grand texte » (3:1) ne s'applique PAS.
       Ne pas fondre les deux : mettre --danger-bg partout éteindrait les traits, mettre --danger
       sur les fonds rouvrirait l'échec AA. Le survol du bouton va un cran plus bas (#A83531, 6,52:1).
       Même valeur en thème sombre : le contraste blanc/rouge ne dépend pas de la surface d'accueil. */
    --danger-bg:#C33F3B;
    /* Surfaces sémantiques (thème) : réévaluées dans :root[data-theme="dark"]. Valeurs claires =
       à l'identique de l'existant → le mode clair reste inchangé au pixel. */
    --bg:#F7FAFC;--surface:#fff;--surface-2:#FAFDFE;--fill:#E6EEF3;--fill-bd:#93A8B4;--fill-ink:#5A6B72;
    color-scheme:light; /* contrôles natifs (date-pickers, scrollbars, spinners) en clair */
    font-family:Arial,Helvetica,'Segoe UI',system-ui,-apple-system,sans-serif; /* charte InTenz : Arial, à défaut Helvetica / sans-serif système */
  }
  *{box-sizing:border-box;margin:0;padding:0}
  html{overflow-x:hidden}
  .skip-link{position:absolute;left:8px;top:-60px;z-index:400;background:var(--teal-deeper);color:#fff;padding:10px 16px;border-radius:0 0 10px 10px;font-weight:700;transition:top .15s}
  .skip-link:focus{top:0}
  .sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
  body{background:var(--bg);color:var(--ink);-webkit-font-smoothing:antialiased;min-height:100vh;min-height:100dvh;display:flex;flex-direction:column}
  header{background:linear-gradient(135deg,#0A3A42 0%,#0E4B54 45%,#127B84 100%);color:#fff;position:relative;overflow:hidden}
  header::after{content:"";position:absolute;right:-80px;top:-120px;width:360px;height:360px;border:2px solid rgba(227,172,43,.25);border-radius:50%;transform:rotate(18deg)}
  body.is-admin header{background:linear-gradient(135deg,#1B2E33 0%,#254046 55%,#2E5159 100%)} /* mode admin : charbon (charte) — distinct du teal normal ; repère = pastille dorée « Mode admin » */
  /* Repère du mode admin RÉEL (hors aperçu « view as ») : le prénom de la puce utilisateur passe en DORÉ
     (accent de la charte). La classe chip-admin est posée par renderHead selon effAdmin() → retirée en aperçu. */
  .chip-user.chip-admin{color:var(--gold)}
  .head-top{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;position:relative;z-index:1;padding:22px 32px 26px}
  .brand{display:flex;align-items:center;gap:16px;min-width:0;flex:0 1 auto;overflow:hidden}
  .brand>div:last-child{min-width:0}
  .brand img{height:54px;width:auto;display:block;flex:none}
  /* Logo cliquable (retour à l'accueil) : un vrai <button>, donc à dépouiller de son habillage —
     le repère visuel reste le logo lui-même. `display:block` + padding 0 pour ne pas décaler
     l'alignement de la marque, qui est réglé au pixel avec le séparateur et le titre. */
  .brand-home{padding:0;border:none;background:none;cursor:pointer;display:block;flex:none;border-radius:10px;line-height:0;transition:opacity .15s}
  .brand-home:hover{opacity:.82}
  .brand-home:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
  .brand .divider{width:1px;height:38px;background:rgba(255,255,255,.28);flex:none}
  .brand h1{font-size:19px;font-weight:700;letter-spacing:.2px;line-height:1.15;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .brand p{font-size:12.5px;color:rgba(240,228,208,.96);font-weight:500;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .head-actions{display:flex;align-items:center;gap:10px;flex:0 0 auto}
  @media(max-width:860px){
    .head-top{padding:16px 20px}
    .brand img{height:46px}
    .brand h1{font-size:16.5px}
    .brand p{display:none}
    .brand-by{display:none} /* « by InTenz » masqué dès la tablette/mobile : titre trop long sinon (déborde) */
    .brand .divider{height:28px}
    .head-top{gap:12px}
  }
  @media(max-width:540px){
    .head-top{padding:16px 14px} /* aligné sur .wrap (14px) : le logo tombe pile sur le bord du contenu */
    .brand{gap:10px}
    .brand img{height:40px}
    .brand .divider{display:none}
    .brand h1{font-size:14px} /* 15px → le titre ne tenait pas sous 390px et se coupait ; entier à 14px > tronqué à 15px */
    .brand-sub{display:none} /* mobile : garder seulement « Planning Flex-O » */
    .wrap{padding-left:14px;padding-right:14px}
  }
  .chip{display:inline-flex;align-items:center;gap:8px;height:38px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.16);padding:0 16px;border-radius:100px;font-size:12px;font-weight:600;color:#fff;cursor:pointer;transition:.15s}
  .chip:hover{background:rgba(255,255,255,.16)}
  .chip-ico{width:16px;height:16px;flex:none}
  /* En-tête à droite : le bouton thème est STATIQUE (dans .head-actions-wrap, hors #headActions
     que renderHead réécrit) → toujours présent, même sur l'écran de connexion. */
  .head-actions-wrap{display:flex;align-items:center;gap:10px;flex:0 0 auto}
  .chip-theme{padding:0;width:38px;justify-content:center;flex:none}
  .theme-ico-sun{display:none} /* clair : on montre la Lune (→ passer en sombre) */
  :root[data-theme="dark"] .chip-theme .theme-ico-moon{display:none}
  :root[data-theme="dark"] .chip-theme .theme-ico-sun{display:block} /* sombre : on montre le Soleil (→ repasser clair) */
  /* Bouton « Guide » : ORDINATEUR SEULEMENT. L'en-tête mobile est saturé — un chip de plus y tronque
     le titre (mesuré à 390 px). Sur petit écran, le guide reste dans le menu utilisateur. */
  .chip-help{display:none}
  @media(min-width:1024px){.chip-help{display:inline-flex;cursor:pointer}}
  .chip-logout .chip-ico{display:none} /* desktop : « Déconnexion » en texte (icône masquée) */
  /* Mobile : tout sur UNE ligne (logo + titre ellipsé + profil compact + déconnexion en icône).
     Placé APRÈS les règles .chip de base pour surcharger correctement (ordre source). */
  @media(max-width:540px){
    .head-top{flex-wrap:nowrap}
    .head-actions{width:auto;gap:6px;flex-wrap:nowrap;flex:none}
    .head-actions .chip{height:44px;padding:0 13px;font-size:12.5px} /* cible tactile ≥ 44 px */
    .head-actions-wrap{gap:6px}
    .chip-theme{height:44px;width:44px} /* aligné sur les autres chips (cible tactile) */
    /* Mobile : juste la tête. Prénom + chevron volaient 27 px au titre, qui s'affichait « Planning… ».
       Le chip devient un bouton rond de 44 px comme Thème et Déconnexion (cible tactile), et le nom
       reste porté par son aria-label. */
    .chip-user .chip-lbl,.chip-user .caret{display:none}
    .chip-user{width:44px;min-width:44px;padding:0;gap:0;justify-content:center}
    .chip-user .chip-ava{width:30px;height:30px}
    .chip-logout{width:44px;min-width:44px;padding:0;justify-content:center}
    .chip-logout .chip-lbl{display:none}
    .chip-logout .chip-ico{display:block}
  }
  .chip .dot{width:8px;height:8px;border-radius:50%;background:var(--gold)}

  .wrap{width:100%;max-width:1320px;margin:0 auto;padding:26px 24px 20px}
  /* Grand écran : le contenu s'élargit (jusqu'à 1780px / 92vw) au lieu de laisser de larges marges.
     Seuil 1460px : 92vw y vaut déjà > 1320px, donc jamais plus étroit que la base. */
  @media(min-width:1460px){ .wrap{max-width:min(1780px, 92vw)} }
  @media(min-width:1460px){ .head-top{max-width:min(1780px, 92vw);margin:0 auto} }
  /* Barre CENTRÉE (et non étalée aux extrémités) : navigation de date et bascule Semaine/Mois se
     lisent au centre, sous le titre. `.nav` reste INSÉCABLE — la date et « Aujourd'hui » doivent tenir
     sur UNE ligne, sinon le bouton passe seul en dessous et la barre paraît cassée. */
  .toolbar{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:16px;margin-bottom:22px}
  .tb-center{grid-column:2;display:flex;align-items:center;gap:16px;flex-wrap:wrap;justify-content:center}
  .cap{grid-column:3;justify-self:end}
  /* Étroit : la grille 3 colonnes n'a plus de sens, on empile en restant centré. */
  /* Étroit : la grille 3 colonnes n'a plus de sens → flex empilé. « Répliquer » est PREMIER dans le
     DOM (pour occuper la colonne 1 sur ordinateur) : sans `order`, il remonterait AU-DESSUS de la date
     sur téléphone. On rétablit donc l'ordre visuel — date/bascule d'abord, bouton dessous. */
  @media(max-width:820px){
    .toolbar{display:flex;flex-wrap:wrap;justify-content:center}
    .tb-center{order:1}
    .cap{order:2;justify-self:auto}
    .row-scope{order:3;justify-self:auto;width:100%;justify-content:center}
  }
  .nav{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}
  /* « Capacité … postes » est un réglage d'ADMINISTRATION : inutile — et trompeur — pour un
     collaborateur, qui ne peut pas le modifier. `is-admin` est posé par applyRole(), donc l'aperçu
     « Vue collab' » le masque aussi, fidèlement. */
  body:not(.is-admin) .cap{display:none}
  .nav .period{font-size:17px;font-weight:700;min-width:250px;text-align:center;color:var(--ink-2)}
  .btn{border:none;cursor:pointer;font-family:inherit;font-weight:600;border-radius:11px;padding:10px 16px;font-size:13.5px;transition:.15s;display:inline-flex;align-items:center;gap:7px}
  .btn:disabled,.btn.is-busy{opacity:.6;cursor:progress;pointer-events:none}
  .loading-ph{padding:22px;text-align:center;color:var(--grey);font-size:13px;font-weight:600}
  .btn-ico{background:var(--surface);border:1px solid var(--line);color:var(--ink-2);width:40px;height:40px;padding:0;justify-content:center;font-size:17px;box-shadow:var(--shadow)}
  .btn-ico:hover{border-color:var(--teal);color:var(--teal)}
  .btn-ghost{background:var(--surface);border:1px solid var(--line);color:var(--ink-2);box-shadow:var(--shadow)}
  .btn-ghost:hover{border-color:var(--teal);color:var(--teal)}
  .btn-teal{background:var(--teal-dark);color:#fff}
  .btn-teal:hover{filter:brightness(1.06)}
  /* ===== Écran de connexion (modal-login) : hero identitaire + bouton Microsoft premium ===== */
  .modal-login{max-width:400px}
  .lg-hero{position:relative;overflow:hidden;background:linear-gradient(135deg,#0A3A42 0%,#0E4B54 45%,#127B84 100%);padding:20px 24px 21px;text-align:center}
  .lg-hero::before{content:"";position:absolute;right:-70px;top:-95px;width:230px;height:230px;border:2px solid rgba(227,172,43,.28);border-radius:50%;transform:rotate(18deg)}
  .lg-hero::after{content:"";position:absolute;left:-70px;bottom:-110px;width:210px;height:210px;border-radius:50%;background:radial-gradient(circle,rgba(227,172,43,.20),transparent 68%)}
  .lg-hero img{height:84px;position:relative;z-index:1;filter:drop-shadow(0 2px 6px rgba(0,0,0,.25))}
  .lg-hero h2{color:#fff;font-size:19px;font-weight:800;letter-spacing:.2px;margin-top:6px;position:relative;z-index:1}
  .lg-hero p{color:rgba(238,222,198,.88);font-size:12.5px;font-weight:500;margin-top:3px;position:relative;z-index:1}
  .modal.modal-login .mbody{padding:24px 26px 28px} /* spécificité > .modal .mbody (padding-bottom:0) défini plus bas */
  .lg-hi{font-size:17px;font-weight:800;color:var(--ink-2);text-align:center}
  .lg-sub{font-size:13px;color:var(--grey);text-align:center;line-height:1.5;margin:7px 0 20px}
  .btn-ms{display:flex;align-items:center;justify-content:center;gap:12px;width:100%;box-sizing:border-box;background:#fff;border:1px solid #C4CDD3;color:#243B44;font-weight:700;font-size:14.5px;padding:13px 16px;border-radius:13px;text-decoration:none;box-shadow:0 1px 4px rgba(10,58,66,.06);transition:transform .15s,box-shadow .15s,border-color .15s}
  .btn-ms:hover{transform:translateY(-1px);border-color:#9FB2BB;box-shadow:0 8px 22px rgba(10,58,66,.14)}
  .btn-ms:active{transform:translateY(0);box-shadow:0 2px 8px rgba(10,58,66,.10)}
  .btn-ms:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
  .ms-logo{width:20px;height:20px;flex:none}
  .lg-note{display:flex;align-items:center;justify-content:center;gap:6px;font-size:11.5px;color:var(--grey);margin-top:14px}
  .lg-note svg{width:13px;height:13px;flex:none;opacity:.75}
  .login-bg{display:inline-flex;align-items:center;gap:7px;margin:20px auto 0;padding:8px 16px;border:none;background:none;border-radius:20px;color:var(--grey);font-family:inherit;font-size:12px;font-weight:600;cursor:pointer;transition:background .14s,color .14s}
  .login-bg svg{width:13px;height:13px;flex:none;opacity:.85}
  .login-bg:hover{background:var(--light);color:var(--teal-dark)}
  .login-bg:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
  #ssoBlock{display:flex;flex-direction:column;align-items:center}
  .lg-back{display:block;margin:0 0 14px;font-size:12px;color:var(--grey)}
  .btn-danger{background:var(--surface);border:1px solid #F0C9C7;color:var(--danger)}
  .btn-scarlet{background:#E11D2E;color:#fff;border:1px solid #E11D2E}
  .btn-scarlet:hover{background:#C11626;border-color:#C11626}
  /* Bannière d'avertissement (ex. suppression d'un administrateur) */
  .cd-warn{background:#FFF7E6;border:1px solid #F3E4BD;color:#9A6B0E;border-radius:10px;padding:10px 12px;font-size:12.5px;font-weight:700;margin-bottom:12px}
  /* Checklist de mot de passe en direct */
  .pw-hints{display:flex;flex-wrap:wrap;gap:5px 12px;margin-top:7px;font-size:11.5px}
  .pwh{color:var(--grey)}
  .pwh.ok{color:#277A5E;font-weight:600}
  /* Modale écarlate bloquante (ex. dernier administrateur) */
  .modal-scarlet{border-top:5px solid #E11D2E}
  .modal-scarlet .mhead h2{color:#C11626}
  .scarlet-ico{font-size:30px;line-height:1;display:inline-flex;align-items:center;flex:none}
  .btn-danger:hover{background:#FDF2F1}
  .cap{display:flex;align-items:center;gap:8px;background:var(--surface);border:1px solid var(--line);border-radius:11px;padding:6px 12px;box-shadow:var(--shadow);font-size:13px;font-weight:600;color:var(--ink-2)}
  /* Filtre nom dans l'en-tête « Collaborateur » */
  .corner-search{display:flex;align-items:center;gap:6px;margin-top:8px;max-width:210px;background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.2);border-radius:9px;padding:0 9px;transition:.15s}
  .corner-search:focus-within{background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.4)}
  .corner-search svg{width:14px;height:14px;color:rgba(255,255,255,.6);flex:none}
  .corner-search input{border:none;background:none;outline:none;font-family:inherit;font-size:12.5px;font-weight:500;color:#fff;padding:7px 2px;width:100%;min-width:0}
  .corner-search input::placeholder{color:rgba(255,255,255,.5);font-weight:500}
  .cap input{width:52px;border:1px solid var(--line);border-radius:7px;padding:5px 6px;font-family:inherit;font-weight:700;text-align:center;color:var(--teal-dark);font-size:14px}
  .cap input:disabled{color:var(--grey);background:var(--bg)}
  .viewtog{display:flex;background:var(--surface);border:1px solid var(--line);border-radius:11px;box-shadow:var(--shadow);overflow:hidden}
  .viewtog button{border:none;background:none;font-family:inherit;font-weight:600;font-size:13.5px;padding:9px 17px;cursor:pointer;color:var(--ink-2);transition:.15s}
  .viewtog button:hover{color:var(--teal)}
  .viewtog button.active{background:var(--teal-dark);color:#fff}
  table.plan.month .col-name{width:230px;min-width:212px}
  table.plan.month .hf{height:40px;border-radius:7px}
  table.plan.month td.day{padding:3px}
  table.plan.month .halves{gap:3px}
  table.plan.month thead .day-h{padding:8px 3px 6px}
  table.plan.month thead .day-h .dnum{font-size:13px}
  table.plan.month thead .sub span{font-size:8px;padding:3px 0}
  td.day.wkstart{border-left:2px solid #DCE6EA}
  thead th.wkstart{border-left:2px solid rgba(255,255,255,.20)}
  /* Vue Mois : séparateur de semaine (lundi) plus marqué pour regrouper visuellement les semaines */
  table.plan.month td.day.wkstart,table.plan.month thead th.wkstart{border-left:3px solid var(--gold)}
  /* Vue Mois : badge « Sxx » (numéro de semaine ISO) sur l'en-tête des lundis */
  .wknum{display:none}
  table.plan.month thead .wknum{display:block;font-size:8.5px;font-weight:800;color:var(--gold);letter-spacing:.4px;line-height:1;margin-bottom:3px}
  /* Vue Semaine : trait doré vertical au changement de mois (ex. mar 30 juin | mer 1 juil.) */
  table.plan:not(.month) td.day.monthstart,table.plan:not(.month) thead th.monthstart{border-left:3px solid var(--gold)}

  .card{background:var(--surface);border-radius:var(--radius);box-shadow:var(--shadow);overflow:hidden;border:1px solid var(--line)}
  /* #3 Zone de défilement BORNÉE — condition SINE QUA NON des en-têtes collants.
     Sans max-height, .grid-scroll prend la hauteur de son contenu : il n'y a donc AUCUN défilement
     interne vertical (c'est la page qui défile) et `position:sticky` n'a rien à quoi s'accrocher —
     ni l'en-tête, ni la ligne « moi ». En bornant la hauteur, le tableau défile DANS son cadre
     (horizontalement ET verticalement) et les éléments collants fonctionnent vraiment.
     NB : pas d'overscroll-behavior:contain — en fin de course le défilement doit repartir sur la page
     (sinon on reste « coincé » dans le tableau, ce qui est piégeux pour un tableau intégré). */
  .grid-scroll{overflow:auto;max-height:calc(100dvh - 96px);-webkit-overflow-scrolling:touch;scrollbar-width:thin}
  table.plan{border-collapse:collapse;width:100%;min-width:820px}
  /* Vue Semaine : colonnes de jour de largeur ÉGALE (sinon un libellé long — ex. « Fête nationale »
     un jour férié — élargit sa colonne en table-layout auto). La colonne « nom » garde sa largeur fixe. */
  table.plan:not(.month){table-layout:fixed}
  table.plan th,table.plan td{border-bottom:1px solid var(--line)}
  .col-name{width:288px;min-width:264px}
  table.plan .col-name{position:sticky;left:0;z-index:2;box-shadow:1px 0 0 var(--line)}
  table.plan thead th.corner{z-index:3}
  thead th{background:#0A3A42;color:#fff;padding:0;position:sticky;top:0;z-index:3;height:1px}/* height:1px = astuce pour que .dh-cell (height:100%) se résolve à la hauteur RENDUE de la cellule */
  /* Cellule d'en-tête en colonne flex : la rangée M/A (`.sub`) est poussée en BAS de chaque cellule
     (`.day-h` en flex:1 occupe le reste). Ainsi le trait horizontal M/A est aligné d'une colonne à
     l'autre même si un libellé de jour est plus haut (ex. la ligne « Fête nationale » d'un férié). */
  .dh-cell{display:flex;flex-direction:column;height:100%;min-height:100%}
  .dh-cell>.day-h{flex:1 1 auto}
  .dh-cell>.sub{flex:0 0 auto}
  thead .day-h{padding:11px 6px 9px;text-align:center;font-weight:600}
  thead .day-h .dnum{font-size:16px;font-weight:800;display:block}
  thead .day-h .dname{font-size:10.5px;text-transform:uppercase;letter-spacing:1px;color:rgba(238,222,198,.8);font-weight:600}
  thead .day-h .dmon{display:block;font-size:9px;text-transform:uppercase;letter-spacing:.6px;color:rgba(238,222,198,.62);font-weight:600;margin-top:1px}
  thead .day-h.today{background:rgba(227,172,43,.22)}
  thead .day-h.today .dmon{color:var(--champagne)} /* AA : le libellé de mois reste lisible sur la teinte « aujourd'hui » (≥ 4.5:1) */
  thead .sub{display:flex;border-top:1px solid rgba(255,255,255,.12)}
  thead .sub span{flex:1;font-size:9.5px;text-transform:uppercase;letter-spacing:.5px;padding:4px 0;color:rgba(255,255,255,.9);font-weight:600;text-align:center}
  thead .sub span:first-child{border-right:1px solid rgba(255,255,255,.12)}
  .subh b{font-weight:800;margin-left:4px;font-size:10.5px}
  /* Complet / au-delà : plus de couleur d'état (or/rouge). Repère NEUTRE clair sur le bandeau
     sombre + pictogramme d'alerte ; « au-delà » a un fond un peu plus marqué. */
  .subh.full{color:#fff;background:rgba(255,255,255,.16);font-weight:800;border-radius:5px}
  .subh.over{color:#fff;background:rgba(255,255,255,.26);font-weight:800;border-radius:5px}
  .subh-w{width:10px;height:10px;margin-left:3px;vertical-align:-1px}
  table.plan.month .subh b{display:none}
  thead th.corner{background:#0A3A42;text-align:left;padding:16px 18px;vertical-align:middle}
  thead th.corner .t{font-size:12px;text-transform:uppercase;letter-spacing:1.2px;color:var(--gold);font-weight:700}
  thead th.corner .t .t-count{color:rgba(255,255,255,.65);font-weight:600;letter-spacing:.5px}
  thead th.corner .s{font-size:11px;color:rgba(255,255,255,.7);font-weight:500;margin-top:2px}

  tbody th.name{padding:12px 16px;vertical-align:middle;background:var(--surface);text-align:left;font-weight:400} /* reset défauts <th> (scope=row) */
  .who{display:flex;align-items:center;gap:11px}
  .avatar{width:34px;height:34px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;font-size:12.5px;font-weight:700;color:#fff}
  .who .who-nm{flex:1;min-width:0}
  .who .nm{font-size:14px;font-weight:600;color:var(--ink-2);line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .who .rl{font-size:11.5px;color:var(--grey);font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .who .cnt{margin-left:auto;font-size:11px;font-weight:700;color:var(--teal-dark);background:var(--light);border-radius:20px;padding:3px 9px;white-space:nowrap}
  body:not(.is-admin) .who .cnt{display:none}

  td.day{padding:5px;vertical-align:middle}
  td.day.today{background:rgba(227,172,43,.06)}
  .halves{display:flex;gap:5px}
  .hf{position:relative;flex:1;height:44px;border-radius:9px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.12s;user-select:none;border:1.5px solid var(--fill-bd);background:var(--fill);color:var(--fill-ink)}
  .hf:hover{background:#E4EEF0;border-color:#C9DCE0}
  .hf.on{color:#fff}
  .hf.on-desk{background:var(--green);border-color:var(--green);box-shadow:0 3px 9px rgba(63,169,133,.30)}
  .hf.on-maybe{background:var(--maybe);border-color:var(--maybe);box-shadow:0 3px 9px rgba(200,129,26,.28)}
  .hf.on-shared{background:var(--shared);border-color:var(--shared);box-shadow:0 3px 9px rgba(54,103,201,.28)}
  .hf.on:hover{filter:brightness(1.03)}
  .hf-ic{display:flex;align-items:center;justify-content:center;pointer-events:none}
  .hf svg{width:17px;height:17px;opacity:0;transition:.12s}
  .hf .hf-g{font-weight:800;font-size:15px;line-height:1;opacity:0;transition:.12s}
  .hf.on svg,.hf.on .hf-g{opacity:1}
  .hf.busy{opacity:.55;pointer-events:none}
  /* Bouton ⋯ : accès au sélecteur d'état (peut-être / espace partagé). Discret, révélé au survol. */
  .hf-more{position:absolute;top:1px;right:1px;width:16px;height:14px;padding:0;border:0;border-radius:5px;background:transparent;color:inherit;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:.12s}
  .hf-more svg{width:13px;height:13px}
  .hf:hover .hf-more,.hf:focus-within .hf-more{opacity:1}
  /* ⋯ (accès direct à « peut-être / espace partagé ») visible par défaut à la souris — sinon indécouvrable.
     Cases actives : dots blancs sur fond coloré. Cases VIDES (gris clair) : dots ASSOMBRIS (#3E5157) +
     pastille discrète — le currentColor gris à faible opacité était quasi invisible sur le gris (retour user). */
  .hf.on .hf-more{opacity:.6}
  .hf:not(.on) .hf-more{opacity:.85;color:#33454B;background:rgba(74,92,100,.14)}
  .hf-more:hover{background:rgba(255,255,255,.28)}
  .hf:not(.on) .hf-more:hover{opacity:1;background:rgba(90,107,114,.2)}
  /* Tactile : le ⋯ devient une vraie cible visible (souris = survol) ; cibles nav ≥ 40-44px. */
  @media(pointer:coarse){
    .hf-more{opacity:.9;width:28px;height:24px;border-radius:6px;background:rgba(90,107,114,.12)}
    .hf.on .hf-more{background:rgba(255,255,255,.22)}
    .btn-ico{min-width:44px;min-height:44px}
    .up-nav,.pg-btn{min-width:40px;min-height:40px}
    /* Cadenas de la ligne « semaine » : SEUL accès aux journées bloquées sur mobile (les en-têtes
       de colonne, qui portent l'autre cadenas, sont masqués en vue cartes) — et bouton de densité,
       oublié du même bloc. 32 et 30 px : au-dessus du plancher WCAG 2.5.8 mais sous la convention
       44 px que ce bloc applique déjà partout ailleurs. Le dessin (icône 15 px) ne bouge pas, seule
       la boîte grandit ; la ligne peut refluer (@media max-width:768) donc rien ne sort de l'écran. */
    .up-lock,.dens-btn{min-width:44px;min-height:44px}
    .up-edit{min-height:44px}   /* zone tactile ; largeur libre (le libellé « Modifier » l'étire) */
  }
  /* Vue CARTES tactile : le ⋯ est le seul chemin découvrable vers « peut-être » et « espace partagé »
     (un appui simple sur la case ne fait que basculer « au poste »). Son DESSIN reste petit — 28×24,
     discret dans le coin d'une case déjà chargée — mais sa ZONE DE CONTACT est portée à 44×44 par un
     pseudo-élément, ancré sur le coin haut-droit de la case pour ne mordre ni sur la case voisine
     (8 px de gouttière) ni au-delà du bord. La case fait 99×44 : il reste ~55 px de large pour
     l'appui « au poste ». Et l'erreur de visée s'inverse dans le bon sens — on ouvre un menu
     (annulable, rien d'écrit) au lieu d'écrire immédiatement une présence en base.
     Borné à ≤768 px : au-delà (tablette), c'est la GRILLE qui s'affiche, avec des demi-journées
     étroites qu'une zone de 44 px recouvrirait entièrement. */
  @media(pointer:coarse) and (max-width:768px){
    .hf-more::before{content:"";position:absolute;top:-1px;right:-1px;width:44px;height:44px}
  }
  /* Vue MOIS : les demi-journées n'y font que ~19 px de large. Le ⋯ (16 px, et 28 px sur tactile)
     recouvrait jusqu'à 88 % de la cellule et débordait sur la gauche → d'où le « décalage » constaté.
     On le réduit ET on le masque au repos : il ne réapparaît qu'au SURVOL (souris). Sur tactile il n'y
     a pas de survol → cellules propres ; la vue Mois y reste consultative (le clic bascule la présence,
     et « peut-être » / « espace partagé » se posent en vue Semaine, où les cases sont larges).
     Spécificité volontairement élevée : doit primer sur .hf:not(.on) .hf-more et @media(pointer:coarse). */
  table.plan.month .hf-more{width:14px;height:12px;border-radius:4px}
  /* …et la zone de contact élargie du tactile n'y a pas sa place non plus : 44 px sur une cellule
     de ~19 px avalerait la case entière (et ses voisines). La vue Mois reste consultative. */
  table.plan.month .hf-more::before{display:none}
  table.plan.month .hf-more svg{width:10px;height:10px}
  table.plan.month .hf:not(.on) .hf-more,
  table.plan.month .hf.on .hf-more{opacity:0}
  table.plan.month .hf:hover .hf-more,
  table.plan.month .hf:focus-within .hf-more{opacity:.95}
  tbody tr:hover th.name,tbody tr:hover td.day{background:var(--surface-2)}
  /* Jours fériés : en-tête rouge (sur fond sombre) + colonne teintée, saisie toujours possible */
  thead th.holiday .day-h{background:rgba(217,83,79,.20)}
  thead th.holiday .day-h.today{background:rgba(217,83,79,.30)}
  .day-h.holiday .dname{color:#FFC3BD}
  .day-h.holiday .dnum{color:#FF9A90}
  .day-h.holiday .dmon{color:#FF9A90} /* opaque : libellé de mois « jour férié » ≥ 4.5:1 sur la teinte rouge du thead (WCAG AA) — la version à 85% tombait à 4,26:1 */
  .day-h .holn{display:block;font-size:8.5px;font-weight:700;color:#FF9A90;text-transform:uppercase;letter-spacing:.3px;line-height:1.15;margin-top:2px;white-space:normal}
  table.plan.month .holn{display:none}
  td.day.holiday{background:rgba(217,83,79,.06)}
  tbody tr:hover td.day.holiday{background:rgba(217,83,79,.11)}
  /* --- Journée BLOQUÉE par un admin (CODIR sur site…) ---
     Même teinte rouge qu'un férié, parce que ça veut dire la même chose : on ne saisit pas. Ce que
     la couleur seule ne dit pas — « la surface est fermée » et non « c'est chômé » — est porté par
     les HACHURES de la case. La teinte de l'en-tête est un cran plus soutenue qu'un férié : celui-ci
     est subi par le calendrier, celui-là est une décision qu'on doit remarquer. */
  /* Cadenas de blocage dans l'en-tête (admins seuls). En ABSOLU : la rangée M/A doit rester alignée
     d'une colonne à l'autre (cf. .dh-cell), un bouton en flux la décalerait. Discret au repos,
     franc au survol — c'est une action rare et lourde de conséquences. */
  thead .day-h{position:relative}
  .dayblock{position:absolute;top:3px;right:3px;z-index:1;width:22px;height:22px;padding:0;border:none;border-radius:6px;
    background:transparent;color:rgba(255,255,255,.42);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.14s}
  .dayblock svg{width:13px;height:13px}
  .dayblock:hover{background:rgba(255,255,255,.16);color:#fff}
  .dayblock:focus-visible{outline:2px solid var(--gold);outline-offset:1px;color:#fff}
  .dayblock.on{color:#FF9A90}
  .dayblock.on:hover{background:rgba(217,83,79,.30);color:#fff}
  thead th.blocked .day-h{background:rgba(217,83,79,.28)}
  thead th.blocked .day-h.today{background:rgba(217,83,79,.36)}
  .day-h.blocked .dname{color:#FFC3BD}
  .day-h.blocked .dnum,.day-h.blocked .dmon{color:#FF9A90}
  td.day.blocked{background:rgba(217,83,79,.06)}
  tbody tr:hover td.day.blocked{background:rgba(217,83,79,.11)}
  /* Case d'une journée dont le bureau est fermé : hachurée (la surface « bureau » est indisponible)
     mais CLIQUABLE — elle mène à l'espace partagé, qui reste ouvert. Le glyphe est celui du
     coworking, pas un cadenas : il annonce ce que le clic va faire. */
  /* ⚠️ Deux messages à ne pas confondre : le FOND rouge hachuré dit « surface bureau indisponible »,
     le GLYPHE dit ce que le clic va faire — se déclarer en espace partagé. Peindre le glyphe en
     rouge au repos et ne révéler le bleu qu'au survol trompait tout le monde sur tactile, où le
     survol n'existe pas : la case entière parlait le langage de l'interdit alors qu'un simple appui
     inscrivait en coworking, c'est-à-dire l'objet même de la fonctionnalité. */
  /* ⚠️ La BORDURE est le seul repère qui survive partout : en vue MOIS le motif texte est masqué et
     le cadenas admin absent, en vue CARTES le glyphe est masqué (.hf:not(.on) svg{display:none}).
     Elle était posée à 45 % d'opacité, soit 1,93:1 sur le fond de case (mesuré) — sous le 3:1 des
     éléments non textuels : une case fermée se lisait comme une case vide. On la passe donc pleine
     (5,21:1 en clair, 5,18:1 en sombre), exactement la teinte que le survol révélait déjà — et pour
     la même raison qu'en v1.0.38 : sur tactile il n'y a pas de survol, l'état doit se voir AU REPOS.
     Elle reste BLEUE et dashed : le rouge parlerait d'interdit, alors que la case est cliquable.
     Les hachures rouges (« surface bureau indisponible ») montent de .13 à .30 — repère secondaire,
     assez dense pour se voir dans une cellule de vue Mois sans virer au panneau d'interdiction. */
  .hf.shut{cursor:pointer;border-style:dashed;border-color:var(--shared);color:var(--shared);
    background:repeating-linear-gradient(135deg,rgba(217,83,79,.30) 0 5px,transparent 5px 11px),var(--surface-2);box-shadow:none}
  /* Survol : MÊME densité de hachures qu'au repos (.30), seule la couleur bascule — la surface
     passe du « bureau indisponible » à « ce clic vous inscrit en coworking ». Laisser le survol à
     .12 face à un repos à .30 ferait paraître la case plus VIDE au survol, à contresens. */
  .hf.shut:hover{color:var(--shared);border-color:var(--shared);
    background:repeating-linear-gradient(135deg,rgba(54,103,201,.30) 0 5px,transparent 5px 11px),var(--surface-2)}
  .hf.shut svg{opacity:1;width:15px;height:15px}
  /* Créneau saisi AVANT le blocage : conservé (on ne supprime la déclaration de personne en douce),
     signalé par un liseré rouge, et cliquable — le clic ne fait plus qu'une chose : le retirer. */
  .hf.to-clear{box-shadow:0 0 0 2px var(--surface),0 0 0 4px var(--danger)}
  .hf.to-clear::after{content:"!";position:absolute;top:-7px;right:-7px;width:17px;height:17px;border-radius:50%;
    background:var(--danger-bg);color:#fff;font-size:11px;font-weight:800;display:flex;align-items:center;justify-content:center;border:2px solid var(--surface)}
  /* Ligne de la personne connectée : mise en avant nette (bande teintée + accent).
     `:not(.solo)` — ces repères servent à DISTINGUER sa ligne des autres. Quand elle est la seule
     affichée (l'étendue par défaut depuis v1.0.23), ils n'ont plus rien à distinguer : bande, accent
     teal et trait de figeage deviennent une décoration inexplicable autour d'un tableau d'une ligne.
     Conditionner À LA SOURCE plutôt qu'annuler après coup : une contre-règle plus spécifique
     écraserait aussi les teintes de jour (férié / aujourd'hui), qui doivent réapparaître.
     `.solo` est posé par applyFilter() dès qu'une seule ligne est visible. */
  table.plan:not(.solo) tbody tr.me-row td{background:rgba(4,139,154,.06)}
  table.plan:not(.solo) tbody tr.me-row th.name{box-shadow:inset 4px 0 0 var(--teal),1px 0 0 var(--line)}
  tr.me-row td{border-bottom:1px solid var(--line)}
  /* #7 La LIGNE de l'utilisateur connecté reste figée juste sous l'en-tête (lui-même figé), pour se
     comparer aux autres sans la perdre de vue en faisant défiler — sur les DEUX vues (Mois et Semaine).
     Ne fonctionne que grâce au cadre borné (.grid-scroll max-height, cf. #3) : sans lui, aucun
     défilement interne → rien à quoi s'accrocher. --thead-h = hauteur rendue de l'en-tête, mesurée en JS.
     Fond OPAQUE obligatoire (sinon le contenu défilant transparaît sous la ligne).
     `:not(.solo)` : seule ligne affichée → rien à figer ni à comparer (cf. bloc ci-dessus). */
  table.plan:not(.solo) tbody tr.me-row>th.col-name,
  table.plan:not(.solo) tbody tr.me-row>td{position:sticky;top:var(--thead-h,56px);z-index:2;background:var(--green-soft);border-bottom:2px solid var(--teal)}
  table.plan:not(.solo) tbody tr.me-row>th.col-name{z-index:4} /* coin haut-gauche figé : au-dessus des autres cellules collantes */
  /* Exception férié : sa teinte est SEMI-TRANSPARENTE et sa spécificité l'emporte sur le fond opaque
     ci-dessus (en sombre surtout : le préfixe :root[data-theme="dark"] pèse 2 sélecteurs de plus) →
     la cellule figée laissait transparaître le contenu qui défile dessous. On SUPERPOSE la teinte à
     un fond opaque (dégradé plat sur --green-soft) : on garde le repère férié ET l'opacité, sans
     figer en dur une couleur composite qui se désynchroniserait des variables. */
  table.plan:not(.solo) tbody tr.me-row>td.day.holiday{background:linear-gradient(rgba(217,83,79,.06),rgba(217,83,79,.06)) var(--green-soft)}
  table.plan:not(.solo) tbody tr.me-row>td.day.blocked{background:linear-gradient(rgba(217,83,79,.06),rgba(217,83,79,.06)) var(--green-soft)}
  .emptyrow td{padding:34px;text-align:center;color:var(--grey);font-size:14px}

  .grid-hint{margin:16px 2px 8px;font-size:12.5px;color:var(--grey);font-weight:500}
  /* Barre au-dessus de la grille : « Répliquer la semaine » (#4). L'étendue d'affichage n'a plus de
     bouton ici — sa ligne par défaut, dépliage via #hiddenNote sous le tableau. */
  .row-scope{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0;grid-column:1;justify-self:start}
  .rs-repl:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
  /* `min-height` et NON `height` : une hauteur figée laissait le libellé déborder de la pastille dès
     qu'il passait à la ligne (vu en paysage sur téléphone). La pastille grandit désormais avec son
     contenu — un bouton ne doit jamais pouvoir être plus petit que son texte. */
  .rs-repl{display:inline-flex;align-items:center;gap:8px;min-height:34px;padding:5px 15px;border:1px solid var(--teal);background:var(--green-soft);color:var(--teal-dark);border-radius:100px;font:inherit;font-size:12.5px;font-weight:700;cursor:pointer;transition:.15s;line-height:1.25}
  .rs-lbl{text-align:left}
  /* Largeurs INTERMÉDIAIRES (paysage téléphone, petite tablette) : la colonne de gauche est trop
     étroite pour « Répliquer la semaine précédente ». On garde le mot porteur ; le sens complet reste
     dans `aria-label` + `title`. Sous 820 px le bouton est pleine largeur : le libellé entier y tient. */
  @media(min-width:821px) and (max-width:1150px){
    .rs-more{display:none}
    .rs-repl{white-space:nowrap}
  }
  /* Largeurs INTERMÉDIAIRES (paysage téléphone, petite tablette) : la colonne de gauche est trop
     étroite pour « Répliquer la semaine précédente ». On garde le mot porteur ; le sens complet reste
     dans `aria-label` + `title`. Sous 820 px le bouton est pleine largeur : le libellé entier y tient. */

  .rs-repl:hover{background:var(--teal-dark);color:#fff;border-color:var(--teal-dark)}
  .rs-repl svg{width:15px;height:15px;flex:none}
  /* Modale de réplication : récap des créneaux à créer. */
  .rp-intro{font-size:13.5px;color:var(--ink-2);margin-bottom:12px}
  .rp-list{display:flex;flex-direction:column;gap:8px;max-height:46vh;overflow-y:auto}
  .rp-day{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 10px;padding:8px 0;border-top:1px solid var(--line)}
  .rp-day:first-child{border-top:none}
  .rp-dl{min-width:118px;font-weight:700;font-size:12.5px;color:var(--ink-2);text-transform:capitalize}
  .rp-slots{display:flex;flex-wrap:wrap;gap:6px}
  .rp-slot{font-size:11.5px;font-weight:700;padding:3px 9px;border-radius:100px;background:var(--green-soft);color:var(--green)}
  .rp-slot.st-maybe{background:var(--maybe-soft);color:var(--maybe)}
  .rp-slot.st-shared{background:var(--shared-soft);color:var(--shared)}
  .rp-note{margin-top:12px;font-size:12px;color:var(--grey);font-style:italic}
  /* #4A Bandeau « semaine prochaine non renseignée » : discret, mais l'action est juste à côté. */
  .nudge{display:flex;align-items:center;flex-wrap:wrap;gap:10px 14px;margin:0 0 14px;padding:12px 16px;border:1px solid var(--teal);background:var(--green-soft);border-radius:14px;font-size:13.5px;color:var(--ink-2)}
  .nudge-ic{width:20px;height:20px;flex:none;color:var(--teal-dark)}
  .nudge-tx{flex:1;min-width:170px}
  /* Mémo « rappel agenda » : un CONSEIL, pas une action attendue → teinte neutre plutôt que le teal
     du bandeau « semaine prochaine », qui doit rester le seul à réclamer l'œil. */
  .nudge-tip{border-color:var(--line);background:var(--surface-2)}
  /* Incidents signalés (bandeau du haut). Ton AMBRE, distinct du rouge « journée fermée » : c'est un
     avertissement, pas une interdiction. Texte en --ink-2 (contraste garanti en clair ET sombre) ;
     l'état passe par la bordure et l'icône, jamais par la couleur du texte seul. */
  .incidents{display:flex;flex-direction:column;gap:8px;margin:0 0 14px}
  /* ROUGE d'alerte, comme le bandeau « journee fermee » (`.nudge-block`) : un incident doit se REPERER
     d'un coup d'oeil. On reprend le rouge deja eprouve de l'app plutot qu'une teinte inedite.
     ATTENTION contraste : `--danger` (#D9534F) sert au LISERE et a l'ICONE (glyphes, seuil 3:1) ; le
     TEXTE reste sur `--ink-2`, seul moyen de tenir le 4,5:1 en theme clair ET sombre (scans axe). */
  .inc-item{display:flex;align-items:flex-start;gap:11px;padding:13px 15px;border:1px solid var(--danger);border-left:4px solid var(--danger);background:rgba(217,83,79,.09);border-radius:12px;font-size:13.5px;color:var(--ink-2);line-height:1.45}
  .inc-ic{width:21px;height:21px;flex:none;margin-top:0;color:var(--danger)}
  .inc-tx{flex:1;min-width:0}
  .inc-by{display:block;font-size:11.5px;color:var(--grey);margin-top:2px}
  /* Corbeille (et non une croix) : le geste supprime pour toute l'équipe, l'icône doit l'annoncer. */
  .inc-del{flex:none;border:0;background:none;color:var(--grey);cursor:pointer;padding:4px;border-radius:7px;display:inline-flex;align-items:center;justify-content:center;min-width:32px;min-height:32px}
  .inc-del svg{width:16px;height:16px}
  .inc-del:hover{color:var(--danger);background:var(--surface)}
  /* Alerte dans l'en-tête du bloc « semaine » : rouge, mais discrète — elle DOUBLE le bandeau du haut
     pour la semaine regardée, elle ne le remplace pas. */
  .up-alert{display:inline-flex;align-items:center;flex:none;font-size:11.5px;font-weight:700;color:var(--ink-2);background:rgba(217,83,79,.12);border:1px solid var(--danger);border-radius:999px;padding:3px 10px;margin-left:10px;white-space:nowrap}
  :root[data-theme="dark"] .up-alert{background:rgba(240,115,111,.14);border-color:#F0736F}
  /* Mobile : la pastille QUITTE la ligne du titre. Placée à côté, elle volait la largeur d'un titre
     déjà en `flex:1` — « SEMAINE EN COURS (S31) » se cassait sur quatre lignes. Elle passe donc sur
     SA PROPRE ligne, pleine largeur, sous l'en-tête (l'en-tête est déjà en `flex-wrap:wrap`). */
  @media(max-width:640px){
    .up-alert{order:99;width:100%;margin-left:0;justify-content:center;box-sizing:border-box}
  }
  /* Historique des incidents (admin) — carte AUTONOME, pleine largeur.
     ⚠️ Elle réutilisait `.sso-card`, bornée à 560 px : comme cette règle est définie PLUS BAS dans le
     fichier et à spécificité égale, c'est elle qui l'emportait — le tableau restait comprimé quoi que
     `.ih-card` déclare. Une classe d'état ne doit pas dépendre de l'ordre du fichier. */
  /* L'écran reprend le gabarit `.panel` du Journal d'activité (pleine largeur) : plus de carte à
     largeur bornée, et les mêmes filtres/pagination visuellement. */
  .ih-table th[data-sort]{cursor:pointer;user-select:none}
  .ih-table th.sorted::after{content:"";display:inline-block;margin-left:6px;border:4px solid transparent;border-bottom-color:currentColor;vertical-align:middle}
  .ih-table th.sorted[aria-sort="descending"]::after{border-bottom-color:transparent;border-top-color:currentColor;margin-bottom:-4px}
  .ih-table td{vertical-align:top}
  .ih-sub{display:block;font-size:11px;color:var(--grey);margin-top:2px}
  .ih-tag{display:inline-block;font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px;border:1px solid var(--line);color:var(--ink-2);white-space:nowrap}
  .ih-tag.on{border-color:var(--danger);background:rgba(217,83,79,.12)}
  .ih-tag.off{background:var(--surface-2)}
  .ih-closed td{color:var(--grey)}
  .inc-presets{display:flex;flex-wrap:wrap;gap:8px;margin:2px 0 4px}
  .inc-preset{border:1px solid var(--line);background:var(--surface-2);color:var(--ink-2);font-family:inherit;font-size:12px;padding:6px 11px;border-radius:999px;cursor:pointer}
  .inc-preset:hover{border-color:var(--teal)}
  /* Période : deux listes côte à côte, empilées quand la place manque (mobile). */
  .inc-range{display:flex;gap:12px;flex-wrap:wrap}
  .inc-range .af-field{flex:1;min-width:150px}
  .inc-range select{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:10px;padding:10px 12px;font-family:inherit;font-size:14px;color:var(--ink-2);background:var(--surface)}
  /* Dit, AVANT de valider, sur quels jours la bannière apparaîtra. */
  .inc-hint{font-size:12px;color:var(--grey);line-height:1.5;margin:8px 0 14px}
  /* Barre d'actions en tête de contenu (au-dessus des bandeaux). */
  .top-actions{display:flex;justify-content:flex-end;margin:0 0 12px}
  .ta-inc{display:inline-flex;align-items:center;gap:8px;min-height:40px}
  .ta-inc svg{width:17px;height:17px;color:var(--danger);flex:none}
  @media(max-width:540px){.top-actions{justify-content:stretch}.ta-inc{width:100%;justify-content:center;min-height:44px}}
  /* Journée bloquée : ce bandeau-là n'invite à rien, il informe d'une contrainte → teinte d'alerte,
     et aucun bouton (il n'est pas masquable : la fenêtre d'affichage est de 7 jours). */
  .nudge-block{border-color:var(--danger);background:rgba(217,83,79,.09)}
  .nudge-block .nudge-ic{color:var(--danger)}
  /* Le teal de base ne fait que 3.67:1 sur le vert doux (il en faut 4.5) → teal foncé, 5.7:1.
     Vaut pour les 2 encarts posés sur --green-soft : le bandeau et la note sous le tableau. */
  /* #4B Rappel de saisie (profil) : jour + heure → .ics récurrent. */
  /* Grille plutôt que flex : en flex, le champ Heure (largeur native, variable selon l'OS) débordait
     de son item sur iOS et le bouton lui passait par-dessus. Ici les 2 colonnes sont égales par
     construction et le bouton occupe toute la ligne suivante — plus aucun recouvrement possible. */
  .rem-row{display:grid;grid-template-columns:1fr 1fr;gap:10px;align-items:end;margin-top:10px}
  .rem-row .btn{grid-column:1/-1;justify-self:start}
  /* `.field label` (0,1,1) impose display:block + margin-bottom : il faut être plus spécifique,
     sinon le libellé se colle au champ au lieu de le surmonter, et la marge casse l'alignement. */
  .field .rem-f{display:flex;flex-direction:column;gap:4px;margin:0;min-width:0}
  /* Hauteur imposée aux deux : le champ Heure natif est plus haut que le menu (nettement sur iOS),
     ce qui désalignait les libellés. Même largeur ET même hauteur → les 2 champs sont identiques. */
  /* Jour ET Heure sont deux <select> (cf. REM_TIMES) : même nature → même taille partout, y compris
     là où un input[type=time] natif refusait de se laisser dimensionner (iOS). */
  .rem-f .sel{width:100%;height:40px}
  .legend{display:flex;align-items:center;gap:10px 32px;flex-wrap:wrap;margin:4px 2px 30px;font-size:12.5px;color:var(--ink-2);font-weight:500}
  .lg-grp{display:flex;align-items:center;gap:8px 16px;flex-wrap:wrap}
  .lg-cap{font-size:10px;text-transform:uppercase;letter-spacing:.6px;font-weight:800;color:var(--grey)}
  .legend .it{display:flex;align-items:center;gap:7px}
  /* pastille = même rendu que la case (couleur + glyphe blanc) pour une lecture immédiate */
  .swatch{width:20px;height:20px;border-radius:6px;border:1.5px solid transparent;display:inline-flex;align-items:center;justify-content:center;color:#fff;flex:none;font-size:12px;font-weight:800}
  .swatch svg{width:13px;height:13px}
  .swatch.on{background:var(--green)}
  .swatch.maybe{background:var(--maybe)}
  .swatch.shared{background:var(--shared)}
  .swatch.off{background:var(--fill);border-color:var(--fill-bd)}
  /* M / A : badge neutre (foncé) — la couleur reste réservée aux ÉTATS, pas aux demi-journées */
  .lg-ma{display:inline-flex;align-items:center;justify-content:center;min-width:19px;height:19px;padding:0 4px;background:var(--ink-2);color:#fff;border-radius:5px;font-size:11px;font-weight:800}
  /* ---- Sélecteur d'état de présence (popover) ---- */
  .pk-pop{position:fixed;z-index:1200}
  .pk-menu{background:var(--surface);border:1px solid var(--line);border-radius:14px;box-shadow:0 14px 36px rgba(10,58,66,.20);padding:6px;min-width:196px}
  .pk-opt{display:flex;align-items:center;gap:10px;width:100%;border:0;background:transparent;padding:9px 10px;border-radius:9px;cursor:pointer;font:inherit;font-size:14px;color:var(--ink);text-align:left}
  .pk-opt:hover,.pk-opt:focus-visible{background:var(--light);outline:none}
  .pk-opt .pk-lbl{flex:1}
  .pk-opt .pk-dot{width:15px;height:15px;border-radius:5px;flex:0 0 auto;border:1.5px solid var(--fill-bd);background:var(--fill)}
  .pk-opt.pk-desk .pk-dot{background:var(--green);border-color:var(--green)}
  .pk-opt.pk-maybe .pk-dot{background:var(--maybe);border-color:var(--maybe)}
  .pk-opt.pk-shared .pk-dot{background:var(--shared);border-color:var(--shared)}
  .pk-opt.sel{font-weight:700}
  .pk-check{color:var(--teal);font-weight:800}
  /* ---- Compteurs « peut-être » / « espace partagé » sur le tableau de bord ---- */
  .tc-extra{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
  .tc-x{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:600;padding:4px 11px;border-radius:100px}
  .tc-x i{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
  .tc-x.maybe{background:var(--maybe-soft);color:#8A5A0F}
  .tc-x.maybe i{background:var(--maybe)}
  .tc-x.shared{background:var(--shared-soft);color:#274a97}
  .tc-x.shared i{background:var(--shared)}
  /* Bandeau week-end (carte « aujourd'hui » masquée : rien à renseigner) */
  .today-we .tc-head{margin-bottom:0}
  .tc-we{display:flex;align-items:center;gap:10px;margin-top:10px;font-size:13.5px;color:var(--grey);line-height:1.45}
  .tc-we svg{width:20px;height:20px;flex:0 0 auto;color:var(--teal)}
  .tc-st{width:8px;height:8px;border-radius:50%;flex:0 0 auto;margin:0 1px}
  .tc-st.maybe{background:var(--maybe)}
  .tc-st.shared{background:var(--shared)}
  /* Peut-être / Espace partagé : fond teinté clair (état lisible d'un coup d'œil) au lieu d'un fin anneau. */
  .tc-person.st-maybe{border-color:var(--maybe);background:var(--maybe-soft)}
  .tc-person.st-shared{border-color:var(--shared);background:var(--shared-soft)}

  /* Accueil — infos pratiques du bureau (rappels) */
  .office-info{margin:4px 0 30px;border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);box-shadow:var(--shadow);overflow:hidden}
  .oi-head{display:flex;align-items:center;gap:13px;padding:12px 20px;background:linear-gradient(120deg,var(--teal-deeper) 0%,var(--teal) 100%);position:relative;overflow:hidden;width:100%;border:none;text-align:left;cursor:pointer;font-family:inherit}
  .stats-head{border-radius:var(--radius);border:1px solid var(--line);box-shadow:var(--shadow);background:linear-gradient(120deg,#36806E 0%,var(--green) 100%)} /* même gabarit qu'Infos pratiques, accent vert */
  .oi-chev{width:20px;height:20px;margin-left:auto;color:#fff;flex:none;position:relative;z-index:1;transition:transform .2s}
  .oi-head.oi-open .oi-chev{transform:rotate(180deg)}
  .oi-head:focus-visible{outline:2px solid #fff;outline-offset:-3px}
  .oi-head::after{content:"";position:absolute;right:-50px;top:-70px;width:190px;height:190px;border-radius:50%;background:radial-gradient(circle,rgba(227,172,43,.30),transparent 68%);pointer-events:none}
  .oi-badge{width:36px;height:36px;border-radius:11px;flex:none;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.24);color:#fff;position:relative;z-index:1}
  .oi-badge svg{width:20px;height:20px}
  .oi-htxt{position:relative;z-index:1}
  .oi-htxt h3{font-size:16px;font-weight:800;color:#fff;letter-spacing:.2px}
  .oi-htxt p{font-size:12px;color:rgba(238,222,198,.92);font-weight:500;margin-top:1px}
  /* 6 infos → nombre de colonnes DIVISEUR de 6 (3/2/1) pour toujours remplir les lignes,
     y compris en plein écran (l'auto-fit donnait 4-5 colonnes → cases vides en bas). */
  .oi-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--line)}
  @media(max-width:820px){ .oi-grid{grid-template-columns:repeat(2,1fr)} }
  @media(max-width:520px){ .oi-grid{grid-template-columns:1fr} }
  .oi-item{display:flex;align-items:center;gap:13px;padding:15px 20px;background:var(--surface);transition:background .15s}
  .oi-item:hover{background:var(--surface-2)}
  /* Adresse cliquable → Google Maps */
  a.oi-item-link{text-decoration:none;color:inherit;cursor:pointer}
  a.oi-item-link:hover{background:var(--surface-2)}
  a.oi-item-link:hover .oi-val{text-decoration:underline;text-underline-offset:2px}
  .oi-go{display:inline-block;color:var(--teal);font-weight:700;margin-left:2px}
  .oi-ic{width:40px;height:40px;border-radius:12px;flex:none;display:flex;align-items:center;justify-content:center}
  .oi-ic svg{width:20px;height:20px}
  .oi-ic.teal{background:rgba(4,139,154,.12);color:var(--teal)}
  .oi-ic.gold{background:rgba(227,172,43,.18);color:#B9860F}
  .oi-ic.green{background:rgba(63,169,133,.15);color:#36806E}
  .oi-body{display:flex;flex-direction:column;min-width:0}
  .oi-lbl{font-size:10px;text-transform:uppercase;letter-spacing:.9px;font-weight:700;color:var(--grey)}
  .oi-val{font-size:13.5px;font-weight:500;color:var(--ink-2);line-height:1.32;margin-top:3px}
  .oi-val b{font-weight:700;color:var(--teal-dark)}

  /* Aujourd'hui au bureau */
  #todayPanel:empty{display:none}
  #todayPanel{margin-bottom:16px}
  .today-card{background:var(--surface);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);padding:14px 18px}
  .tc-skel{height:58px;border-radius:10px;background:var(--light)}
  .tc-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:11px}
  .tc-title{font-size:12.5px;font-weight:800;color:var(--ink-2);text-transform:uppercase;letter-spacing:.7px}
  .tc-title::before{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--green);margin-right:8px;vertical-align:middle}
  .tc-date{font-size:12.5px;color:var(--grey);text-transform:capitalize}
  .tc-sum{margin-left:auto;font-size:12px;font-weight:600;color:var(--teal-dark)} /* teal-dark : 5,6:1 sur blanc (l'ancien --teal tombait à 4,06:1 pour ce texte normal) */
  .tc-people{display:flex;flex-wrap:wrap;gap:8px}
  .tc-person{display:inline-flex;align-items:center;gap:7px;background:var(--light);border:1px solid var(--line);border-radius:100px;padding:4px 12px 4px 4px;font-size:13px;font-weight:600;color:var(--ink-2)}
  .tc-av{width:26px;height:26px;border-radius:50%;overflow:hidden;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;color:#fff;flex:none}
  .tc-when{font-size:9px;font-weight:800;min-width:16px;height:16px;padding:0 2px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:#fff}
  /* M (ambre) / A (indigo) / J (teal) : MÊMES couleurs à gauche (badges) et à droite (compteurs).
     Pas de confusion avec les états, désormais matérialisés par des pastilles à fond teinté. */
  .tc-when.m{background:#A8530F}
  .tc-when.a{background:#4B57C4}
  .tc-when.d{background:#0A7B88}
  .tc-legend{display:flex;flex-wrap:wrap;gap:14px;margin-top:11px;padding-top:10px;border-top:1px solid var(--light);font-size:11.5px;font-weight:600;color:var(--grey)}
  .tc-legend span{display:inline-flex;align-items:center;gap:5px}
  .tc-legend .tc-when{position:static}
  .tc-empty{font-size:13px;color:var(--grey)}
  /* Synthèse des 5 prochains jours ouvrés (même style que la carte du jour) */
  .up-card{margin-top:14px}
  .up-head{align-items:center;gap:8px;margin-bottom:8px}
  .up-head .tc-title{flex:1;text-align:center}
  .up-nav{flex:none;width:30px;height:30px;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--teal);font-size:17px;font-weight:800;line-height:1;cursor:pointer;font-family:inherit;padding:0}
  .up-nav:hover:not(:disabled){background:var(--light)}
  .up-nav:disabled{opacity:.3;cursor:default}
  .up-nav:focus-visible{outline:2px solid var(--teal);outline-offset:1px}
  .up-reset{flex:none;font-size:12px;white-space:nowrap}
  .up-list{display:flex;flex-direction:column}
  .up-day{display:flex;align-items:center;gap:12px;padding:9px 0;border-top:1px solid var(--light)}
  .up-day:first-child{border-top:none}
  .up-date{flex:0 0 92px;font-size:12.5px;font-weight:700;color:var(--ink-2)}
  /* Chips photo + prénom (mêmes styles .tc-person que « Aujourd'hui ») */
  .up-avs{flex:1;display:flex;flex-wrap:wrap;align-items:center;gap:6px;min-width:0}
  .up-pname{white-space:nowrap}
  /* #1 Densité des noms (data-dens sur #todayPanel) : 0 = icônes · 1 = trigramme · 2 = prénom.
     Défaut prénom (desktop) / icônes (mobile) posé par le JS. Pilote AUSSI .up-pname (sinon masqué
     en mobile). .lbl-tri masqué par défaut ; .lbl-name visible par défaut (= densité 2). */
  #todayPanel .lbl-tri{display:none}
  #todayPanel[data-dens="0"] .lbl-name,#todayPanel[data-dens="0"] .up-pname{display:none}
  #todayPanel[data-dens="0"] .up-person{padding-right:4px}
  #todayPanel[data-dens="1"] .lbl-name{display:none}
  #todayPanel[data-dens="1"] .lbl-tri{display:inline}
  .dens-btn{flex:none;width:30px;height:30px;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--teal-dark);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;transition:.15s}
  .dens-btn:hover{border-color:var(--teal)}
  .dens-btn svg{width:16px;height:16px}
  .dens-btn:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
  /* Bouton « Modifier » (admins) : bascule le mode édition. Neutre au repos, plein teal quand actif
     (l'admin voit d'un coup d'œil qu'il peut retirer/fermer). Icône crayon → coche. */
  .up-edit{flex:none;display:inline-flex;align-items:center;gap:5px;height:30px;padding:0 10px;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--link);cursor:pointer;font-family:inherit;font-size:12px;font-weight:700;transition:.15s;white-space:nowrap}
  .up-edit svg{width:15px;height:15px;flex:none}
  .up-edit:hover{border-color:var(--teal)}
  .up-edit.on{background:var(--teal-dark);color:#fff;border-color:var(--teal-dark)}
  .up-edit:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
  :root[data-theme="dark"] .up-edit{background:var(--surface-2)}
  .up-more{font-size:11px;font-weight:700;color:var(--grey);align-self:center;margin-left:2px}
  .up-none{font-size:12px;color:var(--grey);font-style:italic}
  .up-nums{display:flex;gap:5px;flex:none}
  /* ⚠️ `.up-nums` est en `flex:none` et ne rétrécit donc JAMAIS : sur une journée à la fois BLOQUÉE
     et complète, la colonne de droite porte pastille du motif + 2 compteurs + « Complet » + cadenas,
     et déborde de l'écran étroit. `html{overflow-x:hidden}` interdisant tout panoramique, le dernier
     élément — le cadenas, SEUL accès mobile aux journées bloquées — devenait inatteignable, très
     précisément dans le cas d'usage principal (bloquer une journée déjà pleine).
     Deux garde-fous : la ligne peut refluer, et le cadenas passe en tête pour n'être jamais
     le premier rogné si elle déborde malgré tout. */
  @media(max-width:768px){
    /* Chaque jour devient une CARTE EMPILÉE : ligne d'en-tête (date à gauche, compteurs à droite),
       puis les personnes EN DESSOUS, pleine largeur. Auparavant les trois blocs (date, personnes,
       compteurs) étaient sur une seule ligne flex `align-items:center` : dès que les pastilles
       s'enroulaient sur plusieurs lignes, la date et les compteurs flottaient à MI-HAUTEUR et
       chevauchaient la pastille du milieu. L'ordre flex remet tout d'aplomb sans toucher au HTML. */
    .up-day{flex-wrap:wrap;align-items:center;row-gap:8px;column-gap:8px}
    .up-date{order:1;flex:1 1 auto;white-space:nowrap}     /* gauche de l'en-tête */
    .up-nums{order:2;flex:none;flex-wrap:wrap;justify-content:flex-end;max-width:72%}  /* droite de l'en-tête */
    .up-avs{order:3;flex:0 0 100%}                          /* les personnes : ligne pleine largeur dessous */
    .up-lock{order:-1}                                       /* dans .up-nums : jamais le premier rogné */
    /* Journée bloquée : la ligne des personnes, désormais pleine largeur, commence pile sur le
       liseré rouge inséré à gauche (box-shadow inset 3px). Sans dégagement, « personne » (ou une
       pastille) mord dessus. On l'écarte comme la date au-dessus (padding-left:9px). */
    .up-day.blocked .up-avs{padding-left:9px}
  }
  .up-cnt{min-width:22px;height:22px;padding:0 5px;border-radius:7px;display:inline-flex;align-items:center;justify-content:center;font-size:11.5px;font-weight:800;color:#fff}
  /* Compteurs de droite : M (ambre foncé) / A (indigo) distincts + lettre. La capacité reste
     prioritaire (or = complet, rouge = au-delà) via .full/.over. */
  .up-cnt.m{background:#A8530F}
  .up-cnt.a{background:#4B57C4}
  .up-cnt.m::before{content:"M";font-size:8.5px;font-weight:800;opacity:.78;margin-right:3px}
  .up-cnt.a::before{content:"A";font-size:8.5px;font-weight:800;opacity:.78;margin-right:3px}
  /* Occupation vs sièges : complet (or) puis au-delà (corail) — override du bleu/vert */
  /* Capacité : plus de couleur sur le compteur. Une pastille NEUTRE « Complet » / « Au-delà »
     (avec pictogramme d'alerte) apparaît à côté quand un créneau atteint/dépasse la capacité. */
  .up-full{display:inline-flex;align-items:center;gap:4px;margin-left:1px;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.3px;color:var(--ink-2);background:var(--surface);border:1.5px solid var(--ink-2);border-radius:7px;padding:2px 7px;white-space:nowrap}
  .up-full.over{border-style:dashed}
  .up-full svg{width:12px;height:12px;flex:none}
  /* --- Journée BLOQUÉE dans le bloc « semaine » ---
     Même famille visuelle que « Complet » (pastille à droite, même gabarit), mais en rouge plein :
     « complet » constate un remplissage, « bloqué » est une décision qui interdit. La ligne prend
     une teinte et un liseré gauche — sur 5 lignes très semblables, la pastille seule se rate. */
  .up-day.blocked{background:rgba(217,83,79,.055);box-shadow:inset 3px 0 0 var(--danger)}
  .up-day.blocked .up-date{color:#A33A37;padding-left:9px}
  :root[data-theme="dark"] .up-day.blocked{background:rgba(240,115,111,.07)}
  :root[data-theme="dark"] .up-day.blocked .up-date{color:#F5A6A3}
  /* Cadenas de la ligne « semaine » : sur fond CLAIR (contrairement à celui de l'en-tête de grille,
     posé sur le bandeau sombre) → couleurs propres. Cible tactile ≥ 32px : c'est le seul accès sur
     mobile, il doit se viser au doigt. */
  .up-lock{position:static;width:32px;height:32px;margin-left:2px;border-radius:9px;color:var(--grey);opacity:.55;background:transparent}
  .up-lock svg{width:15px;height:15px}
  .up-lock:hover{background:var(--fill);color:var(--ink-2);opacity:1}
  .up-lock:focus-visible{outline:2px solid var(--teal);outline-offset:1px;opacity:1;color:var(--ink-2)}
  .up-lock.on{color:var(--danger);opacity:1}
  .up-lock.on:hover{background:rgba(217,83,79,.14);color:var(--danger)}
  :root[data-theme="dark"] .up-lock.on{color:#F0736F}
  .up-blocked{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.3px;
    color:#fff;background:var(--danger-bg);border:1.5px solid var(--danger-bg);border-radius:7px;padding:2px 7px;white-space:nowrap;max-width:190px}
  .up-blocked svg{width:12px;height:12px;flex:none}
  .up-blk-lbl{overflow:hidden;text-overflow:ellipsis} /* motif long : tronqué, jamais de ligne qui déborde */
  /* Carte « Aujourd'hui » quand LE jour est bloqué : même bandeau que .cap-alert, teinte d'alerte. */
  .blk-alert{border-color:rgba(217,83,79,.45);background:rgba(217,83,79,.08);color:var(--ink-2)}
  .blk-alert svg{color:var(--danger)}
  :root[data-theme="dark"] .blk-alert{background:rgba(240,115,111,.10);border-color:rgba(240,115,111,.4)}
  :root[data-theme="dark"] .blk-alert svg{color:#F0736F}
  /* Croix de retrait (admins) sur une pastille. Discrète au repos pour ne pas transformer le
     panneau en tableau de bord d'actions, franche au survol/focus. Toujours visible au TOUCHER :
     sans souris, un état « au survol » n'existe pas. */
  .tc-x-btn{flex:none;width:18px;height:18px;margin-left:1px;padding:0;border:none;border-radius:50%;cursor:pointer;
    display:inline-flex;align-items:center;justify-content:center;background:transparent;color:var(--grey);opacity:.35;transition:.14s}
  .tc-x-btn svg{width:11px;height:11px}
  .tc-person:hover .tc-x-btn,.tc-person:focus-within .tc-x-btn{opacity:1}
  .tc-x-btn:hover{background:var(--danger-bg);color:#fff;opacity:1}
  .tc-x-btn:focus-visible{outline:2px solid var(--danger);outline-offset:1px;opacity:1}
  @media(hover:none){.tc-x-btn{opacity:.75}}
  /* Chiffres du résumé « Aujourd'hui » colorés selon l'occupation */
  .cap-n{font-weight:800}
  .cap-n.full{color:var(--gold)}
  .cap-n.over{color:#E2683F}
  /* Alerte capacité (carte Aujourd'hui) : ton ambre rassurant, renvoie vers les espaces partagés */
  .cap-alert{display:flex;align-items:flex-start;gap:9px;margin-top:12px;padding:10px 13px;border-radius:12px;background:#FFF6E9;border:1px solid #F1D9A8;color:#8A5B14;font-size:12px;font-weight:500;line-height:1.4}
  .cap-alert svg{width:17px;height:17px;flex:none;margin-top:1px;color:#C77A1E}
  .cap-alert b{font-weight:800;color:#7A4E10}
  .cap-alert sup{font-size:.7em}
  /* Note explicative sièges / espaces partagés */
  /* align-items:baseline : quand le texte passe sur 2 lignes, « complet / au-delà » restent
     alignés sur la 1re ligne du texte au lieu de flotter à son milieu vertical. */
  /* Puces (complet/au-delà) alignées entre elles sur une ligne ; l'explication passe TOUJOURS
     sur sa propre ligne (flex-basis 100%) → alignement net et identique à toutes les largeurs. */
  .cap-note{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;margin-top:12px;padding-top:11px;border-top:1px solid var(--light);font-size:11.5px;color:var(--grey)}
  .cap-txt{flex:1 1 100%;color:var(--grey)}
  /* Blocage vue Mois en portrait mobile : overlay plein écran centré avec un téléphone animé.
     Visible UNIQUEMENT en vue Mois + écran tactile étroit + PORTRAIT. En paysage / vue Semaine /
     desktop → media query non satisfaite → masqué (la vue Mois s'affiche normalement). */
  .rotate-block{display:none}
  @keyframes rb-rotate{0%,22%{transform:rotate(0)}52%,80%{transform:rotate(90deg)}100%{transform:rotate(0)}}
  @media (orientation:portrait) and (max-width:820px) and (pointer:coarse){
    body.view-month .rotate-block{display:flex;align-items:center;justify-content:center;position:fixed;inset:0;z-index:150;background:rgba(10,58,66,.94);padding:28px}
    body.view-month .card,body.view-month .grid-hint,body.view-month .legend,body.view-month #hiddenNote{display:none!important} /* on masque la grille cramponnée dessous */
    .rotate-block .rb-card{max-width:300px;display:flex;flex-direction:column;align-items:center;gap:14px;text-align:center;color:#fff}
    .rotate-block .rb-anim{width:92px;height:92px;display:inline-flex;align-items:center;justify-content:center}
    .rotate-block .rb-anim svg{width:100%;height:100%;color:var(--gold);transform-origin:50% 50%;animation:rb-rotate 2.8s ease-in-out infinite}
    .rotate-block .rb-title{font-size:21px;font-weight:800}
    .rotate-block .rb-sub{font-size:13.5px;line-height:1.45;color:rgba(240,228,208,.92)}
    .rotate-block .rb-back{margin-top:6px;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.3);color:#fff;font-weight:700}
    .rotate-block .rb-back:hover{background:rgba(255,255,255,.24)}
  }
  /* Guide d'utilisation (mode opératoire) */
  .guide{display:flex;flex-direction:column;gap:16px}
  .gd-step{display:flex;gap:14px;align-items:flex-start}
  .gd-ic{flex:0 0 auto;width:38px;height:38px;border-radius:10px;background:var(--green-soft);color:var(--teal-dark);display:flex;align-items:center;justify-content:center}
  .gd-ic svg{width:20px;height:20px}
  .gd-t{font-weight:700;font-size:15px;color:var(--ink);margin-bottom:3px}
  .gd-d{font-size:13.5px;color:var(--ink-2);line-height:1.55}
  .gd-chip{display:inline-block;padding:1px 8px;border-radius:100px;font-size:12px;font-weight:700;color:#fff;white-space:nowrap}
  .gd-chip.gd-desk{background:var(--green)}
  .gd-chip.gd-maybe{background:var(--maybe)}
  .gd-chip.gd-shared{background:var(--shared)}
  /* Mobile : on masque le prénom pour rester compact (photo + badge seulement) */
  /* (densité mobile des noms gérée par #todayPanel[data-dens] ci-dessus) */
  @media(max-width:520px){ .up-date{flex-basis:74px;font-size:11.5px} }
  /* Tooltip du nom au tap (mobile surtout, où le title natif ne s'affiche pas) */
  .chip-tip{position:fixed;z-index:1200;max-width:230px;background:#0A3A42;color:#fff;font-size:12.5px;font-weight:600;line-height:1.3;padding:7px 11px;border-radius:9px;box-shadow:0 8px 22px rgba(10,58,66,.32);pointer-events:none;opacity:0;transform:translateY(4px);transition:opacity .12s ease,transform .12s ease;white-space:normal}
  .chip-tip.show{opacity:1;transform:translateY(0)}
  .up-person{cursor:pointer}
  .section-title{display:flex;align-items:center;gap:10px;margin:6px 2px 16px}
  .section-title .dot{width:9px;height:9px;border-radius:50%;background:var(--gold)}
  .section-title h2{font-size:13px;text-transform:uppercase;letter-spacing:1.5px;color:var(--teal);font-weight:700}
  .stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(186px,1fr));gap:16px;margin-bottom:22px}
  .kpi{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;box-shadow:var(--shadow);position:relative;overflow:hidden}
  /* La jauge est posée en absolu dans le coin : sans cette réserve, le libellé passait DESSOUS
     (38 px de chevauchement mesurés en paysage). On lui laisse la place plutôt que de déplacer la
     jauge — la lecture « libellé à gauche, jauge à droite » reste celle attendue. */
  .kpi .lab{font-size:11.5px;text-transform:uppercase;letter-spacing:.8px;color:var(--grey);font-weight:600;padding-right:54px}
  .kpi .val{font-size:30px;font-weight:800;color:var(--ink-2);margin-top:6px;line-height:1}
  .kpi .val small{font-size:15px;font-weight:600;color:var(--grey)}
  .kpi .sub{font-size:12px;color:var(--teal);font-weight:600;margin-top:6px}
  .kpi.accent{background:linear-gradient(135deg,#0A3A42,#127B84);border:none}
  .kpi.accent .lab{color:rgba(238,222,198,.85)}.kpi.accent .val{color:#fff}.kpi.accent .sub{color:var(--gold)}
  .kpi .ring{position:absolute;right:14px;top:14px;width:44px;height:44px}

  .two-col{display:grid;grid-template-columns:1.3fr 1fr;gap:20px;margin-bottom:26px}
  #statsCols.solo{grid-template-columns:1fr}
  #statsCols.solo #rankPanel{display:none}
  @media(max-width:900px){.two-col{grid-template-columns:1fr}.stats-grid{grid-template-columns:repeat(2,1fr)}}
  .panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:20px 22px}
  .h3-count{font-size:13px;font-weight:500;color:var(--grey);white-space:nowrap}
  .panel h3{font-size:14.5px;font-weight:700;color:var(--ink-2);margin-bottom:2px}
  .panel .psub{font-size:12px;color:var(--grey);margin-bottom:16px}

  .daybars{display:flex;gap:14px;align-items:flex-end;height:170px;padding-top:8px}
  .daybar{flex:1;display:flex;flex-direction:column;align-items:center;gap:8px;height:100%}
  .daybar .stack{flex:1;width:100%;display:flex;flex-direction:column;justify-content:flex-end;gap:4px}
  .daybar .bar{width:100%;border-radius:7px 7px 3px 3px;position:relative;transition:.3s;min-height:3px}
  .daybar .bar.am{background:var(--teal)}
  .daybar .bar.pm{background:var(--green)}
  .daybar .bar span{position:absolute;top:-17px;left:0;right:0;text-align:center;font-size:10.5px;font-weight:700;color:var(--ink-2)}
  .daybar .dl{font-size:11px;font-weight:700;color:var(--ink-2);text-transform:uppercase;letter-spacing:.5px}
  /* « +N » = personnes en espace partagé : sur site, mais HORS postes. Discret et distinct du chiffre
     de la barre, pour ne pas laisser croire qu'elles occupent un poste. */
  .db-sh{margin-left:4px;font-size:10px;font-weight:700;color:var(--shared);text-transform:none;letter-spacing:0}
  /* `--shared` (#3667C9) n'est PAS redéfini en thème sombre : en texte sur fond sombre il tombe sous
     le seuil AA. On éclaircit donc ici, comme pour les autres couleurs d'état. */
  :root[data-theme="dark"] .db-sh{color:#8FB0F0}
  .mini-leg{display:flex;gap:16px;font-size:11.5px;color:var(--grey);font-weight:600;margin-top:14px;justify-content:center}
  .mini-leg .m{display:flex;align-items:center;gap:6px}.mini-leg .sq{width:11px;height:11px;border-radius:3px}

  /* Le graphique DÉFILE dans son propre cadre au lieu de déborder : avec un trimestre d'historique
     (14 semaines) sur un téléphone, les colonnes tombaient à 19 px et les libellés « S49 30/11 »
     sortaient de la carte de ~90 px. Chaque colonne garde donc une largeur MINIMALE et l'ensemble
     défile horizontalement — jamais de contenu coupé hors du cadre. */
  .trend{display:flex;gap:10px;align-items:flex-end;height:150px;padding-top:20px;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:thin}
  .tcol{flex:1 0 46px;display:flex;flex-direction:column;align-items:center;gap:8px;height:100%}
  .tcol .tstack{flex:1;width:100%;display:flex;align-items:flex-end;justify-content:center}
  .tcol .tbar{width:60%;max-width:34px;background:linear-gradient(180deg,var(--teal),#0A6A73);border-radius:6px 6px 0 0;position:relative;transition:.3s}
  .tcol .tbar.cur{background:linear-gradient(180deg,var(--gold),#C98F1E)}
  .tcol .tbar b{position:absolute;top:-18px;left:-6px;right:-6px;text-align:center;font-size:10.5px;font-weight:700;color:var(--ink-2)}
  .tcol .tl{font-size:10.5px;color:var(--grey);font-weight:600;text-align:center;line-height:1.2}
  .rank .row{display:flex;align-items:center;gap:12px;padding:9px 0;border-bottom:1px solid var(--line)}
  .rank .row:last-child{border:none}
  .rank .av{width:30px;height:30px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;color:#fff;font-size:11px;font-weight:700}
  .rank .nm{font-size:13.5px;font-weight:600;color:var(--ink-2);flex:none;width:130px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .rank .track{flex:1;height:9px;background:var(--light);border-radius:6px;overflow:hidden}
  .rank .fill{height:100%;background:linear-gradient(90deg,var(--teal),var(--green));border-radius:6px;transition:.3s}
  .rank .pc{font-size:12.5px;font-weight:700;color:var(--teal);width:60px;text-align:right}
  .empty{color:var(--grey);font-size:13px;padding:30px 0;text-align:center}

  /* Overlays / gate / modals */
  .overlay{position:fixed;inset:0;background:rgba(10,58,66,.55);backdrop-filter:blur(3px);display:flex;align-items:center;justify-content:center;padding:20px;z-index:100}
  /* Modale : hauteur bornée au viewport (dvh = tient compte de la barre d'URL mobile),
     en flex-column → en-tête fixe, corps défilant, pied collant (voir .mbody / .mfoot). */
  .modal{background:var(--surface);border-radius:20px;box-shadow:0 30px 80px rgba(0,0,0,.35);width:100%;max-width:440px;overflow:hidden;max-height:calc(100vh - 24px);max-height:calc(100dvh - 24px);display:flex;flex-direction:column}
  .modal.lg{max-width:640px}
  .modal .mhead{flex:none;background:linear-gradient(135deg,#0A3A42,#127B84);color:#fff;padding:22px 26px;display:flex;align-items:center;gap:14px}
  .modal .mhead img{height:34px}
  .modal .mhead h2{font-size:16px;font-weight:700}
  .modal .mhead p{font-size:12px;color:rgba(238,222,198,.85);margin-top:2px}
  .modal .mbody{padding:24px 26px 0;flex:1 1 auto;overflow-y:auto}
  .field{margin-bottom:16px}
  .field label{display:block;font-size:12.5px;font-weight:600;color:var(--ink-2);margin-bottom:6px}
  .field input{width:100%;border:1px solid var(--line);border-radius:11px;padding:12px 14px;font-family:inherit;font-size:14px;color:var(--ink-2)}
  .field input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(4,139,154,.12)}
  .help{font-size:11.5px;color:var(--grey);margin-top:5px;line-height:1.45} /* aide : cohérent PARTOUT (pas seulement dans .field) */
  .err{background:#FDF2F1;color:#B23A36;border:1px solid #F0C9C7;border-radius:10px;padding:10px 12px;font-size:12.5px;font-weight:600;margin-bottom:14px;display:none}
  /* Pied de modale COLLANT : Fermer/Enregistrer toujours visibles, même si le corps défile.
     Marges négatives = pleine largeur ; bordure haute pour séparer du contenu qui défile dessous. */
  .modal .mfoot{position:sticky;bottom:0;background:var(--surface);display:flex;gap:10px;justify-content:space-between;align-items:center;margin:8px -26px 0;padding:14px 26px;border-top:1px solid var(--line)}
  /* Mobile : modale plus compacte + champs à 16px (empêche le zoom automatique d'iOS au focus). */
  @media(max-width:640px){
    .overlay{padding:12px}
    .modal .mbody{padding-left:20px;padding-right:20px}
    .modal .mfoot{margin-left:-20px;margin-right:-20px;padding-left:20px;padding-right:20px}
    .modal .mhead{padding-left:20px;padding-right:20px}
    .modal .field input,.modal input,.modal select,.modal textarea{font-size:16px}
    #capacity,.cap input{font-size:16px}
  }
  /* --teal (#048B9A) ne donne que 4,07:1 sur blanc à 12,5 px : sous le seuil AA de 4,5.
     --teal-dark en donne 6,32. Le correctif n'existait qu'en local (.nudge/.hidden-note) ;
     il vaut pour TOUS les boutons-liens — le gate axe ne regardait aucune modale. */
  .link{background:none;border:none;color:var(--link);font-family:inherit;font-weight:600;font-size:12.5px;cursor:pointer;padding:0}
  .link:hover{text-decoration:underline}

  /* Recherche d'utilisateur (liste admin) */
  .usearch{position:relative;margin:2px 0 10px}
  .usearch-ico{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--grey);pointer-events:none}
  .usearch input{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:10px;padding:9px 12px 9px 36px;font-size:14px;font-family:inherit;color:var(--ink);background:var(--surface)}
  .usearch input::placeholder{color:var(--grey)}
  .usearch input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(4,139,154,.12)}
  @media(max-width:640px){.usearch input{font-size:16px}}
  /* --- Modale « journée bloquée » : elle porte TOUT le cycle (blocage, motif, message, inscrits,
     libération), il n'y a plus d'écran d'administration séparé. Un peu plus large que la modale
     standard, et défilante : la liste des inscrits peut être longue. --- */
  .modal-block{max-width:520px}
  .bk-people-wrap{margin-top:2px}
  .bk-load{font-size:12.5px;color:var(--grey);padding:10px 0}
  .bk-sep{height:1px;background:var(--line);margin:16px 0 14px}
  .modal-block .bd-warn{margin-bottom:12px}
  .modal-block .bd-people{margin-bottom:12px}
  .modal-block .bd-steps{margin-bottom:2px}
  .modal-block .btn svg{width:15px;height:15px;flex:none} /* cf. piège de l'icône non dimensionnée */
  @media(max-width:520px){
    .modal-block .bd-steps{flex-direction:column;align-items:stretch}
    .modal-block .bd-step{width:100%}
    .modal-block .bd-step .btn{flex:1;justify-content:center}
  }
  /* --- Journées bloquées (admin) --- */
  .bd-warn{display:flex;gap:10px;align-items:flex-start;font-size:13px;line-height:1.55;color:var(--ink-2)}
  .bd-warn svg{width:18px;height:18px;color:var(--danger);flex:none;margin-top:1px}
  .bd-people{display:flex;flex-wrap:wrap;gap:8px}
  .bd-person{display:inline-flex;align-items:center;gap:8px;background:var(--surface);border:1px solid var(--line);border-radius:999px;padding:4px 12px 4px 4px;font-size:12.5px;font-weight:600;color:var(--ink-2)}
  .avatar-xs{width:24px;height:24px;font-size:10px}
  .bd-slot{font-weight:500;color:var(--grey);font-size:11.5px}
  /* L'ordre des étapes est une règle (on prévient AVANT de retirer) : les numéros l'encodent. */
  .bd-steps{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
  .bd-step{display:inline-flex;align-items:center;gap:8px}
  .bd-n{width:20px;height:20px;border-radius:50%;background:var(--teal-deeper);color:#fff;font-size:11.5px;font-weight:800;display:inline-flex;align-items:center;justify-content:center;flex:none}
  :root[data-theme="dark"] .bd-n{background:var(--teal);color:#062026}
  .bd-hint{flex-basis:100%;font-size:12px;color:var(--grey);line-height:1.5}
  /* Sous 520px les deux étapes se serrent côte à côte et les libellés s'enroulent : on les empile,
     pleine largeur — au passage la cible tactile devient franche. */
  @media(max-width:520px){
    .bd-steps{flex-direction:column;align-items:stretch}
    .bd-step{width:100%}
    .bd-step .btn{flex:1;justify-content:center}
  }
  .adm-list{max-height:340px;overflow:auto;margin:6px 0 4px}
  .icobtn{background:none;border:none;cursor:pointer;color:var(--grey);padding:6px;border-radius:8px;font-size:13px;font-weight:600}
  .icobtn:hover{background:var(--light);color:var(--ink-2)}
  .icobtn.del:hover{color:var(--danger)}
  /* Tableau collaborateurs (admin) : colonnes triables Nom / Prénom / Fonction / Rôle + actions */
  .utable{width:100%;border-collapse:collapse;font-size:13px}
  .utable thead th{position:sticky;top:0;z-index:1;background:var(--light);text-align:left;font-size:10.5px;text-transform:uppercase;letter-spacing:.5px;font-weight:700;color:var(--grey);padding:9px 12px;border-bottom:1px solid var(--line);white-space:nowrap}
  .utable th.sortable{cursor:pointer;user-select:none}
  .utable th.sortable:hover{color:var(--teal)}
  .utable th.sortable:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}
  .utable th .sort-ar{font-size:8px;margin-left:4px;opacity:.3;vertical-align:middle}
  .utable th.sorted .sort-ar{opacity:1;color:var(--teal)}
  .utable th.ut-ah{text-align:right}
  .utable tbody td{padding:8px 12px;border-bottom:1px solid var(--line);vertical-align:middle;color:var(--ink-2)}
  .utable tbody tr:last-child td{border-bottom:none}
  .utable tbody tr:hover{background:var(--surface-2)}
  /* Ligne archivée : atténuée MAIS lisible. On n'utilise plus opacity (qui faisait tomber le
     texte sous le seuil AA) ; fond gris + texte gris foncé (≥4.5:1) + avatar désaturé (le filtre
     n'altère pas le calcul de contraste d'axe, qui lit la couleur de fond réelle). */
  .utable tr.inactive{background:var(--bg)}
  .utable tr.inactive td,.utable tr.inactive .ut-nm{color:#556066}
  .utable tr.inactive .ut-av{filter:saturate(.4)}
  .ut-who{display:flex;align-items:center;gap:9px} /* flex DANS la cellule (un td en flex casse l'alignement des lignes) */
  .ut-name .ut-nm{font-weight:600;color:var(--ink-2)}
  .ut-av{width:30px;height:30px;border-radius:8px;flex:none;display:flex;align-items:center;justify-content:center;color:#fff;font-size:11px;font-weight:700;overflow:hidden}
  .ut-av img{width:100%;height:100%;object-fit:cover}
  .ut-dash{color:var(--grey)}
  .ut-ll{font-size:12px;color:var(--grey);white-space:nowrap}
  .ut-ll .ll-never{color:#B23A36;font-weight:600}
  .ut-actions{text-align:right;white-space:nowrap}
  .utable .tag{margin-left:0;margin-right:3px}
  @media(max-width:820px){ .utable{min-width:680px} }
  /* M7 : sous 640px, la table admin devient des cartes empilées (plus de scroll horizontal). */
  @media(max-width:640px){
    .utable{min-width:0;font-size:13.5px}
    .utable thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0} /* en-têtes en sr-only : les data-label prennent le relais */
    .utable tbody,.utable tbody tr,.utable tbody td{display:block}
    .utable tbody tr{border:1px solid var(--line);border-radius:14px;box-shadow:0 2px 12px rgba(10,58,66,.06);margin-bottom:12px;padding:4px 2px;background:var(--surface)}
    .utable tbody tr:hover{background:var(--surface)}
    .utable tbody td{border:none;padding:7px 14px;display:flex;justify-content:space-between;align-items:center;gap:14px;text-align:right}
    .utable tbody td::before{content:attr(data-label);flex:0 0 auto;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;color:var(--grey);text-align:left}
    .utable td.ut-name{background:var(--light);border-radius:12px 12px 0 0;padding:11px 14px;margin-bottom:2px}
    .utable td.ut-name::before,.utable td.ut-actions::before{display:none}
    .utable tr.inactive td.ut-name{background:#EAF0F4}
    .utable td.ut-ll{white-space:normal}
    .utable td.ut-actions{justify-content:flex-end;flex-wrap:wrap;gap:6px;padding-top:9px}
    .utable td.ut-actions .icobtn{border:1px solid var(--line);border-radius:9px;padding:7px 12px}
  }
  .add-form{display:flex;gap:8px 10px;margin-top:14px;padding-top:16px;border-top:1px solid var(--line);flex-wrap:wrap;align-items:flex-end}
  /* Champ avec label visible (a11y) : légende au-dessus, contrôle en dessous. */
  .af-field{display:flex;flex-direction:column;gap:4px;flex:1;min-width:120px}
  .af-field.af-wide{flex:1.4;min-width:160px}
  .af-lbl{font-size:11px;font-weight:600;color:var(--ink-2);letter-spacing:.2px}
  .add-form input,.add-form select{width:100%;min-width:0;border:1px solid var(--line);border-radius:10px;padding:10px 12px;font-family:inherit;font-size:14px;color:var(--ink-2)}
  .add-form>#uAdd{flex:0 0 auto}
  .add-form input.input-bad{border-color:var(--danger);background:#FDF2F1}
  /* Vignette photo du formulaire de création : même composant que le profil (.ava-frame), en compact. */
  .ava-frame-sm{align-self:center;margin:2px 4px 2px 0}
  .ava-frame-sm .avatar{width:48px;height:48px;box-shadow:0 0 0 2px #fff,0 0 0 3px var(--line);transition:box-shadow .18s}
  .ava-frame-sm:hover .avatar,.ava-frame-sm:focus-visible .avatar{box-shadow:0 0 0 2px #fff,0 0 0 3px var(--teal)}
  .ava-frame-sm .avatar img{width:100%;height:100%;object-fit:cover}
  .ava-frame-sm .ava-cam{width:20px;height:20px;right:-3px;bottom:-3px;border-width:2px}
  .ava-frame-sm .ava-cam svg{width:11px;height:11px}
  .ava-clear{position:absolute;top:-6px;right:-6px;width:19px;height:19px;border-radius:50%;border:2px solid #fff;background:var(--danger-bg);color:#fff;font-size:13px;line-height:1;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0;box-shadow:0 2px 6px rgba(0,0,0,.22);z-index:2}
  .ava-clear:hover{filter:brightness(1.08)}
  .field-err{font-size:11.5px;color:var(--danger);font-weight:600}
  .toast{position:fixed;bottom:max(24px,env(safe-area-inset-bottom,0px));left:50%;transform:translateX(-50%) translateY(20px);display:inline-flex;align-items:center;gap:14px;max-width:calc(100vw - 32px);background:var(--ink-2);color:#fff;padding:11px 20px;border-radius:12px;font-size:13px;font-weight:600;opacity:0;pointer-events:none;transition:.25s;box-shadow:0 10px 30px rgba(0,0,0,.25);z-index:200}
  .toast.show{opacity:1;transform:translateX(-50%) translateY(0);pointer-events:auto}
  .toast-act{flex:none;border:0;background:rgba(255,255,255,.16);color:#fff;font:inherit;font-weight:700;padding:5px 12px;border-radius:8px;cursor:pointer}
  .toast-act:hover{background:rgba(255,255,255,.28)}
  .note{background:#FFFBF0;border:1px solid #F3E4BD;border-radius:12px;padding:14px 18px;font-size:12.5px;color:#7A5E1E;margin-top:22px}
  /* Encart d'information (ton teal doux) — ex. rappel « secours admin » dans le changement de mot de passe */
  .info-note{display:flex;align-items:flex-start;gap:9px;background:#EEF6F7;border:1px solid #CFE6E9;border-radius:12px;padding:11px 13px;font-size:12px;color:#2A6A72;line-height:1.45;margin-bottom:16px}
  .info-note svg{width:16px;height:16px;flex:none;margin-top:1px;color:var(--teal)}
  .info-note b{font-weight:700;color:var(--teal-deeper)}
  .admin-hero{margin:6px 2px 20px}
  .admin-hero h2{font-size:22px;font-weight:800;color:var(--ink-2)}
  .admin-hero p{font-size:13px;color:var(--grey);margin-top:4px}
  .admin-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:18px}
  @media(max-width:820px){.admin-cards{grid-template-columns:1fr}}
  .admin-card{text-align:left;cursor:pointer;border:1px solid var(--line);background:var(--surface);border-radius:var(--radius);padding:24px 22px;box-shadow:var(--shadow);transition:.15s;font-family:inherit;display:flex;flex-direction:column;gap:12px;min-height:186px}
  .admin-card:hover{border-color:var(--teal);transform:translateY(-2px);box-shadow:0 16px 36px rgba(10,58,66,.14)}
  .admin-card .ic{width:52px;height:52px;border-radius:14px;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#0A3A42,#127B84);color:#fff}
  .admin-card.c2 .ic{background:linear-gradient(135deg,#B8860B,#E3AC2B)}
  .admin-card.c3 .ic{background:linear-gradient(135deg,#2F8F76,#49AD95)}
  .admin-card.c4 .ic{background:linear-gradient(135deg,#254046,#4A626C)}
  .admin-card.c5 .ic{background:linear-gradient(135deg,#2557A7,#3C7DD9)}
  .admin-card.c6 .ic{background:linear-gradient(135deg,#B5433F,#D9534F)}
  .admin-card .ic svg{width:26px;height:26px}
  .admin-card h3{font-size:16.5px;font-weight:700;color:var(--ink-2)}
  .admin-card p{font-size:12.5px;color:var(--grey);line-height:1.45}
  .admin-card .arrow{margin-top:auto;font-size:13px;font-weight:700;color:var(--teal)}
  .backbar{display:flex;align-items:center;gap:14px;margin-bottom:20px}
  .backbar #secTitle{font-size:18px;font-weight:700;color:var(--ink-2)}
  /* --- Configuration SSO (admin) : tokens thème → lisible en clair ET sombre --- */
  /* `.card` de base n'a AUCUN padding + overflow:hidden → sans padding propre, le contenu est collé
     aux bords et le titre gras est rogné. On donne donc son inset à la carte SSO, et on aère. */
  .sso-card{max-width:560px;padding:28px 30px}
  .sso-head{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:10px}
  .sso-head h2{font-size:18px;font-weight:800;color:var(--ink-2);line-height:1.3}
  .sso-card .psub{font-size:12.5px;color:var(--grey);line-height:1.6;margin:0 0 24px}
  .sso-badge{display:inline-flex;align-items:center;gap:7px;flex:none;font-size:11.5px;font-weight:700;color:var(--ink-2);padding:5px 12px;border:1px solid var(--line);border-radius:999px;background:var(--surface-2)}
  .sso-badge::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--grey)}
  .sso-badge.on::before{background:#2FB57F}
  .sso-card .af-field{margin-bottom:20px;gap:7px}
  .sso-card .af-field input{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:10px;padding:12px 14px;font-family:inherit;font-size:14px;color:var(--ink-2);background:var(--surface)}
  .sso-card .af-field input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(4,139,154,.12)}
  .sso-redirect{font-size:12px;color:var(--grey);margin:4px 0 24px;line-height:1.7}
  .sso-redirect code{display:inline-block;margin-top:7px;background:var(--fill);color:var(--ink-2);padding:7px 11px;border-radius:7px;font-size:12px;word-break:break-all}
  .sso-actions{display:flex;align-items:center;gap:20px;flex-wrap:wrap;margin-top:4px}
  .sso-warn{display:flex;gap:8px;background:var(--surface-2);border:1px solid var(--line);border-left:3px solid var(--danger);color:var(--ink-2);border-radius:10px;padding:11px 13px;font-size:12.5px;line-height:1.45;margin-bottom:20px}
  .sso-help{margin-top:24px;border-top:1px solid var(--line);padding-top:16px}
  .sso-help summary{font-size:12.5px;font-weight:700;color:var(--link);cursor:pointer;padding:2px 0}
  .sso-steps{margin:12px 0 0;padding-left:20px;font-size:12px;color:var(--grey);line-height:1.85}
  .sso-steps b{color:var(--ink-2);font-weight:700}
  /* Résultat du test : texte toujours en --ink-2 (contraste garanti), l'état ok/err passe par une
     bordure gauche colorée (décorative) → lisible en clair ET sombre sans risque de contraste. */
  .sso-testmsg{font-size:12.5px;line-height:1.45;color:var(--ink-2);margin-top:14px}
  /* ⚠️ PAS de `:empty` ici. WebKit (Safari) ne réévalue PAS ce sélecteur quand le contenu ajouté est
     un simple NŒUD DE TEXTE (textContent) : la règle restait appliquée et le message, pourtant écrit,
     demeurait `display:none` — invisible chez l'utilisateur, alors que Chromium l'affichait. L'état
     est donc porté par une CLASSE explicite, posée par le code qui écrit le message.
     (`#todayPanel:empty` reste sûr : il reçoit des ÉLÉMENTS, cas où l'invalidation fonctionne.) */
  .sso-testmsg.is-empty{display:none}
  /* ⚠️ États nommés `is-ok`/`is-err` et NON `ok`/`err` : `.err` est une classe GLOBALE d'encart
     d'erreur, masquée par défaut (`display:none`, l. ~798) et révélée par `showErr` en style inline.
     Réutiliser ce nom rendait le message de test INVISIBLE dans tous les navigateurs — le texte était
     bien écrit, mais jamais affiché. `display:block` est posé explicitement, sans dépendre d'un défaut. */
  .sso-testmsg.is-ok,.sso-testmsg.is-err{display:block;padding:10px 13px;border:1px solid var(--line);border-radius:9px;background:var(--surface-2)}
  .sso-testmsg.is-ok{border-left:3px solid #2FB57F}
  .sso-testmsg.is-err{border-left:3px solid var(--danger)}
  /* Mobile : APRÈS les règles de base (spécificité égale → l'ordre décide) pour bien les surcharger.
     En colonne, le titre prend toute la largeur (une ligne) et le badge passe dessous, à gauche. */
  @media(max-width:560px){.sso-card{padding:22px 18px}.sso-head{flex-direction:column;align-items:flex-start;gap:9px}}
  .sel{border:1px solid var(--line);border-radius:10px;padding:10px 12px;font-family:inherit;font-size:13.5px;color:var(--ink-2);background:var(--surface)}
  .tag{display:inline-block;font-size:10px;font-weight:700;padding:2px 7px;border-radius:20px;background:var(--light);color:#41525A;margin-left:4px;vertical-align:middle}
  .tag-admin{background:#FBEFD3;color:#7A5410}
  .tag-collab{background:#E1EFF1;color:#0A6A73}
  .tag-wait{background:#FDECEA;color:#B23A36}
  .log-wrap{overflow-x:auto;margin-top:6px}
  .log-table{width:100%;border-collapse:collapse;font-size:12.5px}
  .log-table th{text-align:left;color:var(--grey);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px;padding:8px 10px;border-bottom:1px solid var(--line)}
  .log-table td{padding:9px 10px;border-bottom:1px solid var(--line);color:var(--ink-2);vertical-align:top}
  .log-table tr:hover td{background:var(--surface-2)}
  .log-table .mono{font-variant-numeric:tabular-nums;white-space:nowrap}
  .log-table .sub2{font-size:11px;color:var(--grey);margin-top:2px}
  /* Pied du journal : sélecteur de taille de page + pagination numérotée moderne */
  /* 3 colonnes centrées verticalement : sélecteur (gauche) · pages (centre) · plage (droite) */
  .au-footer{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:14px;margin-top:16px}
  .au-psize{justify-self:start;display:inline-flex;align-items:center;gap:8px;font-size:12.5px;font-weight:600;color:var(--ink-2)}
  .au-psize select{padding:6px 26px 6px 10px}
  .au-pager{justify-self:center;display:inline-flex;align-items:center;gap:5px;flex-wrap:wrap}
  /* .au-footer .au-range (0,2,0) pour battre .panel .psub{margin-bottom} → texte centré verticalement */
  .au-footer .au-range{justify-self:end;text-align:right;margin:0}
  @media(max-width:640px){ .au-footer{grid-template-columns:1fr;justify-items:center;gap:10px} .au-psize,.au-footer .au-range{justify-self:center;text-align:center} }
  .pg-btn{min-width:34px;height:34px;padding:0 9px;border:1px solid var(--line);background:var(--surface);border-radius:10px;font-family:inherit;font-size:13px;font-weight:700;color:var(--ink-2);cursor:pointer;transition:.13s;display:inline-flex;align-items:center;justify-content:center}
  .pg-btn:hover:not([disabled]):not(.pg-cur){background:var(--light);border-color:var(--teal);color:var(--teal)}
  .pg-btn.pg-cur{background:var(--teal);border-color:var(--teal);color:#fff;box-shadow:0 4px 12px rgba(4,139,154,.32);cursor:default}
  .pg-btn.pg-nav{color:var(--teal);font-size:17px;font-weight:600}
  .pg-btn[disabled]{opacity:.38;cursor:default}
  .pg-ell{display:inline-flex;align-items:center;justify-content:center;height:34px;padding:0 3px;color:var(--grey);font-weight:700}
  .preview-bar{background:#FBEFD3;border:1px solid #E8CE8A;color:#7A5E1E;border-radius:12px;padding:10px 16px;font-size:13px;font-weight:600;margin:0 0 18px;display:flex;align-items:center;justify-content:space-between;gap:12px}
  .preview-bar button{background:#E3AC2B;color:#3a2e07;border:none;border-radius:9px;padding:7px 14px;font-family:inherit;font-weight:700;cursor:pointer;font-size:12.5px}
  .hidden{display:none!important}

  /* Menu utilisateur (en-tête) */
  .user-wrap{position:relative;display:inline-flex}
  .chip-user{padding-right:10px}
  .chip-user .chip-ava{width:24px;height:24px;border-radius:50%;object-fit:cover;display:block;flex:none;border:1px solid rgba(255,255,255,.3)}
  /* Repli initiales (pas de photo) — doit suivre .chip-ava : même spécificité, l'ordre tranche. */
  .chip-user .chip-ava-ini{display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;color:#fff}
  .chip-user .caret{width:14px;height:14px;opacity:.9;margin-left:1px;flex:none;transition:transform .18s}
  .chip-user[aria-expanded="true"] .caret{transform:rotate(180deg)}
  .menu{position:fixed;background:var(--surface);border:1px solid var(--line);border-radius:14px;box-shadow:0 16px 40px rgba(10,58,66,.22);padding:6px;min-width:210px;z-index:1000}
  .menu-item{display:block;width:100%;text-align:left;background:none;border:0;padding:10px 12px;border-radius:9px;font-size:13.5px;font-family:inherit;color:var(--ink);cursor:pointer;transition:.12s}
  .menu-item:hover{background:var(--light)}
  .menu-item .dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--gold);margin-right:8px;vertical-align:middle}

  /* Profil : valeurs en lecture seule */
  .modal .ro{font-size:14px;font-weight:600;color:var(--ink-2);padding:2px 0}

  /* Footer du site — bandeau pleine largeur (copyright) */
  .site-footer{background:var(--teal-deeper);margin-top:auto;padding-bottom:env(safe-area-inset-bottom,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}
  .foot-bottom{padding:20px 32px;text-align:center;font-size:12.5px;color:rgba(255,255,255,.7)}
  .foot-link{background:none;border:none;font-family:inherit;font-size:inherit;color:rgba(255,255,255,.82);text-decoration:underline;cursor:pointer;padding:0}
  .foot-link:hover{color:#fff}
  /* Pagination de la liste des utilisateurs (admin) */
  /* Pager placé HORS de la liste défilante (.adm-list a son propre ascenseur) → toujours visible */
  .upager{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
  .upager .psub{text-align:center;margin:0}
  /* Bandeau de reconnexion (échec réseau) */
  .netbar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;background:#FDF2F1;border:1px solid #F0C9C7;color:#B23A36;border-radius:12px;padding:12px 16px;margin-bottom:16px;font-size:13px;font-weight:600}
  /* Note « collaborateurs masqués » (découvrabilité) */
  .hidden-note{text-align:center;font-size:12.5px;color:var(--ink-2);margin:12px auto 2px;padding:7px 14px;max-width:max-content;background:var(--green-soft);border:1px solid #CDEBE2;border-radius:999px}
  /* État de chargement de la grille */
  .card.loading{opacity:.55;transition:opacity .12s;pointer-events:none}
  /* ===== Statistiques avancées (ADMIN uniquement) ===== */
  #adminStats{display:none}
  body.is-admin #adminStats{display:block}
  .admin-stats{margin-bottom:22px}
  .as-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap;margin-bottom:4px}
  .as-period{display:inline-flex;background:var(--light);border:1px solid var(--line);border-radius:11px;overflow:hidden;flex-wrap:wrap}
  .as-period button{background:none;border:0;font-family:inherit;font-size:12.5px;font-weight:600;color:var(--ink-2);padding:8px 13px;cursor:pointer;transition:.12s}
  .as-period button.active{background:var(--teal-dark);color:#fff} /* teal-dark : texte blanc AA (5,6:1) — l'ancien --teal tombait à 3,9:1, et à 2,5:1 en sombre */
  .as-custom{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:10px 0}
  .as-custom input{border:1px solid var(--line);border-radius:9px;padding:7px 10px;font-family:inherit;font-size:13px;color:var(--ink-2)}
  .as-range{margin:4px 0 14px;font-weight:600}
  .as-kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:18px}
  .as-kpi{background:var(--light);border-radius:12px;padding:12px 14px}
  .as-kv{font-size:21px;font-weight:800;color:var(--teal-deeper);line-height:1.1}
  .as-kl{font-size:11.5px;color:var(--grey);font-weight:600;margin-top:3px}
  .as-cols{display:grid;grid-template-columns:1.6fr 1fr;gap:24px}
  .as-subtitle{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--grey);font-weight:700;margin-bottom:12px}
  .as-row{display:flex;align-items:center;gap:10px;margin-bottom:9px}
  .as-rank{width:16px;text-align:center;font-weight:800;color:var(--grey);font-size:12px;flex:none}
  .as-av{width:26px;height:26px;border-radius:50%;overflow:hidden;flex:none;display:flex;align-items:center;justify-content:center;color:#fff;font-size:10px;font-weight:700}
  .as-av .ava-img{width:100%;height:100%;object-fit:cover}
  .as-nm{flex:0 0 130px;font-size:13px;font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .as-track{flex:1;height:9px;background:var(--light);border-radius:6px;overflow:hidden}
  .as-fill{height:100%;background:linear-gradient(90deg,var(--teal),var(--green));border-radius:6px}
  .as-n{width:34px;text-align:right;font-weight:700;color:var(--ink-2);font-size:12.5px;flex:none}
  .as-dow{display:flex;align-items:flex-end;gap:8px;height:160px}
  .as-dcol{flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;height:100%;justify-content:flex-end}
  .as-dbar-wrap{flex:1;width:100%;display:flex;align-items:flex-end;justify-content:center}
  .as-dbar{width:66%;background:linear-gradient(180deg,var(--teal),var(--green));border-radius:6px 6px 0 0;min-height:3px}
  .as-dn{font-size:12px;font-weight:700;color:var(--ink-2)}
  .as-dl{font-size:11px;color:var(--grey);font-weight:600}
  /* « Présents par jour » (personnes distinctes) + filtre espace partagé */
  .as-daysec{margin-top:22px}
  .as-daysec-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:10px}
  .as-daysec-head .as-subtitle{margin-bottom:0}
  .as-incl{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;font-weight:600;color:var(--ink-2);cursor:pointer;user-select:none}
  .as-incl input{width:15px;height:15px;accent-color:var(--shared);cursor:pointer}
  .as-days{overflow-x:auto;padding-bottom:6px}
  .as-days .as-dcol{flex:0 0 auto;min-width:34px}
  .as-days.incl .as-dbar{background:linear-gradient(180deg,var(--shared),#274a97)}
  @media(max-width:760px){ .as-cols{grid-template-columns:1fr;gap:18px} .as-kpis{grid-template-columns:repeat(2,1fr)} .as-nm{flex-basis:100px} }
  /* Modale confidentialité (RGPD) */
  .priv{font-size:13px;line-height:1.55;color:var(--ink-2)}
  .priv p{margin:0 0 11px}
  .priv b{color:var(--ink)}
  .priv a{color:var(--teal)}
  /* Bouton d'action dangereuse (suppression). Fond = --danger-bg, PAS --danger : c'est le bouton
     qui déclenche l'action la plus lourde, son libellé doit passer le seuil AA (cf. le jeton). */
  .btn-danger{background:var(--danger-bg);color:#fff;border:1px solid var(--danger-bg)}
  .btn-danger:hover{background:#A83531;border-color:#A83531}
  /* Accessibilité : anneau de focus clavier net et cohérent (sans gêner la souris) */
  .hf:focus-visible,.btn:focus-visible,.menu-item:focus-visible,.icobtn:focus-visible,#viewtog button:focus-visible,.foot-link:focus-visible,.link:focus-visible,.tc-person:focus-visible{outline:2px solid var(--teal);outline-offset:2px;border-radius:8px}
  .chip:focus-visible{outline:2px solid #fff;outline-offset:2px;border-radius:100px} /* chips sur en-tête foncé */
  /* Filtre : anneau de focus INSET (ne déborde pas du coin arrondi de l'en-tête) */
  .corner-search input:focus-visible{outline:none}
  .corner-search:focus-within{box-shadow:inset 0 0 0 2px var(--gold)}

  /* Photo de profil + verrouillage des lignes (lecture seule) */
  .avatar,.rank .av{overflow:hidden}
  .ava-img{width:100%;height:100%;object-fit:cover;display:block}
  .hf.locked{cursor:default;opacity:.45;pointer-events:none}
  tr.ro-row .who .nm{color:var(--grey)}
  .avatar.avatar-lg{width:84px;height:84px;font-size:27px;box-shadow:0 0 0 3px #fff,0 0 0 4px var(--line),0 8px 20px rgba(10,58,66,.14);transition:box-shadow .18s}
  /* Bloc photo de profil : cadre cliquable + badge caméra en overlay */
  .ava-edit{display:flex;align-items:center;gap:18px;margin-bottom:20px}
  .ava-frame{position:relative;flex:none;cursor:pointer;border-radius:50%;display:block}
  .ava-frame:hover .avatar-lg,.ava-frame:focus-visible .avatar-lg{box-shadow:0 0 0 3px #fff,0 0 0 4px var(--teal),0 10px 24px rgba(10,58,66,.22)}
  .ava-frame:focus-visible{outline:none}
  .ava-cam{position:absolute;right:-2px;bottom:-2px;width:28px;height:28px;border-radius:50%;background:var(--teal);color:#fff;display:flex;align-items:center;justify-content:center;border:2.5px solid #fff;box-shadow:0 2px 7px rgba(10,58,66,.28)}
  .ava-cam svg{width:15px;height:15px}
  .ava-actions{display:flex;flex-direction:column;align-items:flex-start;gap:9px}
  .ava-pick{cursor:pointer;margin:0;display:inline-flex;align-items:center;gap:7px}
  .ava-pick svg{width:15px;height:15px}
  .ava-del{color:var(--danger);font-weight:600}
  /* Recadrage de photo (cropper) */
  .crop-wrap{position:relative;width:260px;max-width:100%;margin:0 auto 4px;border-radius:14px;overflow:hidden;background:#0A3A42;touch-action:none;user-select:none}
  .crop-cv{display:block;cursor:grab;touch-action:none}
  .crop-cv:active{cursor:grabbing}
  .crop-mask{position:absolute;inset:0;pointer-events:none;border-radius:50%;box-shadow:0 0 0 999px rgba(10,58,66,.42);outline:2px solid rgba(255,255,255,.75);outline-offset:-2px}
  .crop-zoom{display:flex;align-items:center;gap:12px;margin:16px 0 6px;color:var(--grey);font-weight:700;font-size:16px}
  .crop-zoom input[type=range]{flex:1;accent-color:var(--teal);height:4px}

  /* ===== Responsive planning / toolbar — placé après les règles de base pour surcharger correctement ===== */
  @media(max-width:860px){
    .col-name{width:200px;min-width:190px}
    table.plan{min-width:660px}
  }
  /* 768px (et non 640) : la vue Semaine passe en cartes empilées dès le zoom 200 % des écrans
     courants (≈683–768 px CSS) → plus de défilement horizontal 2D (WCAG 1.4.10 reflow). */
  @media(max-width:768px){
    .nav .period{min-width:0;font-size:15px}
    .toolbar{gap:10px}
    /* Vue Mois : tableau défilant compact */
    table.plan.month{min-width:560px}
    table.plan.month .col-name{width:132px;min-width:124px}
    /* Vue Semaine : conteneur .card neutralisé → barre de recherche autonome + une carte par collaborateur */
    .card.grid-week{background:none;border:none;box-shadow:none;border-radius:0;overflow:visible}
    .card.grid-week .grid-scroll{overflow:visible;max-height:none} /* vue Semaine mobile = cartes empilées : pas de cadre borné (#3) */
    table.plan:not(.month){display:block;min-width:0;width:100%}
    table.plan:not(.month) thead,table.plan:not(.month) thead tr{display:block}
    table.plan:not(.month) thead th:not(.corner){display:none}
    /* Barre de recherche : champ autonome, posé au-dessus de la liste */
    /* height:auto OBLIGATOIRE : `thead th{height:1px}` (astuce .dh-cell height:100%) n'est anodin que
       sur une cellule de TABLEAU, où la hauteur n'est qu'un minimum et la cellule s'étire. Ici le corner
       passe en display:block → 1px devient une vraie hauteur → la barre de recherche s'écrase et seul
       son contour dépasse derrière la 1re carte (l'« artefact » signalé). */
    /* border:0 — `table.plan th,td{border-bottom:1px solid var(--line)}` (séparateur de LIGNES du
       tableau) n'a plus de sens ici : la cellule devient un champ de recherche autonome, et ce filet
       traversait toute la largeur sous « Filtrer un nom… ». Le cadre visible est celui du champ. */
    table.plan:not(.month) th.corner{display:block;width:auto;height:auto;border:0;position:static;left:auto;box-shadow:none;background:none;padding:0;margin:0 0 14px}
    table.plan:not(.month) th.corner .t{display:none}
    table.plan:not(.month) .corner-search{max-width:none;margin-top:0;background:var(--surface);border-color:var(--line);border-radius:12px;box-shadow:0 2px 10px rgba(10,58,66,.06);padding:2px 13px}
    table.plan:not(.month) .corner-search svg{color:var(--grey);width:16px;height:16px}
    table.plan:not(.month) .corner-search input{color:var(--ink-2);font-size:16px;padding:10px 4px}
    table.plan:not(.month) .corner-search input::placeholder{color:var(--grey)}
    /* Chaque collaborateur = carte distincte, empilée (uniquement le corps, pas la ligne d'en-tête) */
    table.plan:not(.month) tbody{display:block}
    table.plan:not(.month) tbody tr{display:block;border:1px solid var(--line);border-radius:16px;box-shadow:0 2px 12px rgba(10,58,66,.06);margin-bottom:12px}
    /* :not(.solo) — même raison qu'en grille : seule carte affichée, la barre teal « c'est vous »
       ne distingue plus rien. Elle revient avec « Afficher tout le monde ». */
    table.plan:not(.month):not(.solo) tbody tr.me-row{box-shadow:0 2px 12px rgba(10,58,66,.06),inset 4px 0 0 var(--teal)}
    /* Figer « ma ligne » (#7) est une notion de GRILLE : en cartes empilées il n'y a plus de ligne à
       figer — seul le bandeau nom colle (M5, plus bas). Sans cette annulation, la règle desktop
       laisse chaque cellule-jour en position:sticky avec un liseré teal → traits parasites entre
       les jours de MA carte (et d'elle seule). Le repère « c'est moi » = la barre teal ci-dessus. */
    table.plan:not(.month) tbody tr.me-row>th.col-name,
    table.plan:not(.month) tbody tr.me-row>td{border-bottom:0}
    table.plan:not(.month) tbody tr.me-row>td{position:static}
    table.plan:not(.month) td{border:none}
    /* M5 : le bandeau nom reste collé en haut de la carte pendant qu'on fait défiler ses demi-journées. */
    table.plan:not(.month) th.name.col-name{display:block;width:auto;position:sticky;top:0;z-index:3;left:auto;box-shadow:none;background:var(--teal-deeper);padding:11px 15px;border-radius:16px 16px 0 0}
    table.plan:not(.month) tbody tr td.day:last-child{border-radius:0 0 16px 16px}
    table.plan:not(.month) th.name .nm{color:#fff}
    table.plan:not(.month) th.name .rl{color:rgba(238,222,198,.82)}
    table.plan:not(.month) th.name .cnt{color:#fff;background:rgba(255,255,255,.16)}
    table.plan:not(.month) td.day{display:flex;align-items:center;gap:10px;border-top:1px solid var(--line);padding:7px 14px;background:var(--surface)}
    table.plan:not(.month) td.day::before{content:attr(data-d);flex:0 0 96px;font-size:12.5px;font-weight:600;color:var(--ink-2)}
    /* Mobile : le trait de mois devient une bordure haute dorée (au lieu d'une gauche) sur la ligne du jour */
    table.plan:not(.month) td.day.monthstart{border-top:2px solid var(--gold);border-left:none}
    table.plan:not(.month) td.day.today{background:rgba(227,172,43,.07)}
    table.plan:not(.month) td.day.holiday{background:rgba(217,83,79,.06)}
    table.plan:not(.month) td.day.holiday::before{color:var(--danger)}
    table.plan:not(.month) .halves{flex:1;gap:8px}
    table.plan:not(.month) .hf{height:44px;gap:7px;font-size:13px;font-weight:700;color:#5a6b72;border-radius:10px}
    table.plan:not(.month) .hf::before{content:attr(data-lbl)}
    table.plan:not(.month) .hf:not(.on) svg{display:none}
    table.plan:not(.month) .hf.on{color:#fff}
    table.plan:not(.month) .hf.locked{opacity:.5;pointer-events:none}
  }

  /* Respect du réglage système « réduire les animations » (WCAG 2.3.3 / vestibulaire) */
  @media (prefers-reduced-motion: reduce){
    *,*::before,*::after{transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important}
  }

  /* ---- Retrait de `unsafe-inline` (CSP style-src 'self') : couleurs d'avatar en CLASSES ---- */
  /* Palette FIXE (miroir de PALETTE dans app.js) : colorFor(id)=PALETTE[id%10] → classe av0..av9.
     Remplace les style="background:…" inline des avatars (indexés, donc non « injectables »). */
  .av0{background:#0A6A73}.av1{background:#9C5B12}.av2{background:#2F7A5E}.av3{background:#245C86}.av4{background:#254046}
  .av5{background:#A8531A}.av6{background:#12707B}.av7{background:#6E4EA6}.av8{background:#0E5A63}.av9{background:#8A4E7D}

  /* ---- Retrait de `unsafe-inline` : styles STATIQUES ex-inline → utilitaires (déclarations identiques) ---- */
  .u-modal-p{font-size:14px;line-height:1.55;color:var(--ink-2);margin:0 0 4px}
  .u-row{display:flex;gap:12px}
  .u-flex1{flex:1}
  .u-scroll70{max-height:70vh;overflow:auto}
  .u-scroll74{max-height:74vh;overflow:auto}
  .u-mb22{margin-bottom:22px}
  .u-mt8{margin:8px 2px 0}
  .u-sec-div{border-top:1px solid var(--line);padding-top:14px;margin-top:4px}
  .u-row-mt{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
  .u-row-between{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:10px}
  .u-row-wrap{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
  .u-perlbl{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--ink-2)}
  .u-persel{padding:6px 26px 6px 10px;min-width:60px}
  .u-freq{font-size:17px;font-weight:800;line-height:1.15;display:inline-block}
  .u-clickable{cursor:pointer}
  .af-wrap2{flex-wrap:wrap;border-top:none;padding-top:2px}
  .af-wrap0{flex-wrap:wrap;border-top:none;padding-top:0}
  /* template */
  .u-hero-row{display:flex;justify-content:space-between;align-items:flex-end;gap:12px;flex-wrap:wrap}
  .u-my8-18{margin:8px 0 18px}
  .u-my2-22{margin:2px 0 22px}
  .sq-teal{background:var(--teal)}
  .sq-green{background:var(--green)}

  /* ---- Modale « Nouveautés » (changelog) ---- */
  .cl-rel{margin:0 0 18px}
  .cl-date{display:flex;align-items:center;gap:10px;font-weight:800;font-size:14.5px;color:var(--ink);border-bottom:1px solid var(--line);padding-bottom:6px;margin-bottom:8px}
  .cl-v{font-size:11.5px;font-weight:700;color:var(--teal-dark);background:var(--light);border:1px solid var(--line);border-radius:999px;padding:2px 9px}
  .cl-ul{list-style:none;margin:0;padding:0}
  .cl-it{display:flex;align-items:flex-start;gap:9px;padding:4px 0;font-size:13.5px;line-height:1.5;color:var(--ink-2)}
  .cl-k{flex:0 0 auto;font-size:10.5px;font-weight:800;letter-spacing:.02em;border-radius:6px;padding:2px 7px;margin-top:2px}
  .cl-new{background:var(--green-soft);color:var(--green)}
  .cl-imp{background:var(--shared-soft);color:var(--shared)}
  .cl-fix{background:var(--maybe-soft);color:var(--maybe)}
  .cl-sec{background:var(--fill);color:var(--ink-2)}

  /* ---- Édition admin du Wi-Fi (infos pratiques) ---- */
  /* Rendu côté serveur UNIQUEMENT pour l'admin (if $admin). Mais en « Vue collab » (aperçu), on masque
     aussi : body.is-admin = effAdmin() = admin RÉEL et hors aperçu (retiré par applyRole en preview). */
  body:not(.is-admin) .oi-edit{display:none}
  .oi-edit{margin-left:auto;align-self:center;flex:0 0 auto;font-size:11.5px;font-weight:700;color:var(--teal-dark);background:var(--surface);border:1px solid var(--line);border-radius:8px;padding:5px 11px;cursor:pointer;transition:.12s}
  .oi-edit:hover{background:var(--light);border-color:var(--teal)}
  .oi-edit:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
  .oi-muted{color:var(--ink-2);font-style:italic}

  /* ═══════════════════════════════════════════════════════════════════════════════════════
     THÈME SOMBRE — activé par `data-theme="dark"` sur <html> (toggle dans l'en-tête, persistant
     via localStorage, anti-flash par script inline noncé). Approche alignée sur timescan.intenz.fr
     et la charte InTenz : on ne redéfinit que les TOKENS (surfaces → sombres, texte → clair, accents
     → éclaircis). Tout l'app se re-thème sans toucher aux règles claires (mode clair inchangé).
     Restent tels quels (déjà sombres / texte blanc AA) : en-tête, thead, en-tête de modale, tooltip,
     et les états colorés desk / peut-être / espace partagé (fond de couleur + glyphe blanc).
     ═══════════════════════════════════════════════════════════════════════════════════════ */
  :root[data-theme="dark"]{
    color-scheme:dark; /* contrôles natifs (date-pickers, scrollbars, spinners) en sombre */
    --bg:#0C171B;--surface:#15252D;--surface-2:#1C2E36;
    --fill:#223640;--fill-bd:#3A5058;--fill-ink:#AEC0C6;
    --ink:#E6EDEF;--ink-2:#F1F6F7;--grey:#9FB0B6;--line:#26383F;
    --light:#1C3238;--green-soft:#14332B;         /* fills doux (chips, pistes, hovers) → sombres */
    --maybe-soft:#332711;--shared-soft:#16233F;   /* badges « peut-être » / « espace partagé » → sombres */
    --teal:#35B5C0;--link:#35B5C0;                               /* teal clair : texte/icônes sur fond sombre (AA) */
    --shadow:0 12px 34px rgba(0,0,0,.5);          /* ombre lisible sur fond sombre */
  }
  /* --teal-dark reste sombre (fond de bouton teal + texte blanc, AA) ; là où il sert de TEXTE sur
     fond sombre, on bascule vers le teal clair pour le contraste. */
  :root[data-theme="dark"] .who .cnt,
  :root[data-theme="dark"] .cap input,
  :root[data-theme="dark"] .oi-edit,
  :root[data-theme="dark"] .tc-sum,
  :root[data-theme="dark"] .dens-btn,
  :root[data-theme="dark"] .nudge-ic,
  :root[data-theme="dark"] .gd-ic{color:var(--teal)}
  :root[data-theme="dark"] .nudge .link,
  :root[data-theme="dark"] .hidden-note .link,
  :root[data-theme="dark"] .rs-repl{color:var(--teal)}                 /* texte lisible sur le vert doux sombre */
  :root[data-theme="dark"] .rs-repl:hover{color:#fff}                  /* survol : fond teal-dark → texte blanc */
  /* Badges du changelog : teintes d'état éclaircies (le vert/ambre/bleu foncé serait illisible sur sombre). */
  :root[data-theme="dark"] .cl-new{color:#54C9A4}
  :root[data-theme="dark"] .cl-imp{color:#7FA3E8}
  :root[data-theme="dark"] .cl-fix{color:#E0B25E}
  /* Compteurs « peut-être » / « espace partagé » du panneau du jour : couleur d'état = texte sur fond
     doux → éclaircie sur sombre (comme les badges du changelog). */
  :root[data-theme="dark"] .tc-x.maybe{color:#E0B25E}
  :root[data-theme="dark"] .tc-x.shared{color:#7FA3E8}
  /* Bannières d'alerte (sémantique de couleur) : fond sombre teinté + texte clair lisible. */
  :root[data-theme="dark"] .err{background:#3A1E1D;border-color:#5C2E2B;color:#F3A9A5}
  :root[data-theme="dark"] .cd-warn,
  :root[data-theme="dark"] .note,
  :root[data-theme="dark"] .cap-alert{background:#2E2712;border-color:#4E4322;color:#EAC97C}
  /* Le <b> gardait #7A4E10 (thème clair) sur ce fond sombre : 2,07:1 — la valeur mise en
     avant était la moins lisible de la bande. 11,07:1 désormais. Le pictogramme suit. */
  :root[data-theme="dark"] .cap-alert b{color:#F6DCA0}
  :root[data-theme="dark"] .cap-alert svg{color:#E0A857}
  /* Puce utilisateur : léger renfort de bordure sur fond sombre (l'en-tête reste teal). */
  :root[data-theme="dark"] .chip{background:rgba(255,255,255,.10);border-color:rgba(255,255,255,.18)}
  /* Administration (table collaborateurs) : couleurs claires codées en dur → versions sombres lisibles (AA). */
  :root[data-theme="dark"] .utable tr.inactive td,
  :root[data-theme="dark"] .utable tr.inactive .ut-nm{color:#8B9AA0}          /* ligne archivée : gris atténué mais ≥ 4.5:1 */
  :root[data-theme="dark"] .utable tr.inactive td.ut-name{background:var(--surface-2)} /* nom (carte mobile) archivé */
  :root[data-theme="dark"] .ut-ll .ll-never{color:#F0A6A2}                    /* « jamais connecté » : rouge éclairci */
  :root[data-theme="dark"] .tag{color:var(--grey)}                            /* étiquette neutre : texte clair sur fill sombre */
  :root[data-theme="dark"] .tag-admin{background:#3A2E12;color:#EBC978}       /* étiquette « admin » (doré) → fond sombre */
  :root[data-theme="dark"] .tag-collab{background:#123238;color:#4FC5D0}      /* étiquette « collab » (teal) → fond sombre */
  :root[data-theme="dark"] .tag-wait{background:#3A1E1D;color:#F0A6A2}         /* étiquette « en attente » (rose/rouge) → fond sombre */
  /* Statistiques (dépliées) : valeurs KPI en teal foncé codé en dur → teal clair lisible sur sombre. */
  :root[data-theme="dark"] .as-kv{color:var(--teal)}
  /* Grille — JOUR FÉRIÉ : la teinte rouge translucide POSÉE SUR le thead teal vire au gris terne
     (rouge + teal = complémentaires → neutre) et, sur fond sombre, « ressort » comme un bloc plus
     clair. On pose donc un rouge sombre OPAQUE : lisible comme « férié », en léger retrait. */
  /* Teinte sur TOUTE la cellule d'en-tête (pas seulement `.day-h`) : sinon le bloc rouge — plus haut
     que les autres à cause de la ligne « Fête nationale » — flotte et « déborde » sur la rangée M/A.
     Toute la colonne d'en-tête devient un rouge uniforme, même hauteur que les autres. */
  :root[data-theme="dark"] thead th.holiday{background:#3D232A}
  :root[data-theme="dark"] thead th.holiday .day-h,
  :root[data-theme="dark"] thead th.holiday .day-h.today{background:transparent}
  :root[data-theme="dark"] td.day.holiday{background:rgba(240,115,111,.05)}
  /* Même exception qu'en clair, avec la teinte sombre (cf. le bloc « ligne figée ») : sans elle, la
     cellule férié de la ligne figée reste transparente à 95 % en thème sombre. */
  :root[data-theme="dark"] table.plan:not(.solo) tbody tr.me-row>td.day.holiday{background:linear-gradient(rgba(240,115,111,.05),rgba(240,115,111,.05)) var(--green-soft)}
  :root[data-theme="dark"] tbody tr:hover td.day.holiday{background:rgba(240,115,111,.10)}
  /* Journée bloquée, thème sombre : même traitement que le férié (fond porté par le th, day-h
     transparent), avec un rouge un cran plus present — c'est une décision, pas le calendrier. */
  :root[data-theme="dark"] thead th.blocked{background:#4A2830}
  :root[data-theme="dark"] thead th.blocked .day-h,
  :root[data-theme="dark"] thead th.blocked .day-h.today{background:transparent}
  :root[data-theme="dark"] td.day.blocked{background:rgba(240,115,111,.05)}
  :root[data-theme="dark"] tbody tr:hover td.day.blocked{background:rgba(240,115,111,.10)}
  :root[data-theme="dark"] table.plan:not(.solo) tbody tr.me-row>td.day.blocked{background:linear-gradient(rgba(240,115,111,.05),rgba(240,115,111,.05)) var(--green-soft)}
  /* Même partage qu'en clair : fond rouge = bureau indisponible, glyphe bleu = action permise. */
  :root[data-theme="dark"] .hf.shut{color:#7E9BE8;border-color:#7E9BE8;
    background:repeating-linear-gradient(135deg,rgba(240,115,111,.30) 0 5px,transparent 5px 11px),var(--surface-2)}
  :root[data-theme="dark"] .nudge-block{background:rgba(240,115,111,.10)}
  :root[data-theme="dark"] .nudge-block .nudge-ic{color:#F0736F}
  /* Sombre : le rouge de la charte claire perd du contraste sur fond sombre - on passe au rouge clair. */
  :root[data-theme="dark"] .inc-item{background:rgba(240,115,111,.10);border-color:#F0736F;border-left-color:#F0736F}
  :root[data-theme="dark"] .inc-ic{color:#F0736F}
  /* Grille — bouton « ··· » (plus d'options) des cases VIDES : glyphe #33454B + fond gris sombres
     → quasi invisibles sur le fill sombre. On éclaircit le fond ET on révèle discrètement les points
     (masqués par .hf svg{opacity:0}) pour un vrai repère « ··· » au lieu d'un carré nu à peine visible. */
  :root[data-theme="dark"] .hf:not(.on) .hf-more{color:#CAD6DB;background:rgba(255,255,255,.13)}
  :root[data-theme="dark"] .hf:not(.on) .hf-more svg{opacity:.6}
  :root[data-theme="dark"] .hf:not(.on) .hf-more:hover{opacity:1;background:rgba(255,255,255,.22)}
  :root[data-theme="dark"] .hf:not(.on) .hf-more:hover svg{opacity:1}

  /* ---------- Visite guidée ---------- */
  /* Voile sombre au-dessus de tout (l'overlay des modales est à z-index 100). L'élément mis en
     avant est remonté au-dessus du voile par `.tour-spot` ; la carte explicative encore au-dessus. */
  .tour-veil{position:fixed;inset:0;background:rgba(10,58,66,.60);z-index:1000;animation:tour-fade .15s ease}
  @keyframes tour-fade{from{opacity:0}to{opacity:1}}
  /* La cible désignée : remontée au-dessus du voile, détourée, et rendue inerte le temps de la
     visite (on montre, on ne clique pas — règle 2). `position:relative` seulement si l'élément est
     encore en `static`, pour ne pas casser les cellules déjà collantes (sticky) du planning. */
  .tour-spot{position:relative;z-index:1001;box-shadow:0 0 0 3px var(--teal),0 0 0 7px rgba(4,139,154,.35),0 12px 30px rgba(0,0,0,.35);border-radius:10px;pointer-events:none}
  .tour-on{overflow:hidden} /* fige le défilement de fond pendant la visite */
  .tour-card{position:fixed;z-index:1002;max-width:min(340px,calc(100vw - 24px));background:var(--surface);color:var(--ink);border:1px solid var(--line);border-radius:16px;box-shadow:0 24px 60px rgba(0,0,0,.35);padding:18px 18px 14px;animation:tour-fade .15s ease}
  .tour-step{font-size:11px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;color:var(--teal-dark)}
  .tour-t{margin:4px 0 6px;font-size:17px;line-height:1.25;color:var(--ink)}
  .tour-x{margin:0 0 14px;font-size:13.5px;line-height:1.5;color:var(--ink-2)}
  .tour-nav{display:flex;align-items:center;gap:8px}
  .tour-nav .tour-sp{flex:1}
  :root[data-theme="dark"] .tour-step{color:var(--teal)}
