:root {
  --bg-primary: #ffffff;
  --bg-secondary: #f5f5f3;
  --bg-tertiary: #eeede9;
  --bg-info: #e6f1fb;
  --bg-success: #eaf3de;
  --bg-danger: #fcebeb;
  --text-primary: #1a1a18;
  --text-secondary: #5f5e5a;
  --text-tertiary: #888780;
  --text-info: #185fa5;
  --text-success: #3b6d11;
  --text-danger: #a32d2d;
  --border: rgba(0,0,0,0.12);
  --border-md: rgba(0,0,0,0.20);
  --accent: #4e7a36;
  --accent-light: #eaf3df;
  --green: #1d9e75;
  --green-light: #e1f5ee;
  --red: #e24b4a;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --font: 'IBM Plex Sans', system-ui, -apple-system, sans-serif;
  --font-mono: ui-monospace, 'IBM Plex Mono', monospace;
  --shadow-md: 0 4px 12px rgba(0,0,0,0.10);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg-primary: #1c1c1a;
    --bg-secondary: #252523;
    --bg-tertiary: #2c2c2a;
    --text-primary: #f0efe9;
    --text-secondary: #b4b2a9;
    --text-tertiary: #888780;
    --border: rgba(255,255,255,0.10);
    --border-md: rgba(255,255,255,0.18);
    --accent: #6b8f49;
    --accent-light: #20301a;
  }
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* L'attribut `hidden` doit TOUJOURS l'emporter.
   Le `display: none` de la feuille du navigateur a une specificite nulle : la
   moindre classe qui pose un `display` le bat, et l'element reste visible bien
   que `hidden` soit mis. Le piege a mordu deux fois — le bandeau d'alerte du
   standard, puis le selecteur d'equipe du rappeleur, visible pour les managers
   alors qu'il est reserve aux admins. Une regle globale ferme la classe entiere
   de defauts au lieu de la rattraper cas par cas.
   Meme parti que normalize.css. */
[hidden] { display: none !important; }

body { font-family: var(--font); font-size: 15px; background: var(--bg-tertiary); color: var(--text-primary); min-height: 100vh; -webkit-font-smoothing: antialiased; }

.app { max-width: 960px; margin: 0 auto; background: var(--bg-primary); min-height: 100vh; display: flex; flex-direction: column; }

.login-screen { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 24px; }
.login-card { background: var(--bg-primary); border: 0.5px solid var(--border-md); border-radius: var(--radius-lg); padding: 32px; width: 100%; max-width: 360px; box-shadow: var(--shadow-md); }
.login-card h1 { font-size: 18px; font-weight: 600; margin-bottom: 4px; }
.login-card .sub { font-size: 13px; color: var(--text-secondary); margin-bottom: 24px; }

label { display: block; font-size: 12px; color: var(--text-secondary); margin: 12px 0 6px; font-weight: 500; }
input[type="text"], input[type="password"], textarea {
  width: 100%; padding: 10px 12px; font-size: 14px; font-family: var(--font);
  background: var(--bg-secondary); color: var(--text-primary);
  border: 0.5px solid var(--border-md); border-radius: var(--radius-md);
}
input:focus { outline: 2px solid var(--accent); outline-offset: -2px; border-color: var(--accent); }

.btn { padding: 9px 18px; font-size: 14px; font-family: var(--font); font-weight: 500;
       border-radius: var(--radius-md); border: none; cursor: pointer;
       display: inline-flex; align-items: center; gap: 6px; transition: opacity .15s; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary { background: var(--accent); color: white; width: 100%; justify-content: center; margin-top: 18px; }
.btn-primary:hover:not(:disabled) { opacity: 0.9; }

.alert { padding: 10px 12px; border-radius: var(--radius-md); font-size: 13px; margin-top: 12px; }
.alert-error { background: var(--bg-danger); color: var(--text-danger); }
.alert-info  { background: var(--bg-info); color: var(--text-info); }
.alert-success { background: var(--bg-success); color: var(--text-success); }

/* Modal (HTML <dialog>) */
/* margin:auto est INDISPENSABLE : le reset `* { margin: 0 }` plus haut écrase la règle
   navigateur `dialog:modal { margin: auto }` qui centre les modales. Sans lui, elles se
   collent en haut à gauche du viewport — loin du clic, par-dessus la barre latérale, et
   comme showModal() rend le reste de la page inerte, l'interface paraît figée. */
dialog.modal { margin: auto; border: none; border-radius: var(--radius-lg); padding: 0; max-width: 480px; width: 90%;
               background: var(--bg-primary); color: var(--text-primary); box-shadow: var(--shadow-md); }
/* Modale plus haute que l'écran : on fait défiler le corps, pas la fenêtre. */
dialog.modal[open] { display: flex; flex-direction: column; }
dialog.modal .modal-body { overflow-y: auto; }
dialog.modal::backdrop { background: rgba(0,0,0,0.45); }
.modal-header { padding: 16px 20px; border-bottom: 0.5px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
.modal-header h2 { font-size: 16px; font-weight: 600; }
.modal-close { background: none; border: none; cursor: pointer; font-size: 20px; color: var(--text-tertiary); padding: 4px 8px; }
.modal-body { padding: 16px 20px; }
.modal-footer { padding: 12px 20px; border-top: 0.5px solid var(--border); display: flex; gap: 8px; justify-content: flex-end; background: var(--bg-secondary); }
.modal select { width: 100%; padding: 9px 12px; font-size: 14px; font-family: var(--font); background: var(--bg-secondary); color: var(--text-primary); border: 0.5px solid var(--border-md); border-radius: var(--radius-md); }
.modal .row { display: flex; gap: 12px; align-items: center; margin: 10px 0; }
.modal .row label { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-size: 13px; cursor: pointer; }
.btn-secondary { background: var(--bg-tertiary); color: var(--text-primary); border: 0.5px solid var(--border-md); margin: 0; width: auto; }
.btn-secondary:hover:not(:disabled) { background: var(--bg-secondary); }
.btn.btn-primary.btn-inline { width: auto; margin: 0; padding: 8px 16px; }

/* Toggle switch */
.toggle { position: relative; display: inline-block; width: 36px; height: 20px; }
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle-slider { position: absolute; cursor: pointer; inset: 0; background: var(--border-md); border-radius: 20px; transition: .2s; }
.toggle-slider::before { content: ''; position: absolute; height: 14px; width: 14px; left: 3px; bottom: 3px; background: white; border-radius: 50%; transition: .2s; }
.toggle input:checked + .toggle-slider { background: var(--accent); }
.toggle input:checked + .toggle-slider::before { transform: translateX(16px); }

/* Status card */
.status-card { padding: 14px 16px; border-radius: var(--radius-md); border: 0.5px solid var(--border-md);
               display: flex; align-items: center; gap: 12px; margin-bottom: 18px; background: var(--bg-secondary); }
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; background: var(--text-tertiary); }
.status-dot.ok { background: var(--green); box-shadow: 0 0 6px var(--green-light); }
.status-dot.err { background: var(--red); }
.status-text { flex: 1; font-size: 13px; }
.status-text strong { font-weight: 600; }
.status-text .sub { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.status-actions { display: flex; gap: 8px; }
.status-actions .btn { padding: 6px 12px; font-size: 12px; }

/* Clickable rows */
tr.clickable { cursor: pointer; }
tr.clickable:hover { background: var(--accent-light); }

/* Sticky right (badge redirection + toggle standard) */
.sticky-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.fwd-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600;
             padding: 6px 14px; background: var(--bg-warning, var(--bg-danger));
             color: var(--text-warning, var(--text-danger)); border-radius: var(--radius-pill, 999px);
             border: 1px solid var(--text-warning, var(--text-danger)); }
.toggle-std { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; font-size: 12px; color: var(--text-secondary); }
.toggle-std input { display: none; }
.toggle-std .toggle-slider { position: relative; width: 32px; height: 18px; background: var(--border-md); border-radius: 18px; transition: .2s; }
.toggle-std .toggle-slider::before { content: ''; position: absolute; height: 14px; width: 14px; left: 2px; top: 2px; background: white; border-radius: 50%; transition: .2s; }
.toggle-std input:checked + .toggle-slider { background: var(--green); }
.toggle-std input:checked + .toggle-slider::before { transform: translateX(14px); }
.toggle-std .toggle-text { font-weight: 500; }

/* ── Bannière d'appel en cours ─────────────────────────────────────────────
   Les couleurs d'état sont des variables LOCALES : elles ne fuient sur aucun
   autre composant. Le fond reprend les surfaces du thème plutôt qu'une teinte
   figée — l'ancien --green-light, jamais redéfini en sombre, donnait du texte
   clair sur fond clair. La teinte d'état ne porte que l'accent, jamais le texte. */
.live-banner {
  /* Vert assombri par rapport à --green (#1d9e75) : celui-ci ne donne que 3.4:1 sur
     fond clair, sous le seuil de 4.5:1 exigé pour du texte de 12 px. Même famille
     de couleur, contraste conforme. */
  --call-tone: #157a5a;
  --call-tint: rgba(29, 158, 117, 0.13);
  --call-btn-fg: #fff;
  display: none; align-items: center; gap: 18px;
  padding: 20px 24px;
  background: var(--bg-primary);
  border-bottom: 1px solid var(--border);
  box-shadow: inset 3px 0 0 var(--call-tone), 0 1px 3px rgba(0,0,0,0.06);
  animation: slideDown .2s ease;
}
.live-banner.ringing { --call-tone: #b06000; --call-tint: rgba(176, 96, 0, 0.13); }
@media (prefers-color-scheme: dark) {
  /* Teintes éclaircies : sur surface sombre, les tons pleins passent sous le seuil
     de contraste (cf. règle color-dark-mode — on ne réutilise pas les valeurs du
     mode clair telles quelles). */
  .live-banner { --call-tone: #4ecfa0; --call-tint: rgba(78, 207, 160, 0.16); }
  .live-banner.ringing { --call-tone: #ffa726; --call-tint: rgba(255, 167, 38, 0.16); }
  /* En sombre, --accent est éclairci (#6b8f49) pour servir de couleur de texte :
     employé comme fond de bouton, le blanc dessus ne donne que 3.7:1. On inverse
     donc — texte sombre sur accent clair, comme le veut la logique « on-primary »
     des thèmes sombres. */
  .live-banner { --call-btn-fg: #12210b; }
}
.live-banner:not([hidden]) { display: flex; }
@keyframes slideDown { from { opacity:0; transform: translateY(-6px) } to { opacity:1; transform: translateY(0) } }

.live-icon { flex: 0 0 auto; width: 54px; height: 54px; border-radius: 50%;
             display: grid; place-items: center;
             background: var(--call-tint); color: var(--call-tone); }
.live-icon .material-symbols-rounded { font-size: 30px; }
/* La sonnerie pulse pour attirer l'œil ; en communication, plus rien ne bouge. */
.live-banner.ringing .live-icon { animation: callPulse 1.6s ease-in-out infinite; }
@keyframes callPulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--call-tint); }
  50%      { box-shadow: 0 0 0 7px transparent; }
}

.live-info { flex: 1; min-width: 0; }
.live-title { font-size: 21px; font-weight: 600; color: var(--text-primary);
              line-height: 1.25; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.live-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 5px; }
.live-phone { font-family: var(--font-mono); font-size: 14px; color: var(--text-secondary); }
.live-tag { display: inline-flex; align-items: baseline; gap: 5px;
            font-size: 12px; font-weight: 500; padding: 2px 9px; border-radius: 999px;
            background: var(--bg-tertiary); color: var(--text-primary); }
/* Intitulé du champ en retrait : c'est la valeur qui doit sauter aux yeux. */
.live-tag-k { font-size: 10px; font-weight: 600; text-transform: uppercase;
              letter-spacing: .04em; color: var(--text-tertiary); }
.live-state { display: flex; align-items: center; gap: 7px; margin-top: 6px;
              font-size: 13px; font-weight: 500; color: var(--call-tone); }
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--call-tone); flex: 0 0 auto; }
.live-banner.ringing .live-dot { animation: dotBlink 1.6s ease-in-out infinite; }
@keyframes dotBlink { 0%, 100% { opacity: 1 } 50% { opacity: .25 } }
/* Chiffres à chasse fixe : le compteur ne fait pas sautiller la ligne. */
.live-timer { font-variant-numeric: tabular-nums; font-family: var(--font-mono);
              color: var(--text-secondary); font-weight: 400; }

/* Action principale de la bannière — une seule, pleine, et bien détachée : c'est
   ce qu'on doit repérer sans chercher pendant que le téléphone sonne. */
.live-action { flex: 0 0 auto; }
.crm-btn { display: inline-flex; align-items: center; gap: 9px; min-height: 52px;
           padding: 0 24px; border-radius: var(--radius-md);
           background: var(--accent); color: var(--call-btn-fg); font-size: 15px; font-weight: 700;
           letter-spacing: .01em; text-decoration: none; white-space: nowrap;
           box-shadow: 0 2px 10px rgba(0,0,0,0.18);
           transition: opacity .15s, transform .15s, box-shadow .15s; }
.crm-btn:hover { opacity: .92; box-shadow: 0 4px 16px rgba(0,0,0,0.26); transform: translateY(-1px); }
.crm-btn:active { transform: scale(.97); }
.crm-btn:focus-visible { outline: 3px solid var(--call-tone); outline-offset: 3px; }
.crm-btn .material-symbols-rounded { font-size: 21px; }
/* Pendant la sonnerie, un halo pulsé dans le ton de l'état attire l'œil dessus. */
.live-banner.ringing .crm-btn { animation: crmGlow 1.8s ease-in-out infinite; }
@keyframes crmGlow {
  0%, 100% { box-shadow: 0 2px 10px rgba(0,0,0,0.18), 0 0 0 0 var(--call-tint); }
  50%      { box-shadow: 0 2px 10px rgba(0,0,0,0.18), 0 0 0 8px transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .live-banner, .live-banner .live-icon, .live-banner .live-dot,
  .live-banner.ringing .crm-btn { animation: none; }
  .crm-btn { transition: none; }
  .crm-btn:hover { transform: none; }
}
@media (max-width: 800px) { .live-banner { display: none !important; } }

/* Composer (click-to-call) */
.composer { display: flex; align-items: center; gap: 8px; padding: 14px 16px;
            background: var(--bg-secondary); border-bottom: 0.5px solid var(--border);
            flex-wrap: wrap; }
.composer input[type="tel"] { flex: 1; min-width: 200px; padding: 9px 12px; font-size: 14px;
            font-family: var(--font); background: var(--bg-primary); color: var(--text-primary);
            border: 0.5px solid var(--border-md); border-radius: var(--radius-md); }
.composer input[type="tel"]:focus { outline: 2px solid var(--accent); outline-offset: -2px; border-color: var(--accent); }
.composer button { flex-shrink: 0; }
.dial-status { width: 100%; margin-top: 8px; padding: 9px 12px; border-radius: var(--radius-md);
               font-size: 13px; background: var(--bg-info); color: var(--text-info);
               border-left: 3px solid var(--text-info); }
.dial-status.ringing { background: var(--accent-light); color: var(--accent); border-left-color: var(--accent); }
.dial-status.ok { background: var(--bg-success); color: var(--text-success); border-left-color: var(--text-success); }
.dial-status.err { background: var(--bg-danger); color: var(--text-danger); border-left-color: var(--text-danger); }

/* Search bar */
.search-bar { position: relative; padding: 10px 16px 4px; }
.search-bar input[type="search"] { width: 100%; padding: 9px 32px 9px 12px; font-size: 14px;
                                    font-family: var(--font); background: var(--bg-secondary);
                                    color: var(--text-primary); border: 0.5px solid var(--border-md);
                                    border-radius: var(--radius-md); }
.search-bar input[type="search"]:focus { outline: 2px solid var(--accent); outline-offset: -2px; border-color: var(--accent); }
.search-clear { position: absolute; right: 22px; top: 50%; transform: translateY(-30%);
                background: var(--text-tertiary); color: white; border: none; cursor: pointer;
                width: 20px; height: 20px; border-radius: 50%; font-size: 14px; line-height: 1;
                display: flex; align-items: center; justify-content: center; padding: 0; }
.search-clear:hover { background: var(--text-secondary); }

/* Filter chips */
.filter-bar { display: flex; gap: 6px; padding: 12px 16px 4px; flex-wrap: wrap; }
.filter-chip { padding: 5px 12px; font-size: 12px; border: 0.5px solid var(--border-md);
               border-radius: var(--radius-pill, 999px); background: var(--bg-primary);
               color: var(--text-secondary); cursor: pointer; transition: .15s; }
.filter-chip:hover { background: var(--bg-secondary); }
.filter-chip.active { background: var(--accent); color: white; border-color: var(--accent); }

/* Calls list */
.calls-list { padding: 0; }
.day-header { padding: 8px 16px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
              color: var(--text-tertiary); background: var(--bg-secondary);
              border-top: 0.5px solid var(--border); border-bottom: 0.5px solid var(--border); }
.call-item { display: flex; align-items: flex-start; gap: 10px; padding: 12px 16px;
             border-bottom: 0.5px solid var(--border); }
.call-icon { width: 32px; height: 32px; border-radius: 50%; display: flex;
             align-items: center; justify-content: center; font-size: 14px; flex-shrink: 0; }
.call-icon.in { background: var(--bg-success); color: var(--text-success); }
.call-icon.out { background: var(--bg-info); color: var(--text-info); }
.call-icon.missed { background: var(--bg-danger); color: var(--text-danger); }
.call-main { flex: 1; min-width: 0; }
.call-line { display: flex; align-items: center; gap: 8px; }
.call-tel { font-family: var(--font-mono); font-weight: 600; color: var(--accent); text-decoration: none; }
.call-tel:hover { text-decoration: underline; }
.call-time { margin-left: auto; font-size: 12px; color: var(--text-tertiary); font-family: var(--font-mono); }
.call-sub { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.call-subnum { font-size: 12px; color: var(--text-tertiary); font-family: var(--font-mono); margin-top: 1px; }
.sources { margin-top: 6px; padding-left: 0; display: flex; flex-direction: column; gap: 3px; }
.src-row { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-secondary); }
.src-row.src-alt { color: var(--text-secondary); padding-left: 0; }
.src-badge { display: inline-flex; align-items: center; gap: 4px; font-size: 10px; font-weight: 600; padding: 2px 6px;
             border-radius: 4px; border: 0.5px solid var(--border); }
.src-rep { background: var(--bg-info); color: var(--text-info); }
.badge-standard { font-size: 10px; padding: 2px 7px; background: var(--accent-light); color: var(--accent);
                  border-radius: 4px; font-weight: 500; }
.call-crm { margin-top: 4px; }
.crm-link { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 500;
            color: var(--accent); text-decoration: none; }
.crm-link:hover { text-decoration: underline; }
.crm-link .material-symbols-rounded { font-size: 14px; }
.crm-link-plain { color: var(--text-secondary); cursor: default; }

/* Standard tab */
.std-headers { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 16px;
               background: var(--bg-secondary); border-bottom: 0.5px solid var(--border); }
.std-card { display: flex; align-items: center; gap: 10px; padding: 8px 12px;
            background: var(--bg-primary); border: 0.5px solid var(--border-md);
            border-radius: var(--radius-md); flex: 1 1 240px; min-width: 200px; }
.std-avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--green-light);
              color: var(--green-dark, var(--green)); display: flex; align-items: center;
              justify-content: center; font-size: 14px; flex-shrink: 0; }
.std-badge { font-size: 10px; padding: 2px 7px; background: var(--green-light); color: var(--green);
             border-radius: 4px; font-weight: 500; }
.agents-row { display: flex; flex-wrap: wrap; gap: 5px; align-items: center;
              margin-top: 8px; font-size: 11px; }
.agents-label { color: var(--text-tertiary); }
.agents-empty { color: var(--text-tertiary); font-style: italic; }
/* Sépare deux personnes sonnées : la file les a appelées dans cet ordre.
   Purement décorative (aria-hidden), la suite des puces porte déjà le sens. */
.agents-fleche { color: var(--text-tertiary); flex-shrink: 0; opacity: 0.8; padding: 0 1px; }
/* Nombre de tours de la file, en sonnerie successive. */
.agents-tours { color: var(--text-tertiary); white-space: nowrap; font-style: italic; }
.chip { padding: 2px 9px; border-radius: 999px; font-size: 11px; font-weight: 500; }
.chip-missed { background: var(--bg-warning, var(--bg-danger)); color: var(--text-warning, var(--text-danger)); }
.chip-answered { background: var(--bg-success); color: var(--text-success); }
.callback-row { display: flex; align-items: center; gap: 5px; margin-top: 5px; font-size: 11px; }
.callback-yes { color: var(--text-success); }
.callback-no { color: var(--text-tertiary); }

.contacts-bar { display: flex; gap: 8px; margin-bottom: 12px; }
.contacts-bar input[type="search"] { flex: 1; padding: 8px 12px; font-size: 14px;
  background: var(--bg-secondary); color: var(--text-primary);
  border: 0.5px solid var(--border-md); border-radius: var(--radius-md); }
.c-row { display: flex; align-items: baseline; gap: 10px; width: 100%; text-align: left;
  padding: 10px 12px; background: transparent; border: none; border-bottom: 0.5px solid var(--border);
  cursor: pointer; color: var(--text-primary); }
.c-row:hover { background: var(--bg-secondary); }
.c-name { font-weight: 600; }
.c-company { color: var(--text-secondary); font-size: 13px; }
.c-count { margin-left: auto; font-size: 12px; color: var(--text-tertiary); }
#contactSheet .cs-meta { margin: 6px 0; font-size: 14px; color: var(--text-secondary); }
#contactSheet .cs-phone { display: flex; align-items: center; justify-content: space-between;
  padding: 8px 0; border-top: 0.5px solid var(--border); }
#contactSheet .cs-label { font-size: 11px; color: var(--text-tertiary); display: block; }
#contactSheet .cs-num { font-family: var(--font-mono); }
#contactSheet .cs-actions { display: flex; gap: 8px; margin-top: 12px; }
#contactSheet .cs-google { font-size: 12px; color: var(--text-tertiary); font-style: italic; }
.cf-phone-row { display: flex; gap: 6px; margin-bottom: 6px; }
.cf-phone-row .cf-phone-num { flex: 2; }
.cf-phone-row .cf-phone-label { flex: 1; }
.btn-danger { background: var(--red, #e24b4a); color: #fff; border: none; }
/* .rap-config n'appartient pas qu'au rappeleur : le sélecteur d'équipe de l'onglet
   Standard l'émet aussi (standard-tab.js), et public/m/styles.css la redéclare pour
   le mobile. Tout ce qui ne concerne QUE le rappeleur passe donc par #rapTeamBox /
   #rapConfig, plus bas, pour ne pas déplacer l'onglet Standard au passage. */
.rap-config { display: flex; flex-direction: column; gap: 8px; max-width: 420px; }
.rap-config label { font-weight: 500; }
.rap-config select { padding: 8px; border: 0.5px solid var(--border-md); border-radius: var(--radius-md); background: var(--bg-secondary); color: var(--text-primary); }
#secHistos #histoUser { padding: 8px; border: 0.5px solid var(--border-md); border-radius: var(--radius-md); margin-bottom: 12px; }

/* ── Serial rappeleur ───────────────────────────────────────────────────────
   Tous les styles de la section vivent ICI. Ils étaient auparavant partagés
   entre cette feuille et le <style> en ligne de index.html, chargé après elle :
   à spécificité égale l'inline gagnait, et une correction posée ici restait
   sans effet visible. Un seul domicile, plus de fausse vérification. */

/* Largeur : c'est celle à laquelle la ligne « Modèle » des outils (un menu et
   quatre boutons) tient enfin sur un seul rang. Pas davantage — au-delà, ce
   sont les vingt menus du planning qui s'étirent, et c'est justement le mur
   de rectangles identiques qu'on cherche à casser.
   Ciblé par ID et non par .rap-config, partagée avec l'onglet Standard. */
/* Le `gap` est posé ICI, par identifiant, et non laissé à .rap-config : cette
   classe est partagée avec le sélecteur d'équipe de l'onglet Standard et vit
   dans le <style> en ligne d'index.html, plus tôt dans la cascade et à
   spécificité égale — la copie déclarée dans ce fichier était donc morte, et le
   rythme vertical de toute la section continuait d'être commandé d'ailleurs. */
#rapTeamBox, #rapConfig { max-width: 760px; gap: 16px; }

/* Le choix d'équipe commande tout ce qui suit : un filet le pose en préambule,
   là où il touchait le choix de mode sans le moindre blanc. */
#rapTeamBox { gap: 6px; padding-bottom: 16px; margin-bottom: 16px;
              border-bottom: 0.5px solid var(--border); }
/* La marge globale des <label> (12px 0 6px) s'ajoutait au gap du conteneur :
   « Équipe » finissait à 22px de son menu, soit plus loin de son champ que du
   titre de section. L'appariement étiquette/contrôle doit être le lien le plus
   serré de l'écran, pas le plus lâche. */
#rapTeamBox > label, #rapManualBox > label { margin: 0; }
/* Même gabarit que #rapManual : deux menus de même nature ne peuvent pas faire
   l'un toute la colonne et l'autre 320px. */
#rapTeamBox select { max-width: 320px; padding: 9px 12px; font-size: 14px;
                     font-family: var(--font); border-radius: var(--radius-md); }

/* Manuel / Planifié : deux segments accolés, comme .recap-modes. C'est un CHOIX
   ENTRE DEUX, pas deux actions indépendantes — deux boîtes détachées laissaient
   croire qu'on pouvait les activer toutes les deux. Le <input> reste DANS le
   <label> : c'est lui que lit le :has() plus bas, et le JS coche par name. */
.rap-modes { display: inline-flex; align-self: flex-start;
             border: 0.5px solid var(--border-md); border-radius: var(--radius-md);
             overflow: hidden; }
.rap-modes label { display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
                   margin: 0; padding: 8px 14px; font-size: 13px;
                   color: var(--text-secondary); background: var(--bg-primary);
                   border: 0; border-right: 0.5px solid var(--border-md);
                   border-radius: 0; transition: background .15s, color .15s; }
.rap-modes label:last-child { border-right: 0; }
.rap-modes label:hover { background: var(--bg-secondary); color: var(--text-primary); }
/* Texte en --text-primary et non en --accent : sur --accent-light, --accent ne
   donne que 3,76:1 en thème sombre. L'aplat vert porte le signal, le texte
   reste lisible — même parti que .tr-preview et .cf-chip. */
.rap-modes label:has(input:checked) { background: var(--accent-light);
                                      color: var(--text-primary); font-weight: 600; }
/* Sans ça le radio garde l'accent bleu du navigateur : une pastille verte avec
   un point bleu au milieu, seule tache bleue d'une application entièrement verte. */
.rap-modes input[type="radio"] { accent-color: var(--accent); }

/* Garde écrite avant la règle globale [hidden] : le :not() est désormais
   redondant, il documente l'intention. */
#rapManualBox:not([hidden]) { display: flex; flex-direction: column; gap: 6px; }
#rapManualBox > label { font-size: 12px; color: var(--text-secondary); font-weight: 500; }

/* Bandeau « voici ce qui en résulte », même forme que .membres-total et .tr-note. */
.rap-effective { font-size: 13px; color: var(--text-secondary); background: var(--accent-light);
                 border-left: 3px solid var(--accent); border-radius: var(--radius-sm);
                 padding: 10px 14px; }
/* Le nom est ce qu'on vient vérifier : il ne peut pas être de la même couleur
   que son libellé. */
.rap-effective b { color: var(--text-primary); font-weight: 600; }
/* « Aucun rappeleur désigné » était peint dans la couleur d'accent positive,
   liséré vert compris : la couleur affirmait le contraire du texte. Variante
   neutre, comme .tr-elsewhere quand aucune règle ne s'applique. */
.rap-effective[data-vide] { background: var(--bg-secondary); border-left-color: var(--border-md); }

/* Seul rempart contre le width:100% de .btn-primary dans la colonne flex. */
#rapSave { align-self: flex-start; }
/* Le margin-top de .alert s'ajoutait au gap de 16px de la colonne : 28px de vide
   sous le bouton Enregistrer. Ciblé par ID, car showAlert() réécrit la className. */
#rapMsg { margin-top: 0; }

/* ── Rappeleur : outils du planning ─────────────────────────────────────────
   Copie de semaine et modèles, groupés par geste. Plus de fond ni de cadre :
   avec eux, le premier bloc que l'œil accrochait était une boîte de six boutons
   secondaires, pas le planning qui est le sujet de l'écran. Un simple filet
   suffit à dire « ceci agit sur ce qui suit ». */
.rap-outils { display: flex; flex-direction: column; gap: 10px;
              padding: 0 0 14px; margin-bottom: 16px;
              border-bottom: 0.5px solid var(--border); }
/* renderRapOutils() sort en early return tant que le planning n'est pas chargé :
   sans cette garde, un filet flotterait au-dessus d'une grille vide. */
.rap-outils:empty { display: none; }

/* Chaque ligne est une grille à deux colonnes : l'étiquette, puis ses contrôles.
   En flex, la ligne « Modèle » débordait et ses quatre boutons repartaient SOUS
   l'étiquette, cassant la colonne qu'on venait d'établir ; en grille, ils se
   replient dans leur colonne. La ligne « Copier » n'a pas d'étiquette : son bloc
   de contrôles rejoint la colonne 2 de lui-même, sans nœud de calage. */
.rap-outil { display: grid; grid-template-columns: 150px minmax(0, 1fr);
             gap: 8px 10px; align-items: center; }
.rap-outil label { font-size: 12px; color: var(--text-secondary); margin: 0; }
.rap-outil-champs { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rap-outil-champs:only-child { grid-column: 2; }
/* Même gabarit dense que les menus de la grille : quatre calibres de menu
   coexistaient dans un panneau de dix centimètres sans vouloir rien dire. */
.rap-outil select { padding: 6px 9px; font-family: var(--font); font-size: 13px;
                    border: 0.5px solid var(--border-md); border-radius: var(--radius-sm);
                    background: var(--bg-primary); color: var(--text-primary);
                    min-width: 170px; }
.rap-outil .btn { margin: 0; }
/* Ni margin-right ni vertical-align : .btn est en inline-flex, son `gap: 6px`
   fait déjà l'écart (la marge s'y ajoutait, portant l'icône à 11px de son
   libellé quand tous les autres boutons sont à 6) et son `align-items: center`
   fait déjà le calage que vertical-align prétendait faire sans effet. */
.rap-outil .btn .material-symbols-rounded { font-size: 16px; }
/* Un bouton neutralisé doit se lire comme tel : sans ça, on clique sur « Appliquer »
   sans modèle choisi et rien ne se passe, ce qui ressemble à une panne. Mais
   l'opacité globale de .45 effaçait aussi sa bordure et faisait tomber son texte
   à ~2,7:1 : quatre étiquettes grises flottantes à chaque ouverture de l'onglet.
   On éteint le texte, on garde la boîte.

   --text-tertiary ne suffisait pas non plus : 3,08:1 sur le fond de .btn-secondary,
   toujours sous le seuil, pour l'état par défaut de quatre boutons sur six. La
   paire est donc déclarée pour les deux thèmes (4,63:1 en clair, 4,54:1 en sombre).
   L'écart avec un libellé actif reste de 1 à 3 : « désactivé » se lit encore. */
.rap-outil .btn:disabled { opacity: 1; color: #6b6a64; cursor: not-allowed; }
/* « Supprimer » efface un modèle sans retour possible, et a exactement la forme de
   ses trois voisins. Un rouge au survol ralentit la main au moment où ça compte,
   sans ajouter de couleur criarde à un écran qu'on cherche à calmer. --red et
   --text-danger n'étant pas redéfinis en sombre, la paire est déclarée ici. */
.rap-outil #rapSupprimer:hover:not(:disabled) { color: #a32d2d; border-color: #a32d2d; }
/* L'alerte des outils appartient à la pile : le margin-top de .alert s'ajoutait
   au gap et ouvrait 22px de vide sous le dernier bouton. */
#rapOutils #rapTplMsg { margin-top: 0; }

/* ── Rappeleur : grille du planning ─────────────────────────────────────────
   La carte de semaine reprend l'encadré canonique de l'application (fond
   --bg-secondary, filet --border-md, rayon --radius-md, comme .team-card et
   .status-card) et ses jours deviennent des lignes de liste. Sans fond ni
   filets, les dix lignes des deux semaines se lisaient comme une seule liste
   continue, et en thème sombre les deux cadres s'évanouissaient. */
.rap-grid { display: flex; flex-direction: column; gap: 16px; margin-top: 0; }
.rap-week { background: var(--bg-secondary); border: 0.5px solid var(--border-md);
            border-radius: var(--radius-md); padding: 12px 6px 6px; }
.rap-week-head { display: flex; align-items: center; gap: 8px; padding: 0 8px;
                 font-size: 14px; font-weight: 600; letter-spacing: -0.01em;
                 font-variant-numeric: tabular-nums; margin-bottom: 10px; }
/* Les outils disent « S1 → S2 », le menu d'enregistrement dit « Semaine 1 », et
   les cartes ne disaient que « Semaine du 31 août » : trois nommages pour deux
   objets, juste avant une copie qui ÉCRASE intégralement la semaine cible. La
   pastille ferme l'écart.

   Recette de .audit-tag, à une exception près : .audit-tag vit sur --bg-primary,
   où son fond --bg-tertiary marque un vrai pas de gris. Ici la pastille est posée
   sur la carte, déjà en --bg-secondary — le pas était divisé par deux et il ne
   restait qu'un mot gris entouré de blanc. On la pose donc sur le niveau qui
   TRANCHE avec son support, et un filet lui rend sa silhouette dans les deux
   thèmes (3,3:1 en clair, 4,3:1 en sombre). */
.rap-week-num { font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
                padding: 2px 8px; border-radius: var(--radius-pill, 999px);
                background: var(--bg-primary); border: 0.5px solid var(--border-md);
                color: var(--text-secondary); }

/* L'en-tête de colonnes et les lignes jour partagent UNE seule déclaration de
   grille : c'est tout ce qui les aligne, il n'y a ni tableau ni subgrid. Le
   retrait horizontal est donc posé ici, sur les deux à la fois, pour que la
   ligne du jour puisse recevoir un fond sans se décaler d'un cran.
   minmax(0, 1fr) et non 1fr : un <select> a une largeur intrinsèque, et un nom
   composé long ferait déborder la carte au lieu de comprimer la piste. */
.rap-grid-head, .rap-day { display: grid;
                           grid-template-columns: 76px minmax(0, 1fr) minmax(0, 1fr);
                           gap: 10px; align-items: center;
                           padding-left: 8px; padding-right: 8px; }
/* Recette maison des étiquettes de colonnes (.membres-head, .admin-table thead th) :
   11px, capitales, interlettrage 0.04em, 600, et un filet sous la ligne. En
   --text-secondary et non --text-tertiary : ce dernier ne donne que 3,6:1 sur
   fond clair, sous le seuil AA, sur les seuls mots qui expliquent les colonnes. */
.rap-grid-head { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
                 font-weight: 600; color: var(--text-secondary);
                 padding-bottom: 7px; margin-bottom: 2px;
                 border-bottom: 0.5px solid var(--border); }
.rap-day { padding-top: 7px; padding-bottom: 7px;
           border-bottom: 0.5px solid var(--border); transition: background .12s; }
.rap-day:last-child { border-bottom: none; }
/* Une ligne de liste maison réagit au survol (.call-item, .sim-row, .tr-row…) :
   sur vingt cases à pointer, c'est le repère qui manquait. Le rayon n'est posé
   QUE sur les lignes qui reçoivent un fond, comme .tr-row-live : sur la ligne
   nue il recourberait les extrémités du filet séparateur. */
.rap-day:not(.past):hover { background: var(--bg-tertiary);
                            border-radius: var(--radius-sm); }
.rap-day-label { font-size: 12px; color: var(--text-secondary);
                 font-variant-numeric: tabular-nums; }
/* Le quantième porte l'information, le nom du jour l'accompagne : même partage
   qu'en tête de colonne des règles horaires (.tr-colhead / .tr-colhead b). */
.rap-day-label b { font-weight: 600; color: var(--text-primary); }
/* Le menu remonte à --bg-primary : posé sur l'encadré --bg-secondary de la carte,
   il se serait fondu dans son propre fond. Deux surfaces adjacentes ne portent
   jamais le même niveau. */
.rap-day select { padding: 6px 9px; font-size: 13px; font-family: var(--font);
                  background: var(--bg-primary); color: var(--text-primary);
                  border: 0.5px solid var(--border-md); border-radius: var(--radius-sm);
                  transition: border-color .15s, background .15s; }
.rap-day select:hover:not(:disabled) { border-color: var(--accent); }

/* Le créneau du jour, marqué comme toutes les lignes vives de l'application
   (.tr-row-live, .redir-row.active) : un aplat d'accent, jamais une bordure —
   une bordure de plus décalerait cette ligne de ses en-têtes de colonnes.

   L'aplat seul ne suffisait pas : --accent-light ne pèse que 1,05:1 sur la carte
   en clair et 1,10:1 en sombre. Là où la recette est reprise (.tr-row-live), le
   fond est DOUBLÉ d'une pastille « EN DIRECT » ; ici le badge a été écarté, donc
   l'aplat portait seul une information qu'on ne voyait pas. Le liseré d'accent
   la porte vraiment (4,62:1 en clair, 4,13:1 en sombre), et en `inset` plutôt
   qu'en bordure pour ne pas décaler la ligne d'un cran. */
.rap-day.aujourdhui { background: var(--accent-light); border-radius: var(--radius-sm);
                      box-shadow: inset 2px 0 0 0 var(--accent); }

/* Un jour passé n'est plus modifiable, mais il reste à lire : c'est la seule
   chose que ces lignes ont encore à dire. On éteint le contrôle, pas la ligne.
   L'opacité globale de 0.5 traînait le libellé du jour sous 2:1 — un vendredi
   après-midi, la carte la plus importante était la plus morte.

   Le créneau passé RETOMBE AU NIVEAU DE LA CARTE et perd son filet, au lieu de
   descendre d'un cran sur l'échelle des gris. Un niveau de surface ne dit pas la
   même chose dans les deux thèmes : --bg-tertiary est plus SOMBRE que --bg-primary
   en clair (le contrôle recule) mais plus CLAIR en sombre (il avance), et la
   semaine verrouillée devenait la plus lumineuse de l'écran. Se fondre dans son
   propre parent, en revanche, se lit « en retrait » partout — c'est une relation,
   pas une valeur.

   -webkit-text-fill-color en plus de color : Blink et WebKit repeignent le texte
   d'un <select disabled> avec leur propre gris, et `color` seul ne reprend pas
   la main — sans cette ligne la correction resterait lettre morte. */
.rap-day.past select { background: var(--bg-secondary); color: var(--text-secondary);
                       -webkit-text-fill-color: var(--text-secondary);
                       border-color: transparent; opacity: 1; }
.rap-day.past .rap-day-label b { color: var(--text-secondary); font-weight: 500; }

/* La question que l'écran doit trancher est « où manque-t-il quelqu'un ? », et
   « — Personne — » s'affichait exactement comme un nom. La case vide se CREUSE
   dans la carte (elle redescend au fond de son parent) au lieu d'être écrite en
   gris pâle : un trou se voit à la silhouette, sans lire les vingt libellés.
   Écartée des jours passés, qui gardent leur propre traitement.

   Le filet devient tireté : c'est LUI qui sépare « à remplir » de « verrouillé »,
   maintenant que les deux reposent au niveau de la carte. Les distinguer par un
   demi-ton de gris ne tenait pas — 1,07:1 en clair — et s'inversait en sombre. */
.rap-day:not(.past) select:has(option[value=""]:checked) {
  background: var(--bg-secondary); color: var(--text-secondary);
  border-style: dashed; font-style: italic; font-weight: 400;
}

/* Vingt menus se remplissent à la suite au clavier : c'est l'écran où l'on tabule
   le plus, et celui où l'on voyait le moins où l'on se trouvait — l'anneau par
   défaut du navigateur se posait par-dessus des bordures de 0,5px. */
.rap-day select:focus-visible, .rap-outil select:focus-visible,
.rap-outil .btn:focus-visible, #rapTeamBox select:focus-visible,
#rapManual:focus-visible, #rapSave:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
/* Les segments de mode, eux, prennent l'anneau EN DEDANS : .rap-modes est en
   overflow:hidden pour accoler ses deux moitiés, et un anneau débordant y serait
   rogné — donc invisible exactement là où le clavier en a besoin. */
.rap-modes label:has(input:focus-visible) {
  outline: 2px solid var(--accent); outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  .rap-modes label, .rap-day, .rap-day select { transition: none; }
}

/* Les jetons rouges de la palette ne sont pas redéclinés en sombre : #a32d2d y
   tomberait à 2,2:1. Valeur choisie POUR le fond sombre, pas recopiée du clair. */
@media (prefers-color-scheme: dark) {
  .rap-outil #rapSupprimer:hover:not(:disabled) { color: #e9736c; border-color: #e9736c; }
  /* Même raison pour le gris du bouton neutralisé : #6b6a64 est choisi pour les
     fonds clairs et tomberait à 2,4:1 sur --bg-tertiary sombre. */
  .rap-outil .btn:disabled { color: #94938c; }
}

/* ===== Onglets desktop : panneaux aérés (cohérent avec l'admin) ===== */
#tab-calls.active, #tab-standard.active, #tab-contacts.active, #tab-redirections.active {
  display: flex; flex-direction: column; gap: 14px;
  background: var(--bg-secondary); padding: 20px;
}
.composer {
  background: var(--bg-primary); border: 0.5px solid var(--border-md);
  border-radius: var(--radius-lg); box-shadow: 0 1px 2px rgba(0,0,0,0.04);
  padding: 14px 16px; gap: 10px; margin: 0;
}
.search-bar { padding: 0; }
.search-bar input[type="search"] { background: var(--bg-primary); }
.filter-bar { padding: 0; gap: 8px; }
.calls-list {
  background: var(--bg-primary); border: 0.5px solid var(--border-md);
  border-radius: var(--radius-lg); box-shadow: 0 1px 2px rgba(0,0,0,0.04);
  overflow: hidden; padding: 0;
}
.day-header {
  background: transparent; border: none; border-bottom: 0.5px solid var(--border);
  padding: 12px 16px 6px; color: var(--text-tertiary);
}
.call-item { padding: 13px 16px; border-bottom: 0.5px solid var(--border); transition: background .12s; }
.call-item:last-child { border-bottom: none; }
.call-item:hover { background: var(--bg-secondary); }
.contacts-bar { margin: 0; gap: 10px; }
.contacts-bar input[type="search"] { background: var(--bg-primary); }
#cList {
  background: var(--bg-primary); border: 0.5px solid var(--border-md);
  border-radius: var(--radius-lg); box-shadow: 0 1px 2px rgba(0,0,0,0.04); overflow: hidden;
}
.c-row { padding: 13px 16px; border-bottom: 0.5px solid var(--border); }
.c-row:last-child { border-bottom: none; }
.c-row:hover { background: var(--bg-secondary); }
.std-headers { padding: 0; margin: 0; background: transparent; border: none; }
.c-row { align-items: center; }
.c-avatar { width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0; display: flex;
            align-items: center; justify-content: center; color: #fff; font-size: 14px; font-weight: 600; }
.call-icon .material-symbols-rounded { font-size: 19px; }
.std-avatar .material-symbols-rounded { font-size: 18px; }
.agents-label .material-symbols-rounded { font-size: 14px; vertical-align: -2px; }
.callback-row .material-symbols-rounded { font-size: 14px; vertical-align: -2px; }
.btn .material-symbols-rounded { font-size: 18px; }

/* ── Onglet Redirections ── */
.redir-head { font-size: 13px; color: var(--text-secondary); margin-bottom: 2px; }
.redir-refreshing { font-style: italic; opacity: 0.7; }
.redir-list { background: var(--bg-primary); border: 0.5px solid var(--border-md);
              border-radius: var(--radius-lg); box-shadow: 0 1px 2px rgba(0,0,0,0.04);
              overflow: hidden; max-width: 720px; }
.redir-row { display: flex; align-items: center; gap: 12px; padding: 13px 16px;
             border-bottom: 0.5px solid var(--border); }
.redir-row:last-child { border-bottom: none; }
.redir-row.active { background: var(--accent-light); }
.redir-row-ico { font-size: 22px; color: var(--text-tertiary); flex-shrink: 0; }
.redir-row.active .redir-row-ico { color: var(--accent); }
.redir-row-text { flex: 1; min-width: 0; }
.redir-row-name { font-size: 14px; font-weight: 600; }
.redir-row-sub { font-size: 12px; color: var(--text-secondary); }
/* Pastille pleine, comme les autres du projet (.chip, .audit-tag). Sans padding ni
   rayon, le fond clair formait un rectangle à angles vifs collé au texte — ce qui,
   sur fond sombre, se lisait comme une bordure. */
.redir-badge { flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px;
               padding: 4px 11px; border-radius: var(--radius-pill, 999px);
               font-size: 11px; font-weight: 600; white-space: nowrap;
               background: var(--bg-success); color: var(--text-success); }
.redir-row .btn { flex-shrink: 0; margin: 0; width: auto; }
.redir-status { margin-top: 8px; font-size: 13px; color: var(--text-secondary); }
.redir-status.err { color: var(--red); font-weight: 600; }

/* ── Bascule en cours : mise en avant du profil ciblé, autres estompés ── */
.redir-list.busy .redir-row:not(.switching) { opacity: 0.4; transition: opacity .2s; }
.redir-row.switching { background: var(--accent-light); }
.redir-activate.is-loading { opacity: 1; display: inline-flex; align-items: center; gap: 6px; }

/* Bannière + barre de progression indéterminée (retour visuel soutenu) */
.redir-banner { display: flex; align-items: center; gap: 10px; padding: 11px 14px;
                border-radius: var(--radius-md); background: var(--accent-light);
                color: var(--accent); font-weight: 600; font-size: 13px; }
.redir-progress { height: 4px; margin-top: 6px; border-radius: 2px;
                  background: var(--accent-light); overflow: hidden; }
.redir-progress::before { content: ''; display: block; height: 100%; width: 35%; border-radius: 2px;
                  background: var(--accent); animation: redir-slide 1.05s ease-in-out infinite; }
@keyframes redir-slide { from { transform: translateX(-120%); } to { transform: translateX(400%); } }

/* Confirmation brève après succès */
.redir-ok { margin-top: 8px; font-size: 13px; font-weight: 600; color: var(--accent);
            animation: redir-ok 2.2s ease forwards; }
@keyframes redir-ok { 0% { opacity: 0; transform: translateY(-4px); } 12% { opacity: 1; transform: none; }
                      78% { opacity: 1; } 100% { opacity: 0; transform: translateY(-2px); } }

.redir-spin { width: 13px; height: 13px; border: 2px solid currentColor; border-top-color: transparent;
              border-radius: 50%; display: inline-block; animation: redir-spin .7s linear infinite; }
@keyframes redir-spin { to { transform: rotate(360deg); } }

/* Redirections admin (provisionnement des profils de renvoi) */
.redir-admin-hint { color: var(--muted, #667); font-size: .9rem; margin: 0 0 .6rem; }
.redir-admin-teams { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: .6rem; }
.redir-admin-report { font-size: .9rem; padding: .5rem .7rem; border-radius: 8px; background: rgba(0,0,0,.05); margin-bottom: .8rem; }
.redir-admin-report.ok { background: rgba(40,167,69,.12); }
.redir-admin-report.err { background: rgba(220,53,69,.12); }
.redir-admin-person { border-top: 1px solid rgba(0,0,0,.08); padding-top: .8rem; }
.redir-admin-person h4 { margin: 0 0 .5rem; font-size: .95rem; }
.redir-add-target { margin-top: .5rem; }
.redir-others { margin-top: .6rem; opacity: .75; }
.redir-others-head { font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted, #667); margin-bottom: .3rem; }
.redir-person-actions { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin: .5rem 0 .6rem; }
.redir-person-msg { font-size: .85rem; color: var(--muted, #667); }
.redir-person-msg.ok { color: #2e7d32; }
.redir-person-msg.err { color: #c62828; }
.team-member .tm-line { font-family: var(--font-mono); font-size: 12px; color: var(--text-tertiary); margin-left: auto; margin-right: 8px; }
.team-hint { font-size: 11px; color: var(--text-tertiary); margin-top: 6px; font-style: italic; }
/* Fiche utilisateur déplaçable : on la pousse de côté pour lire la page derrière. */
.modal-header.draggable-header { cursor: move; user-select: none; touch-action: none; }
/* Fond volontairement très léger sur cette modale : elle est faite pour être consultée
   EN MÊME TEMPS que le tableau derrière (showModal() assombrit et fige le reste). */
#userModal::backdrop { background: rgba(0,0,0,0.12); }

/* ── Écran de revue du dry-run (Redirections Admin) ── */
.redir-plan { border: 0.5px solid var(--border-md); border-radius: var(--radius-md); margin-top: .6rem; overflow: hidden; }
.rp-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: .6rem;
           padding: .6rem .8rem; background: var(--bg-secondary); border-bottom: 0.5px solid var(--border); }
.rp-totaux { font-size: .82rem; color: var(--text-secondary); }
.rp-all { display: flex; align-items: center; gap: .5rem; padding: .5rem .8rem;
          border-bottom: 0.5px solid var(--border); font-size: .88rem; cursor: pointer; }
.rp-users { max-height: 52vh; overflow-y: auto; }
.rp-user { border-bottom: 0.5px solid var(--border); }
.rp-user.rp-nothing { opacity: .55; }
.rp-user-head { display: flex; align-items: center; gap: .5rem; padding: .5rem .8rem; cursor: pointer; }
.rp-user-head:hover { background: var(--bg-secondary); }
.rp-name { font-weight: 600; font-size: .9rem; }
.rp-label { font-size: .8rem; color: var(--text-secondary); }
.rp-badges { margin-left: auto; display: flex; gap: .3rem; flex-wrap: wrap; }
.rp-b { font-size: .72rem; padding: .1rem .4rem; border-radius: 999px; background: var(--bg-tertiary); color: var(--text-secondary); }
.rp-b.rp-create { background: rgba(40,167,69,.18); color: #2e7d32; }
.rp-b.rp-rename { background: rgba(255,171,0,.18); color: #b06000; }
.rp-b.rp-delete { background: rgba(220,53,69,.18); color: #c62828; }
.rp-items { list-style: none; margin: 0; padding: 0 .8rem .5rem 2.1rem; }
.rp-item { display: flex; align-items: baseline; gap: .45rem; font-size: .82rem; padding: .12rem 0; }
.rp-sym { width: 1em; flex-shrink: 0; font-weight: 700; }
.rp-main { flex: 1; min-width: 0; word-break: break-word; }
.rp-sub { color: var(--text-tertiary); font-size: .76rem; white-space: nowrap; }
.rp-item.rp-create .rp-sym { color: #2e7d32; }
.rp-item.rp-rename .rp-sym { color: #b06000; }
.rp-item.rp-delete .rp-sym { color: #c62828; }
.rp-item.rp-keep { color: var(--text-tertiary); }
.rp-footer { display: flex; align-items: center; gap: .6rem; padding: .6rem .8rem;
             background: var(--bg-secondary); border-top: 0.5px solid var(--border); }
.rp-count { margin-right: auto; font-size: .85rem; color: var(--text-secondary); }
.rp-warn { margin: 0 .8rem .3rem 2.1rem; padding: .3rem .5rem; border-radius: 6px; font-size: .78rem;
           background: rgba(220,53,69,.10); color: #c62828; border-left: 3px solid #c62828; }
/* Profil en cours d'utilisation : jamais supprimé, mis en évidence dans la revue. */
.rp-item.rp-active { color: var(--text-primary); font-weight: 500; }
.rp-item.rp-active .rp-sym { color: #2e7d32; }
.rp-item.rp-active .rp-sub { color: #2e7d32; font-weight: 600; }

/* ── Onglet Simulation (admin) ─────────────────────────────────────────── */
.sim-hint { font-size: 13px; color: var(--text-secondary); line-height: 1.55; margin: 0 0 16px; }
.sim-form { display: flex; gap: 10px; align-items: center; }
.sim-form input { flex: 0 1 240px; padding: 9px 12px; font-size: 14px; font-family: var(--font);
                  border: 0.5px solid var(--border-md); border-radius: var(--radius-md);
                  background: var(--bg-primary); color: var(--text-primary); }
.sim-form .btn-primary { width: auto; margin-top: 0; }
/* Ambre : ni succès ni erreur — un appel fabriqué, qu'on doit repérer d'un coup d'œil. */
.sim-badge { display: inline-flex; align-items: center; margin-left: 8px; padding: 1px 7px; border-radius: 999px;
             font-size: 10px; font-weight: 700; letter-spacing: 0.06em; white-space: nowrap;
             background: rgba(176, 96, 0, 0.14); color: #b06000; }
@media (prefers-color-scheme: dark) { .sim-badge { background: rgba(255, 167, 38, 0.18); color: #ffa726; } }
.sim-active { margin-top: 18px; padding: 14px 16px; border-radius: var(--radius-md);
              border: 0.5px solid var(--border-md); background: var(--bg-secondary); }
.sim-active-num { font-size: 17px; font-weight: 600; display: flex; align-items: center; }
.sim-active-state { font-size: 12px; color: var(--text-secondary); margin-top: 3px; }
.sim-actions { display: flex; gap: 8px; margin-top: 12px; }
.sim-actions .btn { margin-top: 0; width: auto; }
.sim-history-head { margin-top: 26px; }
.sim-row { display: flex; align-items: flex-start; gap: 12px; padding: 11px 2px;
           border-bottom: 0.5px solid var(--border); }
.sim-row:last-child { border-bottom: none; }
.sim-row-main { flex: 1; min-width: 0; }
.sim-row-num { font-size: 14px; font-weight: 500; display: flex; align-items: center; }
.sim-row-sub { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.sim-row-time { font-size: 12px; color: var(--text-tertiary); white-space: nowrap; }
.sim-row .crm-link { margin-top: 4px; }

/* ── Onglet Fiche appelant (admin) ─────────────────────────────────────── */
.cf-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.cf-toolbar input[type="search"] { flex: 0 1 280px; padding: 9px 12px; font-size: 14px;
  font-family: var(--font); background: var(--bg-primary); color: var(--text-primary);
  border: 0.5px solid var(--border-md); border-radius: var(--radius-md); }
.cf-count { font-size: 12px; color: var(--text-secondary); margin-right: auto; }
.cf-selected { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 10px 0 4px; }
.cf-selected-label { font-size: 12px; color: var(--text-secondary); margin-right: 4px; }
.cf-chip { background: var(--accent-light); color: var(--text-primary); }
.cf-group { margin-top: 20px; }
.cf-group h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
               color: var(--text-tertiary); margin-bottom: 8px; }
.cf-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 6px; }
.cf-item { display: flex; align-items: center; gap: 9px; margin: 0; padding: 9px 11px;
           border: 0.5px solid var(--border); border-radius: var(--radius-md);
           font-size: 13px; color: var(--text-primary); cursor: pointer; }
.cf-item:hover { background: var(--bg-secondary); }
.cf-item.on { border-color: var(--accent); background: var(--accent-light); }
.cf-item input { width: 16px; height: 16px; accent-color: var(--accent); flex: 0 0 auto; cursor: pointer; }
.cf-label { flex: 1; min-width: 0; }
.cf-col { font-family: var(--font-mono); font-size: 10px; color: var(--text-tertiary); }

/* ── Onglet Audit (admin) ──────────────────────────────────────────────── */
.audit-summary { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 18px; }
.audit-stat { flex: 1 1 150px; padding: 12px 14px; border-radius: var(--radius-md);
              border: 0.5px solid var(--border); background: var(--bg-secondary);
              font-size: 12px; color: var(--text-secondary); }
.audit-num { display: block; font-size: 22px; font-weight: 600; color: var(--text-primary);
             font-variant-numeric: tabular-nums; margin-bottom: 2px; }
/* Un refus n'est pas une erreur du système : c'est un signal à regarder. */
.audit-stat.alarm { border-color: #b06000; }
.audit-stat.alarm .audit-num { color: #b06000; }

.audit-ok { display: flex; align-items: center; gap: 8px; padding: 11px 14px;
            border-radius: var(--radius-md); background: var(--bg-success);
            color: var(--text-success); font-size: 13px; margin-bottom: 18px; }
.audit-ok .material-symbols-rounded { font-size: 19px; }
.audit-alert { border: 1px solid #b06000; border-radius: var(--radius-md);
               padding: 14px 16px; margin-bottom: 18px; background: rgba(176, 96, 0, 0.06); }
.audit-alert-head { display: flex; align-items: center; gap: 8px; font-size: 13px;
                    font-weight: 600; color: #b06000; margin-bottom: 12px; }
.audit-alert-head .material-symbols-rounded { font-size: 20px; }
.audit-note { font-size: 11.5px; color: var(--text-tertiary); margin-top: 10px; line-height: 1.5; }
.audit-h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
            color: var(--text-tertiary); margin: 22px 0 8px; }
.audit-phone { font-family: var(--font-mono); }
.audit-bad { color: #b06000; font-weight: 600; }
.audit-row-bad td { background: rgba(176, 96, 0, 0.06); }
.audit-tag { font-size: 11px; font-weight: 500; padding: 1px 8px; border-radius: 999px;
             background: var(--bg-tertiary); color: var(--text-secondary); }
.audit-tag.ok { background: var(--bg-success); color: var(--text-success); }
.audit-tag.bad { background: rgba(176, 96, 0, 0.14); color: #b06000; }
#auditDays { padding: 6px 10px; font-size: 13px; font-family: var(--font);
             background: var(--bg-primary); color: var(--text-primary);
             border: 0.5px solid var(--border-md); border-radius: var(--radius-md); }
@media (prefers-color-scheme: dark) {
  .audit-stat.alarm { border-color: #ffa726; }
  .audit-stat.alarm .audit-num, .audit-alert-head, .audit-bad { color: #ffa726; }
  .audit-alert { border-color: #ffa726; background: rgba(255, 167, 38, 0.07); }
  .audit-row-bad td { background: rgba(255, 167, 38, 0.07); }
  .audit-tag.bad { background: rgba(255, 167, 38, 0.18); color: #ffa726; }
}

/* ── Règles horaires ───────────────────────────────────────────────────── */

/* Palette catégorielle. Le mode sombre a ses PROPRES pas, pas une inversion :
   les huit teintes ont été validées séparément contre chaque surface (bande de
   clarté, plancher de chroma, séparation daltonisme), et l'encre posée dessus
   atteint au moins 4,76:1 dans les seize combinaisons. Ne pas retoucher une
   teinte isolément — c'est l'ensemble qui passe les seuils. */
:root {
  --tr-0: #8a8a84; --tr-0-ink: #000;
  --tr-1: #2a78d6; --tr-1-ink: #000;
  --tr-2: #eb6834; --tr-2-ink: #000;
  --tr-3: #1baf7a; --tr-3-ink: #000;
  --tr-4: #eda100; --tr-4-ink: #000;
  --tr-5: #e87ba4; --tr-5-ink: #000;
  --tr-6: #008300; --tr-6-ink: #fff;
  --tr-7: #4a3aa7; --tr-7-ink: #fff;
  --tr-8: #e34948; --tr-8-ink: #000;
}
@media (prefers-color-scheme: dark) {
  :root {
    --tr-0: #7e7e78; --tr-0-ink: #000;
    --tr-1: #3987e5; --tr-1-ink: #000;
    --tr-2: #d95926; --tr-2-ink: #000;
    --tr-3: #199e70; --tr-3-ink: #000;
    --tr-4: #c98500; --tr-4-ink: #000;
    --tr-5: #d55181; --tr-5-ink: #000;
    --tr-6: #008300; --tr-6-ink: #fff;
    --tr-7: #9085e9; --tr-7-ink: #000;
    --tr-8: #e66767; --tr-8-ink: #000;
  }
}
.tr-c0 { --tr-fill: var(--tr-0); --tr-ink: var(--tr-0-ink); }
.tr-c1 { --tr-fill: var(--tr-1); --tr-ink: var(--tr-1-ink); }
.tr-c2 { --tr-fill: var(--tr-2); --tr-ink: var(--tr-2-ink); }
.tr-c3 { --tr-fill: var(--tr-3); --tr-ink: var(--tr-3-ink); }
.tr-c4 { --tr-fill: var(--tr-4); --tr-ink: var(--tr-4-ink); }
.tr-c5 { --tr-fill: var(--tr-5); --tr-ink: var(--tr-5-ink); }
.tr-c6 { --tr-fill: var(--tr-6); --tr-ink: var(--tr-6-ink); }
.tr-c7 { --tr-fill: var(--tr-7); --tr-ink: var(--tr-7-ink); }
.tr-c8 { --tr-fill: var(--tr-8); --tr-ink: var(--tr-8-ink); }

/* En-tête et navigation */
.tr-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 12px; }
.tr-navgroup { display: flex; gap: 4px; }
.tr-title { min-width: 190px; }
.tr-title strong { display: block; font-size: 15px; font-weight: 600; }
.tr-sub { font-size: 11.5px; color: var(--text-secondary); }
.tr-nav { display: inline-flex; align-items: center; justify-content: center;
          min-width: 36px; min-height: 36px; padding: 0 10px;
          background: var(--bg-tertiary); border: 0.5px solid var(--border-md);
          border-radius: var(--radius-sm); cursor: pointer;
          font-family: var(--font); font-size: 12.5px; font-weight: 500;
          color: var(--text-primary); transition: background .15s ease; }
.tr-nav:hover { background: var(--bg-secondary); }
.tr-nav:active { background: var(--border); }
.tr-add { margin-left: auto !important; }

/* Légende — l'identité ne repose jamais sur la seule couleur : elle est ici,
   dans l'étiquette de chaque bande, et dans la liste sous la grille. */
.tr-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-bottom: 10px;
             font-size: 12px; color: var(--text-secondary); }
.tr-key { display: inline-flex; align-items: center; gap: 6px; }
.tr-chip { width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto;
           background: var(--tr-fill, var(--tr-0));
           box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, .18); }

/* Grille */
.tr-grid { display: grid; grid-template-columns: 46px repeat(7, minmax(0, 1fr)); gap: 3px;
           border: 0.5px solid var(--border); border-radius: var(--radius-md);
           padding: 8px; background: var(--bg-secondary); }
.tr-grid:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tr-hours { padding-top: 32px; }
.tr-hour { height: 22px; font-size: 10.5px; color: var(--text-tertiary); text-align: right;
           padding-right: 7px; font-variant-numeric: tabular-nums; position: relative; }
.tr-hour span { position: relative; top: -6px; }
/* Une graduation sur quatre est plus marquée : repérer 06:00 ou 18:00 d'un
   coup d'œil sans compter les lignes. */
.tr-hour:nth-child(6n + 1) { color: var(--text-secondary); font-weight: 600; }

.tr-colhead { text-align: center; font-size: 10.5px; color: var(--text-secondary);
              height: 32px; text-transform: uppercase; letter-spacing: .04em; }
.tr-colhead b { display: block; font-size: 15px; font-weight: 600;
                color: var(--text-primary); letter-spacing: 0;
                font-variant-numeric: tabular-nums; }
.tr-col-today .tr-colhead { color: var(--accent); }
.tr-col-today .tr-colhead b { color: var(--accent); }

.tr-slots { position: relative; height: 528px; background: var(--bg-tertiary);
            border-radius: var(--radius-sm); overflow: hidden;
            /* Une ligne par heure, plus marquée toutes les six. */
            background-image:
              repeating-linear-gradient(to bottom, var(--border) 0 1px, transparent 1px 22px),
              repeating-linear-gradient(to bottom, var(--border-md) 0 1px, transparent 1px 132px); }
.tr-col-today .tr-slots { box-shadow: inset 0 0 0 1.5px var(--accent); }

/* Bandes */
.tr-band { position: absolute; padding: 3px 5px; border: none; cursor: pointer;
           display: flex; flex-direction: column; gap: 1px; overflow: hidden;
           text-align: left; font-family: var(--font);
           border-radius: 4px; background: var(--tr-fill); color: var(--tr-ink);
           /* L'anneau de surface sépare deux bandes voisines sans dépendre
              d'un écart de teinte. */
           box-shadow: 0 0 0 1.5px var(--bg-tertiary);
           transition: filter .15s ease; }
.tr-band:hover { filter: brightness(1.08); }
.tr-band:focus-visible { outline: 2px solid var(--text-primary); outline-offset: 1px; z-index: 2; }
.tr-band-nom { font-size: 11px; font-weight: 600; line-height: 1.2;
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tr-band-h { font-size: 10px; line-height: 1.2; opacity: .85;
             font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Bande trop courte pour deux lignes : l'heure s'efface, l'infobulle et la
   liste la portent toujours. */
.tr-band { container-type: size; }
@container (max-height: 34px) { .tr-band-h { display: none; } }
@container (max-height: 17px) { .tr-band-nom { display: none; } }

/* Bande recouverte par une règle plus prioritaire : hachurée, pas cachée.
   La texture est un second canal, indépendant de la teinte — elle reste lisible
   en daltonisme, en impression et en contrastes forcés. */
.tr-mask { position: absolute; left: 0; right: 0; pointer-events: none;
  background: repeating-linear-gradient(135deg,
    transparent 0 5px, var(--tr-ink) 5px 6px);
  opacity: .4; }
/* Recouverte sur toute sa durée : elle ne s'applique jamais, on le dit aussi
   par le texte — la hachure seule est un signal graphique, pas un mot. */
.tr-band-under { opacity: .78; }
.tr-band-under .tr-band-nom { text-decoration: line-through;
                              text-decoration-thickness: 1px; }

.tr-note { margin-top: 10px; font-size: 12px; line-height: 1.5;
           color: var(--text-secondary); padding: 9px 12px;
           background: var(--bg-secondary); border-radius: var(--radius-sm);
           border-left: 3px solid var(--accent); }
.tr-note b { color: var(--text-primary); font-weight: 600; }

/* Repère de l'heure courante */
.tr-now { position: absolute; left: 0; right: 0; height: 2px;
          background: var(--text-danger); pointer-events: none; z-index: 3; }
.tr-now::before { content: ''; position: absolute; left: -1px; top: -3px;
                  width: 8px; height: 8px; border-radius: 50%; background: var(--text-danger); }

/* Ruban des règles hors semaine */
.tr-elsewhere { margin-top: 10px; font-size: 12px; color: var(--text-secondary);
                padding: 9px 12px; background: var(--bg-secondary);
                border-radius: var(--radius-sm); border-left: 3px solid var(--border-md);
                display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: baseline; }
.tr-elsewhere b { color: var(--text-primary); font-size: 12px; font-weight: 600; }

/* Liste des règles */
.tr-list { margin-top: 16px; }
.tr-row { display: flex; align-items: center; gap: 10px; padding: 10px 4px;
          border-bottom: 0.5px solid var(--border); font-size: 13px; }
.tr-row:last-child { border-bottom: none; }
.tr-row-live { background: var(--accent-light); border-radius: var(--radius-sm);
               padding-left: 8px; padding-right: 8px; }
/* Réordonnancement : l'ordre de la liste EST la priorité chez Keyyo. */
.tr-row[draggable] { cursor: grab; }
.tr-row-drag { opacity: .45; cursor: grabbing; }
/* Le trait marque le bord où la règle viendra se poser. */
.tr-row-over-haut { box-shadow: inset 0 2px 0 0 var(--accent); }
.tr-row-over-bas { box-shadow: inset 0 -2px 0 0 var(--accent); }
.tr-grip { flex: 0 0 auto; display: inline-flex; color: var(--text-tertiary); }
.tr-move { flex: 0 0 auto; display: inline-flex; gap: 2px; }
.tr-up, .tr-down { display: inline-flex; align-items: center; justify-content: center;
                   width: 28px; height: 28px; padding: 0; cursor: pointer;
                   background: none; border: none; border-radius: var(--radius-sm);
                   color: var(--text-secondary); }
.tr-up:hover:not(:disabled), .tr-down:hover:not(:disabled) {
  color: var(--accent); background: var(--bg-secondary); }
.tr-up:disabled, .tr-down:disabled { opacity: .3; cursor: default; }

.tr-rank { flex: 0 0 auto; width: 20px; text-align: center; font-size: 11px;
           font-weight: 600; color: var(--text-tertiary);
           font-variant-numeric: tabular-nums; }
.tr-desc { flex: 1; min-width: 0; }
.tr-live { font-size: 9.5px; font-weight: 700; letter-spacing: .05em; padding: 2px 8px;
           border-radius: 999px; background: var(--accent); color: #fff; flex: 0 0 auto; }
.tr-edit, .tr-del { background: none; border: none; cursor: pointer; font-size: 12.5px;
                    font-family: var(--font); color: var(--text-secondary);
                    padding: 6px 8px; border-radius: var(--radius-sm); }
.tr-edit:hover { color: var(--accent); background: var(--bg-secondary); }
.tr-del:hover { color: var(--text-danger); background: var(--bg-secondary); }
.tr-loading { padding: 26px 12px; text-align: center; color: var(--text-tertiary); font-size: 13px; }
.tr-preview { margin-top: 12px; padding: 9px 11px; border-radius: var(--radius-sm);
              background: var(--accent-light); color: var(--text-primary);
              font-size: 12.5px; font-weight: 500; }
.tr-block { margin-top: 22px; padding-top: 18px; border-top: 0.5px solid var(--border); }

/* Écran étroit : la grille garde ses sept jours mais devient défilable
   horizontalement dans son propre conteneur, plutôt que d'écraser les colonnes
   ou de faire déborder la page. */
@media (max-width: 720px) {
  .tr-grid { overflow-x: auto; grid-template-columns: 40px repeat(7, minmax(74px, 1fr)); }
  .tr-slots { height: 440px; }
}

@media (prefers-reduced-motion: reduce) {
  .tr-nav, .tr-band { transition: none; }
}

/* Bandeau « qui pilote la ligne » : distinguer un renvoi CHOISI d'un renvoi
   POSÉ PAR UNE RÈGLE HORAIRE. Les deux se ressemblaient trait pour trait. */
.pilote { display: flex; flex-direction: column; gap: 4px; margin: 12px 0 14px;
          padding: 12px 14px; border-radius: var(--radius-md);
          border-left: 4px solid var(--border-md); background: var(--bg-secondary);
          font-size: 13px; }
.pilote-titre { display: flex; align-items: center; gap: 7px;
                font-size: 12px; font-weight: 700; letter-spacing: .04em;
                text-transform: uppercase; }
.pilote-titre .material-symbols-rounded { font-size: 19px; }
.pilote-corps { color: var(--text-primary); line-height: 1.5; }
.pilote-sinon { color: var(--text-secondary); font-size: 12px; line-height: 1.5; }
.pilote .btn { align-self: flex-start; margin-top: 6px; }

.pilote-force { border-left-color: var(--text-danger); background: var(--bg-danger); }
.pilote-force .pilote-titre { color: var(--text-danger); }
.pilote-force .pilote-corps, .pilote-force .pilote-sinon { color: var(--text-danger); }
.pilote-regle { border-left-color: var(--accent); background: var(--accent-light); }
.pilote-regle .pilote-titre { color: var(--accent); }
.pilote-defaut { border-left-color: var(--border-md); }
.pilote-defaut .pilote-titre { color: var(--text-secondary); }

/* La coche garde sa couleur propre dans le bandeau de forçage, qui est rouge : le
   rouge dit « les règles horaires sont suspendues », la coche dit « le renvoi est
   bien en place ». Deux informations distinctes, deux couleurs. */
.pilote-force .pilote-ok { color: var(--text-success); }

/* Attente : peint dès le clic et remplacé quand Keyyo confirme, une vingtaine de
   secondes plus tard. Volontairement neutre — rien n'est acquis, donc ni la
   couleur du succès ni celle de l'alerte. */
.pilote-attente { border-left-color: var(--text-secondary); background: var(--bg-secondary); }
.pilote-attente .pilote-titre { color: var(--text-secondary); }
.pilote-attente .pilote-titre .material-symbols-rounded { animation: pilote-pulse 1.4s ease-in-out infinite; }
@keyframes pilote-pulse { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .pilote-attente .pilote-titre .material-symbols-rounded { animation: none; }
}

/* Le badge de la ligne active répète l'origine, là où se porte le clic.
   Ambre et non rouge : forcer un profil n'est pas une erreur, c'est un choix
   délibéré — mais qui suspend le planning, d'où le ton « attention ». Le rouge
   annonçait une panne là où tout fonctionne comme demandé. */
.redir-badge-force { background: rgba(176, 96, 0, 0.12); color: #8a5300; }
.redir-badge-regle { background: var(--accent-light); color: var(--accent); }

/* --bg-success / --bg-danger ne sont pas redéclinés en sombre : appliqués tels
   quels, leurs fonds très clairs (#eaf3de, #fcebeb) formaient une tache pâle sur
   l'interface sombre. Mêmes teintes que .audit-tag et .sim-badge, qui règlent déjà
   ce cas ailleurs dans le projet. */
@media (prefers-color-scheme: dark) {
  .redir-badge { background: rgba(107, 143, 73, 0.22); color: #9ec47a; }
  .redir-badge-force { background: rgba(255, 167, 38, 0.18); color: #ffa726; }
  /* Teinte translucide et non `--accent-light` (#20301a) : posé sur le fond déjà
     verdâtre de la ligne active, ce vert sombre était illisible. */
  .redir-badge-regle { background: rgba(126, 170, 214, 0.20); color: #92bde3; }
}

/* Notifications d'issue d'action, en bas à droite. L'API Keyyo mettant une
   vingtaine de secondes, l'écran se met à jour tout de suite et c'est la
   notification qui annonce le résultat réel. */
#toasts { position: fixed; right: 16px; bottom: 16px; z-index: 1000;
          display: flex; flex-direction: column; gap: 8px;
          max-width: min(360px, calc(100vw - 32px)); pointer-events: none; }
.toast { pointer-events: auto; display: flex; align-items: flex-start; gap: 9px;
         padding: 11px 13px; border-radius: var(--radius-md);
         background: var(--bg-primary); color: var(--text-primary);
         border: 0.5px solid var(--border-md); box-shadow: var(--shadow-md);
         font-size: 13px; line-height: 1.45;
         animation: toast-entree .18s ease-out; }
.toast-ico { font-size: 19px; flex: 0 0 auto; }
.toast-txt { flex: 1; min-width: 0; }
.toast-x { flex: 0 0 auto; background: none; border: none; cursor: pointer;
           font-size: 18px; line-height: 1; color: var(--text-secondary); padding: 0 2px; }
.toast-attente { border-left: 4px solid var(--text-tertiary); }
.toast-attente .toast-ico { color: var(--text-tertiary); }
.toast-succes { border-left: 4px solid var(--accent); }
.toast-succes .toast-ico { color: var(--accent); }
.toast-erreur { border-left: 4px solid var(--text-danger);
                background: var(--bg-danger); color: var(--text-danger); }
.toast-erreur .toast-ico, .toast-erreur .toast-x { color: var(--text-danger); }
.toast-sortie { animation: toast-sortie .18s ease-in forwards; }

@keyframes toast-entree { from { opacity: 0; transform: translateY(8px); } }
@keyframes toast-sortie { to { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
  .toast, .toast-sortie { animation: none; }
}

/* Profil que Keyyo refuse d'activer tant qu'une règle horaire s'applique :
   le bouton est désactivé, et la ligne le dit sans dépendre d'une infobulle. */
.redir-row-inerte .redir-row-name,
.redir-row-inerte .redir-row-ico { opacity: .55; }
.redir-row-inerte .redir-row-sub { color: var(--text-tertiary); font-style: italic; }

/* Les notes viennent de Google et peuvent tenir sur plusieurs lignes. */
textarea { resize: vertical; min-height: 62px; font-family: var(--font); }

/* Les explications de la fiche contact, hors de la rangee de boutons. */
.cs-notes { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }

/* ── Onglet Mails ──────────────────────────────────────────────────────────── */
/* L'état du transport passe AVANT les interrupteurs : un système allumé sur un
   transport en panne ne veut rien dire, et c'est la confusion qu'on veut éviter à
   qui vient régler quelque chose. D'où un bloc large, coloré par l'état. */
.mail-etat { border-radius: var(--radius-md); padding: 14px 16px; margin: 4px 0 22px;
             border-left: 4px solid var(--border-md); background: var(--bg-secondary); }
.mail-etat-titre { display: flex; align-items: center; gap: 8px; font-size: 12px;
                   font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.mail-etat-titre .material-symbols-rounded { font-size: 19px; }
.mail-etat-corps { margin-top: 4px; font-size: 13px; line-height: 1.5; color: var(--text-primary); }
.mail-etat-chiffres { margin-top: 6px; font-size: 12px; color: var(--text-secondary); }
.mail-avert { margin: 8px 0 0 18px; font-size: 12px; color: var(--text-secondary); }

.mail-etat-ok { border-left-color: var(--text-success); }
.mail-etat-ok .mail-etat-titre { color: var(--text-success); }
.mail-etat-off { border-left-color: var(--text-secondary); }
.mail-etat-off .mail-etat-titre { color: var(--text-secondary); }
.mail-etat-ko { border-left-color: var(--text-danger); background: var(--bg-danger); }
.mail-etat-ko .mail-etat-titre, .mail-etat-ko .mail-etat-corps { color: var(--text-danger); }

/* Pendant à l'écran du bandeau qui coiffe les mails eux-mêmes : mêmes mots, même
   orange, pour qu'on fasse le lien sans y réfléchir. */
.mail-dev { background: #b26a00; color: #fff; border-radius: var(--radius-md);
            padding: 14px 16px; margin-bottom: 16px; font-size: 13px; }
.mail-dev-titre { font-weight: 700; letter-spacing: 2px; font-size: 15px; margin-bottom: 4px; }

.mail-titre { font-size: 13px; font-weight: 700; text-transform: uppercase;
              letter-spacing: .04em; color: var(--text-secondary); margin: 22px 0 10px; }
.mail-systemes { border: 0.5px solid var(--border-md); border-radius: var(--radius-md); overflow: hidden; }
.mail-systeme { display: flex; align-items: center; gap: 16px; padding: 12px 16px;
                border-bottom: 0.5px solid var(--border); }
.mail-systeme:last-child { border-bottom: 0; }
.mail-systeme-txt { flex: 1; cursor: pointer; }
.mail-systeme-nom { display: block; font-weight: 600; font-size: 14px; }
.mail-systeme-desc { display: block; font-size: 12px; color: var(--text-secondary); margin-top: 2px; line-height: 1.45; }

.mail-journal { width: 100%; border-collapse: collapse; font-size: 12px; }
.mail-journal th { text-align: left; padding: 8px 10px; color: var(--text-secondary);
                   font-weight: 600; border-bottom: 0.5px solid var(--border-md); white-space: nowrap; }
.mail-journal td { padding: 8px 10px; border-bottom: 0.5px solid var(--border); vertical-align: top; }
.mail-statut { padding: 2px 9px; border-radius: var(--radius-pill, 999px); font-size: 11px; font-weight: 600; }
.mail-statut-envoye { background: var(--bg-success); color: var(--text-success); }
.mail-statut-echec { background: var(--bg-danger); color: var(--text-danger); }
.mail-statut-en_cours { background: var(--bg-tertiary); color: var(--text-secondary); }
.mail-vide { font-size: 13px; color: var(--text-secondary); }

/* --bg-success / --bg-danger ne sont pas redéclinées en sombre : appliquées telles
   quelles, leurs fonds très clairs feraient une tache pâle. */
@media (prefers-color-scheme: dark) {
  .mail-statut-envoye { background: rgba(107, 143, 73, 0.22); color: #9ec47a; }
  .mail-statut-echec { background: rgba(255, 167, 38, 0.18); color: #ffa726; }
  .mail-etat-ko { background: rgba(255, 167, 38, 0.10); border-left-color: #ffa726; }
  .mail-etat-ko .mail-etat-titre, .mail-etat-ko .mail-etat-corps { color: #ffa726; }
}

/* ── Onglet Récap ──────────────────────────────────────────────────────────── */
/* Palette catégorielle validée : bleu / orange / aqua, dans cet ordre fixe. Le
   mode sombre est CHOISI — les mêmes teintes repositionnées pour la surface
   sombre, pas un basculement automatique, qui ferait passer les écarts de
   lisibilité sous le plancher. Un 4e ton a été essayé et écarté : aucun ne tient
   à la fois en clair et en sombre, d'où trois parts par camembert. */
.recap-c-emis, .recap-c-perso_recus { --part: #2a78d6; }
.recap-c-decroches, .recap-c-perso_emis { --part: #eb6834; }
.recap-c-manques, .recap-c-standard { --part: #1baf7a; }
@media (prefers-color-scheme: dark) {
  .recap-c-emis, .recap-c-perso_recus { --part: #3987e5; }
  .recap-c-decroches, .recap-c-perso_emis { --part: #d95926; }
  .recap-c-manques, .recap-c-standard { --part: #199e70; }
}

.recap-barre { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
.recap-jour { font-weight: 600; font-size: 15px; min-width: 240px; }

/* Les chiffres de tête sont des tuiles, pas un graphique : une valeur seule se lit
   mieux écrite en grand qu'encodée dans une longueur ou un angle. */
.recap-tuiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
                gap: 10px; margin-bottom: 24px; }
.recap-tuile { border: 0.5px solid var(--border-md); border-radius: var(--radius-md);
               padding: 14px 16px; background: var(--bg-secondary); }
.recap-tuile-val { font-size: 26px; font-weight: 700; line-height: 1.1; }
.recap-tuile-lib { font-size: 12px; color: var(--text-secondary); margin-top: 4px; }
.recap-tuile-sub { font-size: 11px; color: var(--text-tertiary); margin-top: 2px; }

.recap-graphs { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; }
.recap-fig { border: 0.5px solid var(--border-md); border-radius: var(--radius-md);
             padding: 16px; background: var(--bg-secondary); margin: 0; }
.recap-fig-titre { font-size: 12px; font-weight: 700; text-transform: uppercase;
                   letter-spacing: .04em; color: var(--text-secondary); margin-bottom: 14px; }
.recap-fig-corps { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.recap-svg { width: 180px; height: 180px; flex-shrink: 0; }

/* 2 px de surface entre deux parts : sans cette respiration, deux teintes voisines
   se touchent et se lisent comme un seul bloc. */
.recap-part { fill: var(--part); stroke: var(--bg-secondary); stroke-width: 2; }
.recap-part:hover { opacity: .82; }

.recap-legende { list-style: none; margin: 0; padding: 0; flex: 1; min-width: 150px; }
.recap-leg { display: flex; align-items: center; gap: 9px; padding: 5px 0; font-size: 13px; }
.recap-puce { width: 11px; height: 11px; border-radius: 3px; background: var(--part); flex-shrink: 0; }
.recap-leg-nom { flex: 1; color: var(--text-primary); }
/* Le chiffre reste en encre, jamais dans la couleur de sa part : la teinte est
   portée par la puce, le texte doit rester lisible. */
.recap-leg-val { font-weight: 600; color: var(--text-primary); }
.recap-leg-pct { font-weight: 400; color: var(--text-secondary); }
.recap-vide { font-size: 13px; color: var(--text-secondary); }

/* Repli exigé dès qu'une part descend sous 3:1 de contraste : impression, vision
   des couleurs, contraste faible. */
.recap-table { margin-top: 20px; font-size: 13px; }
.recap-table summary { cursor: pointer; color: var(--text-secondary); padding: 6px 0; }
.recap-table table { border-collapse: collapse; margin-top: 8px; min-width: 280px; }
.recap-table td { padding: 6px 14px 6px 0; border-bottom: 0.5px solid var(--border); }

/* ── Récap d'équipe ────────────────────────────────────────────────────────── */
.recap-titre-eq { font-size: 13px; font-weight: 700; text-transform: uppercase;
                  letter-spacing: .04em; color: var(--text-secondary); margin: 26px 0 12px; }

/* Barres empilées, une par membre. Une SEULE échelle : la largeur est
   proportionnelle au membre le plus actif, sinon 3 appels et 90 appels
   paraîtraient identiques. */
.recap-membres { display: flex; flex-direction: column; gap: 7px; }
.recap-ligne { display: flex; align-items: center; gap: 12px; }
.recap-ligne-nom { width: 170px; flex-shrink: 0; font-size: 13px; white-space: nowrap;
                   overflow: hidden; text-overflow: ellipsis; }
.recap-piste { flex: 1; background: var(--bg-tertiary); border-radius: var(--radius-pill, 999px);
               overflow: hidden; min-width: 60px; }
.recap-barre-membre { display: flex; height: 16px; min-width: 2px;
                      border-radius: var(--radius-pill, 999px); overflow: hidden; }
/* 2 px de surface entre deux segments : sans respiration, deux teintes voisines
   se lisent comme un seul bloc. */
.recap-seg { background: var(--part); box-shadow: inset -2px 0 0 var(--bg-secondary); }
.recap-seg:last-child { box-shadow: none; }
.recap-ligne-val { width: 40px; text-align: right; font-size: 13px; font-weight: 600;
                   font-variant-numeric: tabular-nums; }

.recap-legende-h { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 14px; }
.recap-legende-h .recap-leg { padding: 0; }

.recap-table thead th { text-align: left; padding: 6px 14px 6px 0; font-weight: 600;
                        color: var(--text-secondary); border-bottom: 0.5px solid var(--border-md); }

/* Sélecteur de période. Les quatre choix sont exposés en permanence plutôt que
   repliés dans un menu : passer du jour au mois est le geste principal de cet
   écran, il ne doit pas coûter deux clics. */
.recap-periodes { display: inline-flex; gap: 4px; }
.recap-periodes .btn { margin: 0; }
.recap-sep { color: var(--text-secondary); font-size: 13px; }

/* Sélecteur de date : bouton habillé par-dessus le champ natif.
   Le natif reste dans le DOM — il apporte le clavier, les lecteurs d'écran et le
   calendrier tactile du téléphone. On ne remplace que son apparence, et il
   redevient visible si `showPicker` échoue (cf. recap-vue.js). */
.recap-datewrap { position: relative; display: inline-flex; align-items: center; }
.recap-datebtn { display: inline-flex; align-items: center; gap: 7px;
                 padding: 6px 12px 6px 10px; font: 500 13px var(--font);
                 color: var(--text-primary); background: var(--bg-primary);
                 border: 0.5px solid var(--border-md); border-radius: var(--radius-md);
                 cursor: pointer; white-space: nowrap; transition: border-color .15s, background .15s; }
.recap-datebtn:hover { border-color: var(--accent); background: var(--bg-secondary); }
.recap-datebtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.recap-datebtn .material-symbols-rounded { font-size: 17px; color: var(--text-secondary); }
.recap-datebtn:hover .material-symbols-rounded { color: var(--accent); }

/* Le champ natif est masqué SANS `display:none` : il doit rester mesurable pour
   que `showPicker` ancre le calendrier au bon endroit, et focusable en secours. */
.recap-date { position: absolute; inset: 0; width: 100%; height: 100%;
              opacity: 0; pointer-events: none; border: 0; padding: 0; }
.recap-date.recap-date-visible { position: static; opacity: 1; pointer-events: auto;
              width: auto; height: auto; padding: 6px 10px; font: 500 13px var(--font);
              color: var(--text-primary); background: var(--bg-primary);
              border: 0.5px solid var(--border-md); border-radius: var(--radius-md); }
/* L'indicateur natif est noir : illisible sur fond sombre sans inversion. */
@media (prefers-color-scheme: dark) {
  .recap-date-visible::-webkit-calendar-picker-indicator { filter: invert(1) opacity(.7); }
}

/* Les flèches en carré, pour qu'elles ne s'étirent pas au gré du chevron. */
.recap-fleche { min-width: 30px; padding-left: 8px; padding-right: 8px; }
/* Le choix de date et « Aujourd'hui » se groupent à droite : la navigation à
   gauche, le réglage à droite, plutôt qu'une file indistincte de contrôles. */
.recap-barre-droite { display: flex; align-items: center; gap: 8px;
                      margin-left: auto; flex-wrap: wrap; }

/* Calendaire / Glissant : deux segments accolés plutôt que deux boutons séparés.
   C'est un CHOIX ENTRE DEUX, pas deux actions indépendantes — la forme doit le
   dire, sans quoi on croit pouvoir les activer tous les deux. */
.recap-modes { display: inline-flex; border: 0.5px solid var(--border-md);
               border-radius: var(--radius-md); overflow: hidden; }
.recap-mode { padding: 6px 11px; font: 500 12px var(--font); cursor: pointer;
              background: var(--bg-primary); color: var(--text-secondary);
              border: 0; border-right: 0.5px solid var(--border-md);
              transition: background .15s, color .15s; }
.recap-mode:last-child { border-right: 0; }
.recap-mode:hover { background: var(--bg-secondary); color: var(--text-primary); }
.recap-mode.actif { background: var(--accent-light); color: var(--accent); font-weight: 600; }

/* Les outils du planning rappeleur vivaient ici ; ils ont rejoint le bloc
   « Serial rappeleur », plus haut dans cette feuille, avec le reste de la section. */
