/* ═══════════════════════════════════════════════════════════════════
   TTS Studio — compléments à webint.css
   Créé le 16/10/2026.

   Ne contient QUE les composants propres à l'application, absents de la
   charte : onglets, formulaire de synthèse, lecteur audio, zone de
   dépôt, notifications, fenêtres modales, pied de page RGPD.

   Toutes les couleurs passent par les variables de webint.css : aucune
   valeur chromatique en dur, afin que le site suive la charte si elle
   évolue.

   Noms de classes imposés par le JavaScript de index.html, à ne jamais
   renommer : active, hidden, open, drag-over, .modal-bg, .tab-btn,
   .tab-panel, [data-section], .badge-actif, .badge-inactif.
   ═══════════════════════════════════════════════════════════════════ */


/* ── 1. PAGES D'AUTHENTIFICATION ─────────────────────────────────── */
/* Équivalent neutre de .paris-emblem : l'identité du portail d'origine
   n'a pas à figurer ici. Mêmes valeurs que la charte. */
.auth-logo { font-size: 40px; margin-bottom: 12px; }


/* ── 2. RÔLES ────────────────────────────────────────────────────── */
/* webint définit .user-badge.admin et .user-badge.lecteur ; tts3 utilise
   les rôles « admin » et « user ».

   La même étiquette sert dans la navbar (fond bleu foncé) et dans le
   tableau des utilisateurs (fond blanc). « admin » est une pastille rouge
   pleine, lisible sur les deux. « user », en revanche, demande deux
   variantes : la version translucide de la charte disparaîtrait sur fond
   blanc. La règle de navbar est plus spécifique, elle l'emporte donc. */
.user-badge.user { background: var(--paris-blue-light); color: var(--paris-blue); }
.nav-user .user-badge.user { background: rgba(255, 255, 255, .2); color: var(--white); }


/* ── 3. TABLEAU DE BORD ──────────────────────────────────────────── */
/* Trois colonnes : activités récentes, accès rapides, maintenance.
   Se replie à 2 puis 1 colonne, comme .section-grid de la charte. */
/* align-items par défaut (stretch) : les trois cartes partagent la même
   hauteur et leur bas s'aligne, ce qui évite le décrochage visuel juste
   au-dessus du pied de page. */
.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 18px;
}
.dashboard-grid > .card { display: flex; flex-direction: column; }
.dashboard-grid > .card > .card-body { flex: 1; }

/* .quick-links et .quick-link viennent de la charte ; il manque la
   disposition interne icône + libellé. */
.quick-icon { font-size: 22px; flex: none; }
.quick-link strong { display: block; font-size: 14px; font-weight: 700; }
.quick-link small { display: block; font-size: 12px; color: var(--text-muted); margin-top: 1px; }

/* Un tableau logé dans .card-body--flush ne doit pas ajouter sa propre
   bordure, la carte la porte déjà. */
.table-wrap--plat { border: none; border-radius: 0; }


/* ── 3 ter. RESSOURCES DE LA MACHINE ─────────────────────────────── */
.separateur {
  border-top: 1px solid var(--border);
  margin: 16px 0 14px;
}
.systeme-entete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.systeme-entete h4 {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .5px;
}

.mesure { margin-bottom: 14px; }
.mesure-tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 4px;
}
.mesure-nom { font-size: 13px; font-weight: 600; color: var(--text); }
.mesure-pct { font-size: 13px; font-weight: 700; color: var(--paris-blue); }
.mesure-detail { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.mesure-detail strong { color: var(--text); font-weight: 600; }

/* Jauge : la couleur passe à l'orange puis au rouge selon le remplissage,
   pour qu'un disque qui se remplit saute aux yeux sans lire le chiffre. */
.jauge {
  height: 6px;
  background: var(--border);
  border-radius: 99px;
  overflow: hidden;
}
.jauge > span {
  display: block;
  height: 100%;
  background: var(--paris-blue);
  border-radius: 99px;
  transition: width .3s;
}
.jauge > span.jauge--orange { background: var(--orange); }
.jauge > span.jauge--rouge  { background: var(--red); }

.mesure-liste {
  border-top: 1px solid var(--border);
  padding-top: 10px;
  margin-top: 4px;
}
.mesure-liste > div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 12px;
  padding: 3px 0;
}
.mesure-liste span { color: var(--text-muted); }
.mesure-liste strong { color: var(--text); font-weight: 600; }


/* ── 3 bis. PAGINATION ───────────────────────────────────────────── */
/* .pagination, .page-btn et .page-info viennent de la charte, qui les
   prévoit en liens <a>. Ici la pagination est pilotée en JavaScript :
   il faut donc les compléments propres au <button>. */
button.page-btn {
  font-family: inherit;
  cursor: pointer;
  transition: background .15s, opacity .15s;
}
button.page-btn:disabled {
  opacity: .4;
  cursor: not-allowed;
  color: var(--text-muted);
}
button.page-btn:disabled:hover { background: var(--white); }

/* Sélecteur « lignes par page » rendu compact, à droite de la pagination */
.pagination .page-taille {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  color: var(--text-muted);
}
.pagination .page-taille select {
  padding: 5px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-family: inherit;
  font-size: 13px;
  background: var(--white);
  color: var(--text);
}

@media (max-width: 600px) {
  .pagination { flex-wrap: wrap; gap: 8px; }
  .page-btn { padding: 7px 11px; }
}


/* ── 5. FORMULAIRES ──────────────────────────────────────────────── */
.field { margin-bottom: 16px; }
.field label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 5px;
  color: var(--text-muted);
}
.app-layout select,
.app-layout textarea,
.app-layout input[type="text"],
.app-layout input[type="email"],
.app-layout input[type="password"],
.app-layout input[type="number"],
.modal select,
.modal input {
  width: 100%;
  padding: 9px 12px;
  background: var(--white);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  transition: border-color .15s, box-shadow .15s;
}
.app-layout select:focus,
.app-layout textarea:focus,
.app-layout input:focus,
.modal select:focus,
.modal input:focus {
  outline: none;
  border-color: var(--paris-blue);
  box-shadow: 0 0 0 3px rgba(0, 49, 137, .1);
}
.app-layout textarea { resize: vertical; min-height: 110px; }
.char-count { font-size: 12px; color: var(--text-muted); text-align: right; margin-top: 3px; }

/* Grille 2 colonnes, repliée sous 600px comme la charte */
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }


/* ── 6. SÉLECTEUR DE LANGUE ──────────────────────────────────────── */
.lang-selector { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.lang-btn {
  padding: 7px 16px;
  border-radius: var(--radius);
  border: 1.5px solid var(--border);
  background: var(--white);
  color: var(--text-muted);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all .15s;
}
.lang-btn:hover { border-color: var(--paris-blue); color: var(--text); }
.lang-btn.active {
  background: var(--paris-blue);
  border-color: var(--paris-blue);
  color: var(--white);
}


/* ── 7. CURSEURS ET INTERRUPTEUR ─────────────────────────────────── */
.slider-row { display: flex; align-items: center; gap: 12px; }
.slider-row input[type="range"] {
  flex: 1;
  height: 6px;
  padding: 0;
  cursor: pointer;
  accent-color: var(--paris-blue);
}
.slider-val {
  min-width: 56px;
  text-align: right;
  font-size: 13px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.toggle-row { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.switch { position: relative; display: inline-block; width: 44px; height: 24px; flex: none; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider-switch {
  position: absolute;
  inset: 0;
  background: var(--border);
  border-radius: 99px;
  cursor: pointer;
  transition: background .2s;
}
.slider-switch::before {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  left: 3px;
  top: 3px;
  background: var(--white);
  border-radius: 50%;
  transition: transform .2s;
}
.switch input:checked + .slider-switch { background: var(--paris-blue); }
.switch input:checked + .slider-switch::before { transform: translateX(20px); }
.toggle-label { font-size: 14px; font-weight: 600; cursor: pointer; }


/* ── 8. ZONE DE DÉPÔT DE FICHIER ─────────────────────────────────── */
.dropzone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  padding: 20px;
  text-align: center;
  cursor: pointer;
  transition: border-color .2s, color .2s, background .2s;
  color: var(--text-muted);
  font-size: 13px;
}
.dropzone:hover,
.dropzone.drag-over {
  border-color: var(--paris-blue);
  color: var(--text);
  background: var(--paris-blue-light);
}
.dropzone-icon { font-size: 24px; margin-bottom: 6px; }
.dropzone small { display: block; margin-top: 5px; font-size: 12px; }
.file-selected { font-size: 13px; font-weight: 600; color: var(--green); margin-top: 6px; }


/* ── 9. BOUTONS ──────────────────────────────────────────────────── */
/* .btn-primary de la charte fait 100% de large : adapté aux cartes de
   connexion, pas aux boutons d'action dans l'application. On repasse en
   largeur automatique uniquement dans .app-layout et les modales. */
.app-layout .btn-primary,
.modal .btn-primary {
  width: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 20px;
  font-size: 14px;
}
.btn-primary:disabled { opacity: .5; cursor: not-allowed; }
.btn-primary:disabled:hover { background: var(--paris-blue); }

/* Bouton secondaire : contour, non défini en largeur par la charte */
.app-layout .btn-secondary,
.modal .btn-secondary {
  background: var(--white);
  color: var(--text);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  padding: 9px 18px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: all .15s;
}
.app-layout .btn-secondary:hover,
.modal .btn-secondary:hover {
  border-color: var(--paris-blue);
  color: var(--paris-blue);
}

/* Bouton réduit, pour les colonnes d'actions des tableaux */
.btn-compact { padding: 4px 10px !important; font-size: 12px !important; }

/* .btn-danger de la charte est un fond pâle ; ici bouton de suppression
   à contour, plus lisible dans un tableau dense. */
.app-layout .btn-danger {
  background: var(--white);
  color: var(--red);
  border: 1px solid var(--red);
  border-radius: var(--radius);
  padding: 5px 12px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all .15s;
}
.app-layout .btn-danger:hover { background: var(--red); color: var(--white); }


/* ── 10. RÉSULTAT AUDIO ──────────────────────────────────────────── */
.result-box {
  background: #d1fae5;
  border-left: 3px solid var(--green);
  border-radius: 6px;
  padding: 16px;
  margin-top: 20px;
}
.result-box .result-title { font-weight: 700; color: #065f46; margin-bottom: 12px; }
.result-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 12px; }
.app-layout audio { width: 100%; }


/* ── 11. INDICATEUR D'ATTENTE ────────────────────────────────────── */
.spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: var(--white);
  border-radius: 50%;
  animation: tts3-spin .7s linear infinite;
}
@keyframes tts3-spin { to { transform: rotate(360deg); } }

/* Variante pour un bouton clair : le blanc y serait invisible. */
.spinner--sombre {
  border-color: rgba(0, 49, 137, .25);
  border-top-color: var(--paris-blue);
}


/* ── 12. MESSAGES ────────────────────────────────────────────────── */
/* Noms conservés (le JS les cible par id) mais apparence alignée sur
   .alert-error et .info-banner de la charte. */
.msg-erreur {
  background: #fee2e2;
  color: #991b1b;
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 12px 16px;
  font-size: 13px;
  margin-top: 16px;
}
.msg-info {
  background: var(--paris-blue-light);
  color: var(--paris-blue-dark);
  border-left: 3px solid var(--paris-blue);
  border-radius: 6px;
  padding: 12px 16px;
  font-size: 13px;
}


/* ── 13. NOTIFICATION FLOTTANTE ──────────────────────────────────── */
#toast {
  position: fixed;
  top: 76px;                        /* sous la navbar sticky (60px) */
  left: 50%;
  transform: translateX(-50%);
  background: var(--green);
  color: var(--white);
  padding: 12px 24px;
  border-radius: var(--radius);
  font-size: 14px;
  font-weight: 600;
  z-index: 2000;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .25);
  transition: opacity .3s;
  pointer-events: none;
}
#toast.toast-error { background: var(--red); }
#toast.hidden { opacity: 0; }


/* ── 14. STATISTIQUES ────────────────────────────────────────────── */
/* .stats-grid et .stat-card viennent de la charte ; tts3 nomme ses
   valeurs .stat-val / .stat-lbl là où webint utilise -value / -label.
   Cartes volontairement compactes : la hauteur du bandeau de chiffres
   ne doit pas repousser le contenu utile sous la ligne de flottaison. */
.app-layout .stats-grid {
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}
/* Bandeau de chiffres volontairement bas : valeur et libellé sur une
   seule ligne, ce qui divise la hauteur de la carte par deux (environ
   74px auparavant, 38px ici) et remonte d'autant le contenu utile. */
.app-layout .stat-card {
  padding: 7px 14px;
  display: flex;
  align-items: baseline;
  gap: 10px;
  border-top-width: 2px;
}
.stat-val { font-size: 19px; font-weight: 800; color: var(--paris-blue); line-height: 1.2; }
.stat-lbl {
  font-size: 11px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .5px;
  line-height: 1.2;
}

/* ── 14 bis. DENSITÉ GÉNÉRALE ────────────────────────────────────── */
/* L'en-tête de page de la charte réserve 24px ; on resserre, la navbar
   assurant déjà la séparation visuelle. */
.app-layout { padding: 20px 24px; }
.app-layout .page-header { margin-bottom: 18px; }
.app-layout .page-header h2 { font-size: 20px; }
/* Le « > » est indispensable : sans lui la règle frappe aussi les cartes
   sœurs d'une grille (.dashboard-grid), qui se retrouvent décalées vers
   le bas les unes par rapport aux autres. */
.app-layout > .card + .card { margin-top: 18px; }
.app-layout .card-header { padding: 12px 18px; }
.app-layout .card-body { padding: 14px 18px; }


/* ── 15. TABLEAU DES UTILISATEURS ────────────────────────────────── */
/* Équivalent de .table-scroll de la charte, nom conservé. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.table-wrap table { width: 100%; border-collapse: collapse; font-size: 13px; }
.table-wrap th {
  background: var(--bg);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .5px;
  padding: 10px 14px;
  text-align: left;
  white-space: nowrap;
}
.table-wrap td { padding: 9px 14px; border-top: 1px solid var(--border); vertical-align: middle; }
.table-wrap tbody tr:hover td { background: var(--paris-blue-light); }

/* Nom d'hôte résolu, affiché sous l'adresse IP */
.ip-hote {
  display: block;
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: 11px;
  color: var(--text-muted);
  max-width: 230px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ip-hote:empty { display: none; }

/* Localisation approximative, affichée sous le nom d'hôte. Teinte distincte
   du nom d'hôte : l'un est une donnée DNS vérifiable, l'autre une estimation. */
.ip-lieu {
  display: block;
  font-family: 'Segoe UI', system-ui, sans-serif;
  font-size: 11px;
  color: var(--primary, #4f46e5);
  opacity: .75;
  max-width: 230px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ip-lieu:empty { display: none; }

/* Pages Historique et Tentatives : adresse, nom d'hôte et localisation sur
   une seule ligne. Le conteneur .table-wrap gère le débordement horizontal,
   le nowrap ne casse donc pas la mise en page. */
.ip-une-ligne { white-space: nowrap; }

.ip-une-ligne .ip-hote,
.ip-une-ligne .ip-lieu {
  display: inline;
  max-width: none;
}
.ip-une-ligne .ip-hote:empty,
.ip-une-ligne .ip-lieu:empty { display: none; }

/* Séparateur porté par le CSS et non par le JS : une case encore vide, le
   temps que la résolution arrive, n'affiche pas de point isolé. */
.ip-une-ligne .ip-hote:not(:empty)::before,
.ip-une-ligne .ip-lieu:not(:empty)::before {
  content: " · ";
  opacity: .45;
}

/* Badges d'état produits par le JS */
.badge-actif,
.badge-inactif {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
}
.badge-actif   { background: #d1fae5; color: var(--green); }
.badge-inactif { background: #fee2e2; color: var(--red); }


/* ── 16. FENÊTRES MODALES ────────────────────────────────────────── */
/* .open est posé/retiré par le JS : ne pas renommer. */
.modal-bg {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 16px;
}
.modal-bg.open { display: flex !important; }
.modal {
  background: var(--white);
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
  padding: 28px;
  width: 100%;
  max-width: 440px;
}
.modal-title {
  font-size: 17px;
  font-weight: 700;
  color: var(--paris-blue);
  margin-bottom: 20px;
}
.modal .field label { color: var(--text); font-size: 13px; }
.modal-actions { display: flex; gap: 12px; justify-content: flex-end; margin-top: 20px; }


/* ── 17. PIED DE PAGE RGPD ───────────────────────────────────────── */
/* Plus développé que le .footer de la charte (mentions réglementaires),
   mais sur le même bleu foncé. */
.footer-rgpd {
  background: var(--paris-blue-dark);
  color: rgba(255, 255, 255, .55);
  padding: 22px 24px;
  font-size: 13px;
  line-height: 1.55;
}
.footer-inner { max-width: 1800px; margin: 0 auto; }
.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 22px;
  margin-bottom: 16px;
}
.footer-col h4 {
  font-size: 13px;
  font-weight: 700;
  color: var(--white);
  margin-bottom: 10px;
}
.footer-col p,
.footer-col li { font-size: 12px; }
.footer-col ul { list-style: none; }
.footer-col ul li { padding: 2px 0; }
.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, .15);
  padding-top: 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: space-between;
  font-size: 12px;
}
.rgpd-badge {
  background: rgba(255, 255, 255, .15);
  color: var(--white);
  padding: 3px 10px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 700;
}


/* ── 18. ADAPTATIF ───────────────────────────────────────────────── */
/* Points de rupture alignés sur ceux de la charte (900 / 600). */
@media (max-width: 900px) {
  .tabs-bar { padding: 0 16px; }
}
@media (max-width: 600px) {
  .grid2 { grid-template-columns: 1fr; }
  .tab-btn { padding: 12px 14px; font-size: 13px; }
  .footer-rgpd { padding: 24px 16px; }
  .modal { padding: 20px; }
}

/* Attribution de la base de géolocalisation, exigée par sa licence CC BY 4.0.
   Discrète mais présente : l'omettre nous mettrait en défaut. */
.attribution-donnees {
  display: block;
  margin-top: .4rem;
  font-size: .72rem;
  opacity: .7;
}
.attribution-donnees a { color: inherit; }
