/**
 * UltimateSaas — styles communs à tous les layouts (Materialize, Nexsas, …).
 * Chargé via asset('assets_all/styles.css') dans chaque layout racine.
 */

/* —— Bandeau RGPD / cookies —— */
.us-rgpd-banner {
  --us-primary: #666cff;
  --us-primary-rgb: 102, 108, 255;
  --us-primary-contrast: #fff;

  position: fixed;
  z-index: 1080;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
  pointer-events: none;
  opacity: 0;
  transform: translateY(100%);
  transition: opacity 0.35s ease, transform 0.35s ease;
}

.us-rgpd-banner.is-visible {
  pointer-events: auto;
  opacity: 1;
  transform: translateY(0);
}

.us-rgpd-banner.is-hidden {
  display: none !important;
}

.us-rgpd-banner__inner {
  max-width: 72rem;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.25rem;
  padding: 1rem 1.25rem;
  border-radius: 0.75rem;
  background: #fff;
  border: 1px solid rgba(var(--us-primary-rgb), 0.22);
  box-shadow:
    0 4px 24px rgba(15, 23, 42, 0.12),
    0 0 0 1px rgba(15, 23, 42, 0.04);
}

.us-rgpd-banner__text {
  flex: 1 1 16rem;
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.55;
  color: #3b4256;
}

.us-rgpd-banner__actions {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

.us-rgpd-banner__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  padding: 0.5rem 1.25rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.25;
  cursor: pointer;
  border: none;
  text-decoration: none;
  transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease;
}

.us-rgpd-banner__btn:active {
  transform: scale(0.98);
}

.us-rgpd-banner__btn--primary {
  background: var(--us-primary);
  color: var(--us-primary-contrast);
  box-shadow: 0 2px 8px rgba(var(--us-primary-rgb), 0.35);
}

.us-rgpd-banner__btn--primary:hover {
  filter: brightness(1.06);
  box-shadow: 0 4px 14px rgba(var(--us-primary-rgb), 0.4);
}

.us-rgpd-banner__btn--ghost {
  background: rgba(var(--us-primary-rgb), 0.08);
  color: var(--us-primary);
}

.us-rgpd-banner__btn--ghost:hover {
  background: rgba(var(--us-primary-rgb), 0.14);
}

@media (max-width: 575.98px) {
  .us-rgpd-banner__inner {
    flex-direction: column;
    align-items: stretch;
  }

  .us-rgpd-banner__actions {
    width: 100%;
    flex-direction: column;
  }

  .us-rgpd-banner__btn {
    width: 100%;
  }
}

/* —— Topbar « impersonation » (connexion déléguée) —— */
/* Fixé tout en haut, AU-DESSUS de la barre du haut et non par-dessus (18/10/2026) : la barre du thème
   est `position: fixed; top: 0`, un bandeau sticky la recouvrait. Le bandeau réserve sa hauteur
   (--us-impersonation-h, mesurée par le composant) : la page, la barre du haut et le menu descendent d'autant. */
html:has(.us-impersonation-banner) {
  --us-impersonation-h: 2.75rem;
}

html:has(.us-impersonation-banner) body {
  padding-top: var(--us-impersonation-h);
}

html:has(.us-impersonation-banner) .layout-navbar-fixed .layout-navbar,
html:has(.us-impersonation-banner).layout-navbar-fixed .layout-navbar,
html:has(.us-impersonation-banner) .layout-menu-fixed .layout-menu,
html:has(.us-impersonation-banner).layout-menu-fixed .layout-menu,
html:has(.us-impersonation-banner).us-app-screen .layout-menu {
  top: var(--us-impersonation-h);
}

html:has(.us-impersonation-banner).layout-menu-fixed .layout-menu,
html:has(.us-impersonation-banner).us-app-screen .layout-menu {
  height: calc(100vh - var(--us-impersonation-h));
}

.us-impersonation-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1090;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  flex-wrap: wrap;
  padding: 0.5rem 1rem;
  background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
  color: #fff;
  font-size: 0.875rem;
  line-height: 1.4;
  box-shadow: 0 2px 10px rgba(15, 23, 42, 0.25);
}

.us-impersonation-banner__info {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.us-impersonation-banner__icon {
  flex: 0 0 auto;
  font-size: 1.15rem;
  line-height: 1;
}

.us-impersonation-banner__text {
  min-width: 0;
}

.us-impersonation-banner__text strong {
  font-weight: 700;
}

.us-impersonation-banner__email {
  opacity: 0.85;
}

.us-impersonation-banner__form {
  margin: 0;
  flex: 0 0 auto;
}

.us-impersonation-banner__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.9rem;
  border: none;
  border-radius: 0.4rem;
  background: rgba(255, 255, 255, 0.95);
  color: #b45309;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.15s ease, transform 0.1s ease, box-shadow 0.15s ease;
}

.us-impersonation-banner__btn:hover {
  background: #fff;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.2);
  transform: translateY(-1px);
}

.us-impersonation-banner__btn:active {
  transform: translateY(0);
}

@media (max-width: 575.98px) {
  .us-impersonation-banner__email {
    display: none;
  }
}

/* —— Interrupteur On / Off des tableaux d'administration ——————————————————
   Un `.form-switch` de Bootstrap fait 2 rem de large et se perd dans un tableau
   dense : partout ou une colonne (ou un coin de carte) n'existe QUE pour cet
   interrupteur, on l'agrandit franchement.

   POURQUOI DANS LE COEUR. La regle vivait en double — `_switch_style.blade.php`
   du module Autoscraper et `spider-agent.css` du module SpiderAgent. Deux copies
   des memes valeurs, c'est la premiere retouche qui ne change la taille que d'une
   moitie des ecrans. Elle est ici, chargee par `commonMaster` sur toutes les pages
   d'admin de tous les deploiements ; un module qui veut ce style n'a plus qu'a
   poser la classe.

   `padding-left: 0` annule le decalage de `.form-check`, prevu pour laisser la
   place a un libelle : ici il n'y en a pas, la case doit rester au centre de sa
   colonne.

   CONVENTION D'USAGE — un etat DURABLE (actif/inactif, en pause) se regle par cet
   interrupteur, dans SA propre colonne a gauche des actions, et ne se redit PAS
   ailleurs sous forme de badge : deux rendus du meme booleen, c'est deux endroits
   a corriger le jour ou il change de sens, et un seul qui le sera. La case ne
   porte aucun `name` : le serveur bascule l'etat courant, il ne le recoit pas —
   poster la valeur affichee laisserait un second onglet reste ouvert sur une page
   perimee ecraser l'etat reel. */
.sw-onoff { padding-left: 0; }
.sw-onoff .form-check-input { width: 3rem; height: 1.6rem; margin: 0; float: none; cursor: pointer; }

/* —— Modale defilante dont le <form> enveloppe header / body / footer ————————
   Bootstrap suppose `.modal-header`, `.modal-body` et `.modal-footer` enfants
   DIRECTS de `.modal-content`, qui est un `flex-direction: column` : c'est ce qui
   donne au corps son `flex: 1 1 auto` et borne sa hauteur, sans quoi son
   `overflow-y: auto` (pose par `.modal-dialog-scrollable`) ne se declenche jamais.

   Des qu'un `<form>` s'intercale — pour poster toute la modale d'un bloc, ce que
   fait la moitie de nos modales d'edition — le corps n'est plus un flex item :
   il grandit librement, et le `overflow: hidden` de `.modal-content` COUPE
   simplement le bas du formulaire. Symptome : sur un ecran court, les derniers
   champs ET le bouton Enregistrer deviennent inatteignables, sans barre de
   defilement nulle part. Aucun message, aucune erreur console.

   On rend donc le formulaire lui-meme colonne flex, en relais de `.modal-content`.
   `min-height: 0` n'est pas decoratif : sans lui un flex item refuse de descendre
   sous la hauteur de son contenu, donc rien ne deborde et rien ne defile.

   POURQUOI DANS LE COEUR. Le defaut est structurel, pas propre a un ecran : il
   frappait 10 modales (roles, plans d'abonnement / de credits / One Shot, et les
   deux modales d'edition du module Email). Corrige ici, il l'est partout, et une
   modale future ecrite avec un form n'aura rien a faire de special. */
.modal-dialog-scrollable .modal-content > form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  max-height: 100%;
}
.modal-dialog-scrollable .modal-content > form > .modal-body { min-height: 0; }

/* —— Une action INDISPONIBLE sur une ligne garde sa place, grisee ————————————
   Retirer une icone quand elle ne s'applique pas decale TOUTES les suivantes :
   la colonne « Actions » est alignee a droite (`text-end`), donc une icone en
   moins fait glisser la corbeille d'une ligne sous le crayon de la ligne du
   dessus — on supprime en croyant editer, et on ne le decouvre qu'apres.

   Ce n'est volontairement PAS un `<button disabled>` : Bootstrap 5 pose
   `pointer-events: none` sur les boutons desactives, donc l'infobulle — le seul
   endroit qui dit POURQUOI l'action manque — ne s'afficherait jamais. C'est un
   `<span>` portant les memes classes `.btn`, neutralise ici.

   POURQUOI DANS LE COEUR : la meme regle etait deja recopiee dans deux modules
   (`.pe-act-off` cote Email, `.sa-act-off` cote SpiderAgent). Toute nouvelle vue
   utilise `.us-act-off` et le partial `materialize.admin.partials._action_off`. */
.us-act-off {
  opacity: .3;
  cursor: not-allowed;
}

/* Un survol qui repond donne l'illusion d'un bouton : la boite reste, la reaction non. */
.us-act-off:hover,
.us-act-off:focus,
.us-act-off:active {
  background-color: transparent;
  border-color: transparent;
  box-shadow: none;
  opacity: .3;
}

/* —— Fond personnalisé de la page de connexion (/login) ——
   Réglé dans Réglages → Personnalisation → Identité visuelle (HardSetting `login_background_path`).
   La vue ne pose que la classe `.us-auth-bg` et la variable `--us-auth-bg-image` (l'URL change
   d'un déploiement à l'autre) : tout le reste est ici. */
.us-auth-bg {
  position: relative;
  isolation: isolate;
  background-color: #0b0b14;
  background-image: var(--us-auth-bg-image);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

/* Voile sombre : le formulaire reste lisible quelle que soit l'image choisie. */
.us-auth-bg::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(ellipse at center, rgba(8, 8, 16, .55) 0%, rgba(8, 8, 16, .25) 60%, rgba(8, 8, 16, .45) 100%);
  pointer-events: none;
}

/* La carte se détache du fond : ombre marquée, léger flou derrière elle. */
.us-auth-bg .authentication-inner > .card {
  box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, .45);
  backdrop-filter: blur(6px);
}

/* Aperçu 16:9 dans l'écran d'administration. */
.us-login-bg-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 256px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #f6f6fa;
  border: 1px solid var(--bs-border-color);
  border-radius: 6px;
}
.us-login-bg-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Écran « application » à pleine hauteur (Slack, WhatsApp — window.UsFullHeight, scripts.js) :
   la page ne défile pas. Le menu de gauche, plus haut que la fenêtre, allongeait la page ;
   il est figé à la hauteur de l'écran et défile dans son propre ascenseur. */
html.us-app-screen .layout-menu {
  position: sticky;
  top: 0;
  height: 100vh;
  align-self: flex-start;
}

/* Le menu de gauche défile seul, sur TOUS les écrans d'administration (18/10/2026, demande de Philippe : « pas besoin
   de scroller la page pour descendre »). Même montage que les écrans « application » ci-dessus, étendu à tout grand
   écran : figé à la hauteur de la fenêtre, il défile dans son propre ascenseur (PerfectScrollbar du thème, menu.js).
   ⚠️ Pas `layout-menu-fixed` : le composer du cœur ne la pose plus, et la rallumer changerait toute la mise en page.
   Sous 1200 px, le menu est un tiroir du thème (position fixe) : on n'y touche pas. */
@media (min-width: 1200px) {
  html:not(.us-app-full-on) .layout-wrapper:not(.layout-horizontal) .layout-menu {
    position: sticky;
    top: 0;
    height: 100vh;
    align-self: flex-start;
  }

  html:has(.us-impersonation-banner):not(.us-app-full-on) .layout-wrapper:not(.layout-horizontal) .layout-menu {
    top: var(--us-impersonation-h);
    height: calc(100vh - var(--us-impersonation-h));
  }
}

/* L'ascenseur du menu aux couleurs du thème, visible seulement quand la souris est dans le menu (18/10/2026, demande de
   Philippe). Au doigt, pas de survol : le menu défile quand même, sans ascenseur affiché. */
.layout-menu .menu-inner > .ps__rail-y {
  opacity: 0;
  background-color: transparent;
  transition: opacity 0.2s;
}

.layout-menu:hover .menu-inner > .ps__rail-y {
  opacity: 0.6;
}

.layout-menu .menu-inner > .ps__rail-y > .ps__thumb-y,
.layout-menu .menu-inner > .ps__rail-y:hover > .ps__thumb-y,
.layout-menu .menu-inner > .ps__rail-y.ps--clicking > .ps__thumb-y {
  background-color: var(--bs-primary);
}

.layout-menu .menu-inner > .ps__rail-y:hover,
.layout-menu .menu-inner > .ps__rail-y.ps--clicking {
  opacity: 1;
  background-color: rgba(var(--bs-primary-rgb), 0.12);
}

/* Sans PerfectScrollbar (menu.js retombe sur `overflow-auto`) : l'ascenseur natif, même couleur, lui aussi au survol. */
.layout-menu .menu-inner.overflow-auto {
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
}

.layout-menu:hover .menu-inner.overflow-auto {
  scrollbar-color: var(--bs-primary) transparent;
}

/* Plein écran d'un écran « application » (bouton [data-us-app-fullscreen], scripts.js) : la boîte couvre
   la fenêtre, au-dessus du menu et de la barre du haut, sous les modales (1055) pour que la visionneuse
   et les fenêtres de l'écran restent au-dessus. */
.us-app-full {
  position: fixed !important;
  inset: 0;
  z-index: 1045;
  height: 100vh !important;
  min-height: 0 !important;
  margin: 0 !important;
  border-radius: 0 !important;
}

html.us-app-full-on,
html.us-app-full-on body {
  overflow: hidden;
}

/* Le menu (z-index 1080) et la barre du haut (1075) du thème passeraient au-dessus : masqués le temps
   du plein écran (visibility, pour ne pas faire bouger la mise en page dessous). */
html.us-app-full-on .layout-menu,
html.us-app-full-on .layout-navbar {
  visibility: hidden;
}

/* ════════════════════════════════════════════════════════════════════════════════════════════
   PANNEAU « AUTOMATISATION » COMMUN (context-panel.js, composant components.context.automation,
   carte #115). Variables Bootstrap seulement : il s'ouvre sur tous les thèmes.
   ════════════════════════════════════════════════════════════════════════════════════════════ */
.us-ctx-wrap { position: relative; display: inline-flex; }
/* L'ouvreur du lanceur SpiderAgent historique : présent (il faut une position pour placer son
   menu), invisible. `display: none` lui ferait rendre un rectangle vide. */
.us-ctx-advanced {
  position: absolute; left: 0; bottom: 0; width: 1px; height: 1px;
  padding: 0; border: 0; opacity: 0; overflow: hidden; pointer-events: none;
}
/* « Copier le contexte » (prop `copy` du composant) : menu plafonné, un projet peut porter 90 prompts. */
.us-ctx-copy-menu { max-height: 60vh; overflow-y: auto; }
/* Le thème met `.btn` en capitalize : « Copier Le Contexte ». */
.us-ctx-copy { text-transform: none; }
/* Pied du panneau : le sélecteur « Lancer sur » porte des libellés longs (« Selon mon réglage (Poste … puis …) ») ;
   en largeur libre il poussait « Copier » hors de la fenêtre (05/10/2026). Il est plafonné et tronqué, les
   boutons gardent leur taille. */
.us-ctx-actions { min-width: 0; flex: 0 1 auto; }
.us-ctx-actions .btn { flex: 0 0 auto; white-space: nowrap; }
.us-ctx-cible { width: auto; max-width: 14rem; min-width: 0; flex: 0 1 auto; text-overflow: ellipsis; }
/* Accordéons du panneau Automatisation (2026-10-18) : aucune hauteur maximale, la modale seule défile. */
.us-ctx-accordeon .accordion-button { text-transform: none; padding: .625rem .875rem; }
.us-ctx-bloc-titre {
  position: sticky; top: 0; z-index: 1; padding: .25rem .25rem;
  background: var(--bs-body-bg, #fff); font-size: .75rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .02em; color: var(--bs-secondary-color, #8592a3);
}
.us-ctx-groupe-titre { padding: .375rem .25rem .125rem; font-size: .75rem; font-weight: 600; color: var(--bs-body-color); }
.us-ctx-item { margin: 0 0 .125rem .5rem; font-size: .8125rem; }
.us-ctx-item .form-check-label { cursor: pointer; }
/* Onglet « Prompts de contexte » d'un module (components.context.prompts-manager). */
.us-ctx-gabarit {
  max-height: 16rem; overflow: auto; white-space: pre-wrap; font-size: .75rem;
  padding: .75rem; border-radius: .375rem; background: var(--bs-secondary-bg, #f5f5f9); color: var(--bs-body-color);
}
.us-ctx-grip-col { width: 2rem; }
.us-ctx-grip { cursor: grab; color: var(--bs-secondary-color, #8592a3); }
.us-ctx-manager tr.us-ctx-drag { opacity: .4; }
/* Le thème met `text-transform: capitalize` sur tout `.btn` : « Lanceur Avancé ». Pas ici. */
.us-ctx-modal .btn,
.us-ctx-wrap .btn { text-transform: none; }
/* ═══ LE MENU EN CASCADE DU BOUTON « AUTOMATISATION » (context-menu.js, façon menu Démarrer XP) ═══
   Chaque volet est un `position: fixed` indépendant, posé contre la ligne qui l'ouvre. */
.us-ctx-menu {
  position: fixed; z-index: 1095; min-width: 15rem; max-width: 26rem; max-height: 70vh; overflow-y: auto;
  overscroll-behavior: contain; padding: .25rem 0; border-radius: .375rem;
  background: var(--bs-body-bg, #fff); border: 1px solid var(--bs-border-color, #d9dee3);
  box-shadow: 0 .25rem 1.25rem rgba(0, 0, 0, .18); font-size: .8125rem;
}
.us-ctx-menu-titre {
  padding: .375rem .75rem .5rem; margin-bottom: .25rem; font-size: .75rem; font-weight: 600;
  color: var(--bs-secondary-color, #8592a3); border-bottom: 1px solid var(--bs-border-color, #d9dee3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.us-ctx-menu-sep { margin: .25rem 0; border-top: 1px solid var(--bs-border-color, #d9dee3); }
.us-ctx-menu-vide { padding: .375rem .75rem; color: var(--bs-secondary-color, #8592a3); font-size: .75rem; }
.us-ctx-menu-item {
  display: flex; align-items: center; gap: .5rem; padding: .3125rem .75rem; cursor: pointer;
  color: var(--bs-body-color, #566a7f); line-height: 1.35;
}
.us-ctx-menu-item:hover, .us-ctx-menu-item.is-open { background: var(--bs-secondary-bg, #f5f5f9); }
.us-ctx-menu-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.us-ctx-menu-count { flex: 0 0 auto; font-size: .6875rem; color: var(--bs-secondary-color, #8592a3); }
.us-ctx-menu-chev { flex: 0 0 auto; }
/* Copier / Exécuter : discrets au repos, nets au survol de la ligne. */
.us-ctx-menu-actions { flex: 0 0 auto; display: inline-flex; gap: .25rem; opacity: .35; }
.us-ctx-menu-item:hover .us-ctx-menu-actions { opacity: 1; }
.us-ctx-menu-btn {
  padding: .0625rem .4rem; border: 1px solid var(--bs-border-color, #d9dee3); border-radius: .25rem;
  background: var(--bs-body-bg, #fff); color: var(--bs-primary, #666cff); font-size: .6875rem; line-height: 1.4;
}
.us-ctx-menu-btn:hover { background: var(--bs-primary, #666cff); color: #fff; }
.us-ctx-menu-btn.is-run { color: var(--bs-success, #72e128); }
.us-ctx-menu-btn.is-run:hover { background: var(--bs-success, #72e128); color: #fff; }
.us-ctx-menu-btn.is-ok { background: var(--bs-success, #72e128); border-color: var(--bs-success, #72e128); color: #fff; }
.us-ctx-menu-btn.is-ko { background: var(--bs-danger, #ff4d49); border-color: var(--bs-danger, #ff4d49); color: #fff; }

/* ==============================================================================================
   RAPPELS — le TABLEAU CRUD commun (Tâches, Prospection), remonté de task.css le 2026-09-30.
   🔴 Il a remplacé un formulaire déplié en permanence, qui se lisait comme une LIGNE EXISTANTE.
   ============================================================================================== */
.us-rappel-table { font-size: .8125rem; }
.us-rappel-table > thead > tr > th {
  font-size: .6875rem; font-weight: 600; letter-spacing: .02em; text-transform: uppercase;
  padding-bottom: .25rem; white-space: nowrap;
}
.us-rappel-table > tbody > tr > td { padding: .4rem .35rem; vertical-align: top; }
/* Un rappel suspendu, déjà sonné ou envoyé RESTE lisible : on l'éteint, on ne le cache pas. */
.us-rappel-table > tbody > tr.is-off > td { opacity: .55; }
/* ⚠️ La colonne « Actions » ne se comprime jamais : des icônes qui passent à la ligne décaleraient
   la corbeille sous le crayon de la ligne voisine (règle « colonne ACTIONS » du parc). */
.us-rappel-table > tbody > tr > td:last-child,
.us-rappel-table > thead > tr > th:last-child { width: 1%; white-space: nowrap; }
/* La ligne d'édition n'est pas une ligne de données. */
.us-rappel-edit > td { background-color: rgba(0, 0, 0, .015); border-radius: .25rem; }

/* ==========================================================================================
   SÉCURITÉ DU COMPTE (2026-10-05) — onglet « Sécurité » du profil et écrans de vérification
   (resources/views/materialize/account-security/, materialize/profile/account-security).
   ========================================================================================== */

/* Logo de la carte des écrans de vérification (même hauteur que la connexion). */
.us-auth-logo { height: 40px; }

/* Clavier du PIN : 3 colonnes, touches carrées, aucun champ de saisie. */
.us-pinpad { max-width: 280px; margin: 0 auto; }
.us-pinpad-dots { min-height: 1.75rem; text-align: center; font-size: 1.25rem; letter-spacing: .35rem; margin-bottom: .75rem; }
.us-pinpad-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem; }
.us-pinpad-key { height: 3.25rem; font-size: 1.25rem; font-weight: 600; padding: 0; }

/* QR code (application d'authentification, abonnement ntfy). */
.us-as-qr { width: 168px; height: 168px; background: #fff; border-radius: .375rem; padding: 4px; }
.us-as-qr svg { width: 100%; height: 100%; display: block; }

/* Codes de secours affichés une fois. */
.us-as-recovery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: .4rem; }
.us-as-recovery-grid code { font-size: .95rem; }

/* Champs courts de l'onglet. */
.us-as-password { max-width: 240px; }
.us-as-code { max-width: 140px; }

/* Méthode éteinte par l'administrateur : visible, mais grisée. */
.us-as-off { opacity: .55; }

/* QCM d'un agent répondu depuis la cloche (2026-10-05) : réponse envoyée = formulaire grisé. */
.us-agent-q .btn.active { color: var(--bs-white); background-color: var(--bs-primary); }
.us-agent-q-done { opacity: .6; }

/* Profil : carte « Fuseau horaire » (App\Support\Time\UserTimezone) — liste longue, largeur bornée. */
.us-tz-select {
  max-width: 28rem;
}

/* Profil : choix du module d'une exception de fuseau. */
.us-tz-module-select {
  max-width: 16rem;
}

/* ==============================================================================================
 * BARRE D'ACTIONS DE SÉLECTION — `.us-bulkbar` (2026-10-14, demande de Philippe)
 * Toute barre qui apparaît quand on coche des cases (tableau de bord, Email, Growth, Pilote, Slack,
 * Telegram, WhatsApp, TelVirtuel…) se colle en BAS DE L'ÉCRAN, fixe, quel que soit le défilement.
 * Le module garde sa logique d'affichage (d-none / hidden) : la classe ne fait que la placer.
 * ⚠️ Un ancêtre avec `transform` / `filter` casse `position: fixed` : poser la barre hors d'un tel bloc.
 * ============================================================================================== */
.us-bulkbar {
  position: fixed !important;
  z-index: 1045; /* au-dessus du contenu et de la barre du haut, sous les modales (1055) */
  left: 50%;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  top: auto !important;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100vw - 2rem);
  margin: 0 !important;
  padding: 0.625rem 1rem !important;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  background: var(--bs-paper-bg, var(--bs-body-bg)) !important;
  border: 1px solid var(--bs-border-color) !important;
  border-radius: 0.75rem;
  box-shadow: 0 0.5rem 2rem rgba(var(--bs-black-rgb, 0, 0, 0), 0.22);
}

.us-bulkbar[hidden],
.us-bulkbar.d-none,
/* Variante « auto » : le module ne masque que les BOUTONS (d-none) ; la barre se cache seule quand
   aucun bouton direct n'est visible (TelVirtuel, articles du blog). */
.us-bulkbar[data-us-bulkbar-auto]:not(:has(> .btn:not(.d-none))) {
  display: none !important;
}

/* Sur grand écran, la barre se centre sur la zone de contenu, pas sur la fenêtre (menu latéral ouvert). */
@media (min-width: 1200px) {
  .layout-menu-fixed:not(.layout-menu-collapsed) .us-bulkbar {
    left: calc(50% + var(--bs-menu-width, 16.25rem) / 2);
    max-width: calc(100vw - var(--bs-menu-width, 16.25rem) - 2rem);
  }
}

/* La barre ne cache pas la fin de la page. */
body:has(.us-bulkbar:not(.d-none):not([hidden]):not([data-us-bulkbar-auto])) .content-wrapper,
body:has(.us-bulkbar[data-us-bulkbar-auto]:has(> .btn:not(.d-none))) .content-wrapper {
  padding-bottom: 6rem;
}

/* La barre des lignes cochées, composant `<x-selection.bar>` (2026-10-14) : `.us-bulkbar` la place, ceci la met en ligne. */
.us-selbar {
  display: flex;
}

/* Les gestes de la barre, et sa confirmation (Supprimer…) qui prend leur place le temps d'une réponse. */
.us-selbar-actions,
.us-selbar-ask {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}

.us-selbar-actions.d-none,
.us-selbar-ask.d-none {
  display: none !important;
}

/* Au-delà du plafond (`max`), le compte passe en rouge : le contexte et l'automatisation sont grisés. */
.us-selbar.is-over [data-us-sel-count] {
  color: var(--bs-danger);
}

/* La zone pleine largeur sous les gestes (champ de réponse…) ; absente si elle ne porte que des champs cachés. */
.us-selbar-extra {
  display: block;
  width: 100%;
}

.us-selbar-extra:not(:has(:not(input[type="hidden"]))) {
  display: none;
}

/* ===== Relief des boutons (Réglages → Personnalisation, App\Support\Branding\Relief) =====
   Classe sur <html> : us-btn-relief-light | us-btn-relief-strong (rien = boutons plats).
   Seuls les boutons PLEINS prennent du relief ; contour, texte, lien et désactivés restent plats.
   L'ombre reprend la couleur du bouton (--bs-btn-box-shadow-rgb du thème).
   L'aperçu de l'écran de réglage pose la même classe sur un conteneur .us-btn-relief-preview,
   plus spécifique : il gagne sur la classe de <html>. */
.us-btn-relief-strong :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled) {
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .22) 0%, rgba(255, 255, 255, 0) 55%, rgba(0, 0, 0, .14) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 8px 18px -6px rgba(var(--bs-btn-box-shadow-rgb, 15, 23, 42), .65);
  transition: transform .15s ease, box-shadow .15s ease, background-color .15s ease;
}

.us-btn-relief-strong :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled):hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 12px 24px -6px rgba(var(--bs-btn-box-shadow-rgb, 15, 23, 42), .75);
}

.us-btn-relief-strong :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled):active {
  transform: translateY(0);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, .15), 0 4px 10px -4px rgba(var(--bs-btn-box-shadow-rgb, 15, 23, 42), .6);
}

.us-btn-relief-light :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled) {
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .12) 0%, rgba(255, 255, 255, 0) 60%, rgba(0, 0, 0, .06) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 4px 10px -4px rgba(var(--bs-btn-box-shadow-rgb, 15, 23, 42), .45);
  transform: none;
  transition: box-shadow .15s ease, background-color .15s ease;
}

.us-btn-relief-light :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled):hover {
  transform: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 6px 14px -4px rgba(var(--bs-btn-box-shadow-rgb, 15, 23, 42), .55);
}

.us-btn-relief-preview.us-btn-relief-none :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled),
.us-btn-relief-preview.us-btn-relief-none :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled):hover {
  background-image: none;
  box-shadow: var(--bs-btn-box-shadow);
  transform: none;
}

.us-btn-relief-preview.us-btn-relief-light :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled) {
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .12) 0%, rgba(255, 255, 255, 0) 60%, rgba(0, 0, 0, .06) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 4px 10px -4px rgba(var(--bs-btn-box-shadow-rgb, 15, 23, 42), .45);
  transform: none;
}

.us-btn-relief-preview.us-btn-relief-strong :is(.btn-primary, .btn-secondary, .btn-success, .btn-info, .btn-warning, .btn-danger, .btn-dark):not(:disabled):not(.disabled) {
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .22) 0%, rgba(255, 255, 255, 0) 55%, rgba(0, 0, 0, .14) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 8px 18px -6px rgba(var(--bs-btn-box-shadow-rgb, 15, 23, 42), .65);
}

/* Logo de la page de connexion, à la place du titre « Bienvenue sur … » (15/10/2026). */
.us-auth-logo {
  display: block;
  max-width: 100%;
  max-height: 56px;
  margin: 0 auto 1.25rem;
}

/* ===== Relief des fenêtres modales (Réglages → Personnalisation, App\Support\Branding\Relief) =====
   Classe sur <html> : us-modal-relief-light | us-modal-relief-strong (rien = fenêtres plates).
   Marqué : ombre en couches, reflet, liseré, fond flouté derrière la fenêtre, ouverture en léger zoom.
   L'aperçu de l'écran de réglage (.us-modal-relief-preview) gagne sur la classe de <html>. */
.us-modal-relief-strong .modal-content {
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: 1rem;
  background-image: linear-gradient(180deg, rgba(var(--bs-primary-rgb, 102, 108, 255), .05) 0, rgba(var(--bs-primary-rgb, 102, 108, 255), 0) 140px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 2px 4px rgba(15, 23, 42, .08),
    0 12px 24px rgba(15, 23, 42, .14),
    0 32px 64px rgba(15, 23, 42, .22),
    0 60px 120px -30px rgba(15, 23, 42, .45);
}

.us-modal-relief-strong .modal-backdrop.show {
  backdrop-filter: blur(4px);
}

.us-modal-relief-strong .modal.fade .modal-dialog {
  transform: translateY(12px) scale(.97);
  transition: transform .22s cubic-bezier(.2, .8, .2, 1);
}

.us-modal-relief-strong .modal.show .modal-dialog {
  transform: none;
}

.us-modal-relief-light .modal-content {
  border-radius: .875rem;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .8),
    0 4px 10px rgba(15, 23, 42, .08),
    0 18px 40px -10px rgba(15, 23, 42, .25);
}

html[data-bs-theme="dark"].us-modal-relief-strong .modal-content,
html[data-bs-theme="dark"].us-modal-relief-light .modal-content {
  border-color: rgba(255, 255, 255, .08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06), 0 24px 64px rgba(0, 0, 0, .6);
}

/* Aperçu dans l'écran de réglage : une fausse fenêtre, posée dans la page. */
.us-relief-modal-sample {
  max-width: 420px;
  padding: .5rem .5rem 2rem;
}

.us-relief-modal-sample .modal-header,
.us-relief-modal-sample .modal-body,
.us-relief-modal-sample .modal-footer {
  padding: 1rem 1.25rem;
}

.us-relief-modal-sample .modal-body {
  padding-top: 0;
}

.us-modal-relief-preview.us-modal-relief-none .modal-content {
  border: var(--bs-modal-border-width, 0) solid var(--bs-modal-border-color, transparent);
  border-radius: var(--bs-modal-border-radius, .5rem);
  background-image: none;
  box-shadow: var(--bs-modal-box-shadow, 0 .25rem 1rem rgba(0, 0, 0, .15));
}

.us-modal-relief-preview.us-modal-relief-light .modal-content {
  border: var(--bs-modal-border-width, 0) solid var(--bs-modal-border-color, transparent);
  border-radius: .875rem;
  background-image: none;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .8),
    0 4px 10px rgba(15, 23, 42, .08),
    0 18px 40px -10px rgba(15, 23, 42, .25);
}

.us-modal-relief-preview.us-modal-relief-strong .modal-content {
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: 1rem;
  background-image: linear-gradient(180deg, rgba(var(--bs-primary-rgb, 102, 108, 255), .05) 0, rgba(var(--bs-primary-rgb, 102, 108, 255), 0) 140px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 2px 4px rgba(15, 23, 42, .08),
    0 12px 24px rgba(15, 23, 42, .14),
    0 32px 64px rgba(15, 23, 42, .22),
    0 60px 120px -30px rgba(15, 23, 42, .45);
}

/* ==========================================================================
   Human check : protection anti-robot des formulaires publics
   (<x-human-check form="..."/>, App\Support\HumanCheck, comportement : human-check.js)
   - .hc-trap : le champ piege, hors de l'ecran (pas display:none, que certains robots sautent) ;
   - .hc-grid/.hc-item : le defi d'images. Les tuiles restent claires en theme sombre, sinon
     l'icone noire disparait ;
   - la COULEUR d'une icone nait du couple .hc-v<n> (grille) / .hc-k<n> (icone) : carre latin
     recopie de HumanCheckChallenge::VARIANTS (rouge, vert, bleu, jaune, violet, noir). Les deux
     tables doivent rester egales. Les classes .hc-red, .hc-green... posees sur les icones sont
     des leurres : elles ne doivent JAMAIS recevoir de style.
   ========================================================================== */
.hc-trap { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.hc-box { margin: 0 0 1.25rem; }
.hc-captcha { border: 1px solid var(--bs-border-color, #d9dee3); border-radius: .5rem; padding: .875rem; }
.hc-instruction { font-weight: 600; margin: 0 0 .75rem; }
.hc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(3.25rem, 1fr)); gap: .5rem; }
.hc-item { position: relative; display: flex; align-items: center; justify-content: center; aspect-ratio: 1 / 1;
  background: #fff; border: 2px solid #d9dee3; border-radius: .5rem; padding: 0; cursor: pointer;
  transition: border-color .15s ease, box-shadow .15s ease, transform .1s ease; }
.hc-item:hover { border-color: #9aa3ad; }
.hc-item:focus-visible { outline: 3px solid var(--bs-primary, #666cff); outline-offset: 2px; }
.hc-item.is-selected { border-color: var(--bs-primary, #666cff); box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb, 102, 108, 255), .25); transform: scale(1.04); }
.hc-item .ri { width: 2rem; height: 2rem; font-size: 2rem; }
.hc-ghost { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.hc-refresh { display: inline-flex; align-items: center; gap: .25rem; margin-top: .625rem; padding: 0; border: 0;
  background: none; color: var(--bs-primary, #666cff); font-size: .875rem; cursor: pointer; }
.hc-refresh .ri { width: 1rem; height: 1rem; }
.hc-error { color: var(--bs-danger, #ff4d49); font-size: .875rem; margin-top: .5rem; }
.hc-v0 .hc-k0{color:#f9a825} .hc-v0 .hc-k1{color:#d32f2f} .hc-v0 .hc-k2{color:#212121} .hc-v0 .hc-k3{color:#2e7d32} .hc-v0 .hc-k4{color:#7b1fa2} .hc-v0 .hc-k5{color:#1565c0}
.hc-v1 .hc-k0{color:#2e7d32} .hc-v1 .hc-k1{color:#7b1fa2} .hc-v1 .hc-k2{color:#d32f2f} .hc-v1 .hc-k3{color:#1565c0} .hc-v1 .hc-k4{color:#212121} .hc-v1 .hc-k5{color:#f9a825}
.hc-v2 .hc-k0{color:#212121} .hc-v2 .hc-k1{color:#1565c0} .hc-v2 .hc-k2{color:#f9a825} .hc-v2 .hc-k3{color:#d32f2f} .hc-v2 .hc-k4{color:#2e7d32} .hc-v2 .hc-k5{color:#7b1fa2}
.hc-v3 .hc-k0{color:#d32f2f} .hc-v3 .hc-k1{color:#f9a825} .hc-v3 .hc-k2{color:#2e7d32} .hc-v3 .hc-k3{color:#7b1fa2} .hc-v3 .hc-k4{color:#1565c0} .hc-v3 .hc-k5{color:#212121}
.hc-v4 .hc-k0{color:#1565c0} .hc-v4 .hc-k1{color:#212121} .hc-v4 .hc-k2{color:#7b1fa2} .hc-v4 .hc-k3{color:#f9a825} .hc-v4 .hc-k4{color:#d32f2f} .hc-v4 .hc-k5{color:#2e7d32}
.hc-v5 .hc-k0{color:#7b1fa2} .hc-v5 .hc-k1{color:#2e7d32} .hc-v5 .hc-k2{color:#1565c0} .hc-v5 .hc-k3{color:#212121} .hc-v5 .hc-k4{color:#f9a825} .hc-v5 .hc-k5{color:#d32f2f}
/* LA LIBRAIRIE (2026-10-16) : texte complet d'un prompt, d'un contexte ou d'un playbook (fenêtre #librairie-fiche). */
.librairie-texte {
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 65vh;
  overflow: auto;
  font-size: .8125rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: .375rem;
  padding: .75rem;
}

/* ===== Position des notifications flash (Réglages → Personnalisation, App\Support\Branding\ToastPosition) =====
   Toute pile de toasts porte .us-toast-stack ; la classe us-toast-pos-<position> de <html> la place.
   Défaut (aucune classe, ou top-center) : en haut au centre, sous la barre du haut. */
.us-toast-stack {
  position: fixed;
  z-index: 1100;
  top: 0;
  left: 50%;
  right: auto;
  bottom: auto;
  transform: translateX(-50%);
  margin-top: 4.5rem;
  max-width: calc(100vw - 1rem);
}

.us-toast-pos-top-start .us-toast-stack,
.us-toast-pos-bottom-start .us-toast-stack {
  left: 0;
  right: auto;
  transform: none;
}

.us-toast-pos-top-end .us-toast-stack,
.us-toast-pos-bottom-end .us-toast-stack {
  left: auto;
  right: 0;
  transform: none;
}

.us-toast-pos-bottom-start .us-toast-stack,
.us-toast-pos-bottom-center .us-toast-stack,
.us-toast-pos-bottom-end .us-toast-stack {
  top: auto;
  bottom: 0;
  margin-top: 0;
}

/* ============ TABLEAUX EMPILÉS (2026-10-18) ============
   Classe posée par assets_all/table-stack.js sur un tableau qui déborde de son bloc, sous 1400 px :
   chaque ligne devient une fiche, chaque cellule « libellé de colonne : valeur ». Exclure un tableau : `.us-no-stack`. */
.table.us-table-stacked { display: block !important; min-width: 0 !important; width: 100% !important; }
/* `display: block` et le retour à la ligne forcé sur TOUT le contenu (18/10/2026, SpiderAgent > Playbooks) : resté
   en `display: table`, un tableau garde la largeur de son mot le plus long. Un identifiant dans un <code> (Bootstrap :
   `word-wrap: break-word`, qui ne réduit pas la largeur minimale) faisait déborder la fiche de 190 px sur mobile. */
.table.us-table-stacked > * > tr > * * { overflow-wrap: anywhere; max-width: 100%; }
.table.us-table-stacked > thead { display: none; }
.table.us-table-stacked > tbody,
.table.us-table-stacked > tfoot { display: block; width: 100%; }
.table.us-table-stacked > tbody > tr:not(.collapse):not(.collapsing),
.table.us-table-stacked > tbody > tr.collapse.show,
.table.us-table-stacked > tfoot > tr {
  display: block;
  width: 100%;
  margin-bottom: .5rem;
  padding: .25rem .75rem;
  border: 1px solid var(--bs-border-color);
  border-radius: .5rem;
}
.table.us-table-stacked > tbody > tr > td,
.table.us-table-stacked > tbody > tr > th,
.table.us-table-stacked > tfoot > tr > td,
.table.us-table-stacked > tfoot > tr > th {
  display: block;
  width: 100% !important;
  padding: .3rem 0 !important;
  border: 0 !important;
  text-align: right !important;
  white-space: normal !important;
  overflow-wrap: anywhere;
}
.table.us-table-stacked > tbody > tr > *:not(:last-child),
.table.us-table-stacked > tfoot > tr > *:not(:last-child) { border-bottom: 1px dashed var(--bs-border-color) !important; }
.table.us-table-stacked > tbody > tr > *::before,
.table.us-table-stacked > tfoot > tr > *::before {
  content: attr(data-us-label);
  float: left;
  width: 40%;
  padding-right: .75rem;
  font-weight: 600;
  text-align: left;
  color: var(--bs-secondary-color);
}
.table.us-table-stacked > * > tr > [data-us-label=""]::before,
.table.us-table-stacked > * > tr > :not([data-us-label])::before { display: none; }
/* Le libellé flotte à gauche, la valeur s'aligne à droite et garde ses retours à la ligne (<br>, <small>). */
.table.us-table-stacked > * > tr > *::after { content: ""; display: block; clear: both; }

/* ============ BARRE DU HAUT DÉFILANTE SUR MOBILE ET TABLETTE (2026-10-18, demande de Philippe) ============
   Sous 1200 px, les icônes (18 sur fifi.fr) débordaient de l'écran sans moyen d'atteindre les dernières : la rangée
   défile horizontalement au doigt, sans ascenseur visible. Les menus ne sont pas coupés : sous 1200 px leurs icônes
   sont en `position: static`, le menu se place par rapport à la barre (fixe), hors de la rangée qui défile.
   Hors barre intégrée à LauncherLauncher (#us-navbar-embed), qui a ses propres règles. */
@media (max-width: 1199.98px) {
  html:not(:has(#us-navbar-embed)) .layout-navbar .navbar-nav-right { min-width: 0; flex: 1 1 auto; }
  html:not(:has(#us-navbar-embed)) .layout-navbar .navbar-nav-right > .navbar-nav {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    max-width: 100%;
    min-width: 0;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  html:not(:has(#us-navbar-embed)) .layout-navbar .navbar-nav-right > .navbar-nav::-webkit-scrollbar { display: none; }
  html:not(:has(#us-navbar-embed)) .layout-navbar .navbar-nav-right > .navbar-nav > .nav-item { flex: 0 0 auto; }
}
