/* =============================================
   FAISTATV — CSS personnalisé

   Seul fichier de style écrit à la main, et seul fichier d'assets versionné :
   tout le reste d'assets/ vient de la distribution Zynix et est provisionné
   hors git.

   Il se charge après styles.css, donc il surcharge le thème sans avoir
   besoin de !important. Y ajouter toute règle maison plutôt que de la
   glisser dans un <style> de page : c'est ce qui avait fini par créer deux
   versions divergentes de ce fichier.

   ---------------------------------------------------------------
   Règle d'écriture : passer par les variables du thème, jamais par
   une couleur en dur.

   C'est ce qui garantit que le CSS maison et les composants Zynix parlent
   de la même couleur. Une valeur recopiée à la main finit toujours par
   dériver de sa source.

   | Variable                  | Rôle                          |
   |---------------------------|-------------------------------|
   | rgb(var(--primary-rgb))   | l'accent violet du produit    |
   | var(--custom-white)       | fond des surfaces (cartes)    |
   | var(--default-border)     | filets et bordures            |
   | var(--default-text-color) | texte courant                 |
   | var(--text-muted)         | texte secondaire              |
   | rgb(var(--light-rgb))     | fond de survol                |

   Le projet employait #6366f1 — l'indigo de Tailwind — proche mais distinct
   du #735DFF du thème : l'interface affichait deux violets voisins côte à
   côte. Il n'en reste que les palettes catégorielles, où le violet désigne une
   catégorie parmi d'autres et non l'accent du produit.
============================================= */

/* Espacement fil d'ariane + titre */
.page-header-breadcrumb {
    padding-top: 1.5rem;
    padding-bottom: 1rem;
}
.page-header-breadcrumb .breadcrumb {
    margin-bottom: 0.4rem;
}
.page-header-breadcrumb .page-title {
    line-height: 1.3;
}

/* Onglets — commutateur segmenté
   Ils suivaient le modèle classique de l'onglet raccordé : le sélectionné prend
   le fond blanc de la zone de contenu. Or la page est gris très clair
   (245,246,250) et ce blanc s'y détache à 1,08:1 — l'onglet choisi disparaissait
   purement et simplement. Les inactifs, en --text-muted, sortaient à 2,29:1.

   D'où un modèle qui ne peut pas s'effacer : un boîtier blanc cerné, posé sur
   la page grise, et le segment actif rempli.

   Le remplissage est la couleur primaire ramenée à 88 %, pour que le blanc s'y
   lise à 5,47:1 — à 100 % il n'atteint que 4,43:1, sous le seuil. La valeur est
   dérivée de la variable du thème, pas recopiée : color-mix la calcule, et la
   déclaration précédente sert de repli aux navigateurs qui l'ignorent. */
.nav-tabs {
    border-bottom: 0;
    gap: 4px;
    display: inline-flex;
    flex-wrap: wrap;
    background: var(--custom-white);
    border: 1px solid var(--default-border);
    border-radius: 12px;
    padding: 4px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.nav-tabs .nav-link {
    font-size: 0.9rem;
    font-weight: 500;
    padding: 0.55rem 1.1rem;
    color: var(--default-text-color);
    border: 0;
    border-radius: 9px;
    background: transparent;
    transition: background 0.15s, color 0.15s;
}
.nav-tabs .nav-link:hover:not(.active) {
    background: rgba(var(--primary-rgb), 0.1);
    color: rgb(var(--primary-rgb));
}
.nav-tabs .nav-link.active {
    font-weight: 600;
    color: #fff;
    background: rgb(var(--primary-rgb));
    background: color-mix(in srgb, rgb(var(--primary-rgb)) 88%, #000);
}
.nav-tabs .nav-link.active .badge {
    background: rgba(255, 255, 255, 0.22) !important;
    color: #fff !important;
}
.nav-tabs .nav-link .badge {
    font-size: 0.7rem;
}

/* Cartes légèrement plus aérées */
.custom-card .card-header {
    padding: 0.9rem 1.25rem;
    border-bottom: 1px solid var(--default-border);
}

/* Boutons d'action dans les tableaux */
.btn-xs {
    padding: 0.2rem 0.5rem;
    font-size: 0.75rem;
}

/* =============================================
   Menu latéral

   Les !important viennent du thème, dont les sélecteurs sont plus
   spécifiques que ceux-ci. Ils sont conservés tels quels : les retirer
   demanderait de réécrire les sélecteurs, ce qui changerait le rendu.

   --- Lisibilité ---
   Le thème pose les libellés en #657a99, soit un contraste de 4,38:1 sur le
   blanc du menu. Le seuil de la norme est de 4,5:1 pour du texte de cette
   taille : on passait juste en dessous, et cela se voyait. Les titres de
   catégorie, écrits dans la couleur primaire, tombaient à 4,43:1 pour des
   capitales de 0,68rem — le pire cas de la page.

   La correction passe par var(--default-text-color), la couleur de texte du
   thème — 13,74:1 — plutôt que par une teinte choisie à l'œil : c'est la règle
   d'écriture de ce fichier, et elle vaut ici comme ailleurs.

   L'accent violet reste, mais sur ce qui n'est pas du texte : le repère de
   l'entrée active et son icône. En couleur de police il ne donne que 4,43:1,
   sous le seuil ; comme élément d'interface, le seuil est de 3:1 et il passe.
============================================= */

/* Couleur des libellés et des icônes, qui héritent par currentColor */
.side-menu__item {
    color: var(--default-text-color) !important;
}
.side-menu__item .side-menu__label {
    color: var(--default-text-color) !important;
    font-weight: 500 !important;
}

/* Titres de catégories */
.slide__category {
    margin-top: 1rem !important;
    margin-bottom: 0.2rem !important;
}
.slide__category .category-name {
    display: flex !important;
    align-items: center !important;
    gap: 8px !important;
    font-size: 0.68rem !important;
    font-weight: 700 !important;
    letter-spacing: 0.1em !important;
    text-transform: uppercase !important;
    /* Le tiret coloré porte l'accent ; le texte, lui, doit se lire. */
    color: var(--default-text-color) !important;
    padding: 2px 16px !important;
    opacity: 1 !important;
}
.slide__category .category-name::before {
    content: '';
    display: inline-block;
    width: 16px;
    height: 2px;
    background: rgb(var(--primary-rgb));
    border-radius: 2px;
    flex-shrink: 0;
}

/* Survol des entrées de menu */
.side-menu__item {
    border-radius: 8px !important;
    margin: 2px 8px !important;
    transition: background 0.15s, color 0.15s, transform 0.1s !important;
}
.side-menu__item:hover {
    background: rgba(var(--primary-rgb), 0.12) !important;
    color: rgb(var(--primary-rgb)) !important;
    transform: translateX(3px) !important;
}
.side-menu__item:hover .side-menu__label {
    color: rgb(var(--primary-rgb)) !important;
}
.side-menu__item:hover svg {
    stroke: rgb(var(--primary-rgb)) !important;
    color: rgb(var(--primary-rgb)) !important;
}

/* Entrée active
   Elle ne se distinguait que par un fond teinté à 15 %, sans autre signe : on
   ne voyait pas d'un coup d'œil où l'on se trouvait. Trois marques cumulées —
   le fond, un repère à gauche, le libellé coloré et épaissi — au lieu d'une
   seule, à peine perceptible. */
.slide.active .side-menu__item {
    background: rgba(var(--primary-rgb), 0.14) !important;
    box-shadow: inset 3px 0 0 rgb(var(--primary-rgb)) !important;
}
.slide.active .side-menu__item .side-menu__label {
    color: var(--default-text-color) !important;
    font-weight: 600 !important;
}
/* L'icône, elle, n'est pas du texte : elle peut porter le violet du produit. */
.slide.active .side-menu__item svg {
    stroke: rgb(var(--primary-rgb)) !important;
    color: rgb(var(--primary-rgb)) !important;
}
/* Le survol ne déplace pas l'entrée courante : elle est déjà à sa place. */
.slide.active .side-menu__item:hover {
    transform: none !important;
}

/* Bloc de profil, au bas du menu
   Il était écrit en style en ligne, et c'était l'endroit le moins lisible de
   l'interface : le rôle sortait à 2,05:1 et les deux icônes à 2,22:1, quand le
   seuil est de 4,5:1 pour du texte et de 3:1 pour un élément. En cause, des
   opacités de 0,55 et 0,6 empilées sur une couleur déjà pâle.

   Deux bordures étaient par ailleurs en blanc translucide — rgba(255,255,255,…)
   — sur le fond blanc du menu : le filet de séparation et l'anneau de l'avatar
   n'existaient pas à l'écran. */
.menu-profil {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 12px 16px;
    border-top: 1px solid var(--default-border);
    background: var(--menu-bg);
    z-index: 10;
}
.menu-profil__avatar {
    text-decoration: none;
}
.menu-profil__avatar img,
.menu-profil__avatar span {
    width: 36px;
    height: 36px;
    border-radius: 50%;
}
.menu-profil__avatar img {
    object-fit: cover;
    border: 2px solid var(--default-border);
}
.menu-profil__avatar span {
    background: rgb(var(--primary-rgb));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 600;
    font-size: 13px;
}
.menu-profil__nom {
    color: var(--default-text-color);
}
.menu-profil__role {
    /* 2,05:1 auparavant. Le rôle est une information, pas un filigrane. */
    color: var(--default-text-color);
    opacity: 0.7;
}
.menu-profil__action {
    color: var(--default-text-color);
    opacity: 0.75;
    padding: 4px;
    border-radius: 6px;
    transition: background 0.15s, opacity 0.15s, color 0.15s;
}
.menu-profil__action:hover,
.menu-profil__action:focus-visible {
    opacity: 1;
    background: rgba(var(--primary-rgb), 0.1);
    color: rgb(var(--primary-rgb));
}
.menu-profil__action--sortie:hover,
.menu-profil__action--sortie:focus-visible {
    background: rgba(var(--danger-rgb), 0.12);
    color: rgb(var(--danger-rgb));
}

/* =============================================
   Vidéothèque templates
============================================= */

/* La carte d'un template inactif portait « opacity-60 », qui n'existe dans
   aucune des feuilles chargées : Bootstrap s'arrête à 25, 50, 75 et 100. Rien
   n'était donc grisé, et seul le badge « Inactif » distinguait la fiche. */
.tpl-inactif {
    opacity: 0.6;
}

/* Bouton de lecture au centre de l'aperçu. Les deux emplacements qui le
   portent répétaient chacun la même déclaration en ligne, plus deux gestes de
   survol écrits en JavaScript dans onmouseover/onmouseout. */
.tpl-play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 52px;
    height: 52px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.6);
    border: 2px solid rgba(255, 255, 255, 0.8);
    border-radius: 50%;
    cursor: pointer;
    z-index: 5;
    transition: background 0.2s, border-color 0.2s;
}
.tpl-play:hover,
.tpl-play:focus-visible {
    background: rgba(var(--primary-rgb), 0.85);
    border-color: rgb(var(--primary-rgb));
}
.tpl-play i {
    color: #fff;
    font-size: 20px;
    margin-left: 3px;
}

/* =============================================
   Carte du réseau
============================================= */

/* Les lignes de la liste étaient des div cliquables, avec leur survol écrit
   dans deux attributs onmouseover. Devenues des boutons, elles s'atteignent au
   clavier ; il faut en revanche défaire l'habillage par défaut. */
.site-list-item {
    background: none;
    border: 0;
    border-bottom: 1px solid var(--default-border, #e9ecef);
    cursor: pointer;
    transition: background 0.15s;
}
.site-list-item:hover,
.site-list-item:focus-visible {
    background: rgba(var(--primary-rgb), 0.06);
}
.site-list-logo {
    width: 38px;
    height: 38px;
    border-radius: 8px;
    object-fit: cover;
    flex-shrink: 0;
}
.site-list-avatar {
    background: linear-gradient(135deg, #10b981, #059669);
    color: #fff;
}
/* Le dégradé partait de l'indigo vers un violet plus clair. Il part
   maintenant du violet du thème vers une version assombrie — même sens que
   le vert ci-dessus, et les initiales blanches y restent lisibles. */
.site-list-avatar.est-mien {
    background: linear-gradient(135deg,
                rgb(var(--primary-rgb)),
                color-mix(in srgb, rgb(var(--primary-rgb)) 75%, #000));
}

/* Bulle d'un marqueur. Tout cela était écrit en style en ligne, dans une
   chaîne HTML montée en JavaScript. */
.carte-popup { min-width: 210px; }
.carte-popup-entete {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}
.carte-popup-entete strong { font-size: 14px; }
.carte-popup-logo {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    object-fit: cover;
}
.carte-popup-avatar {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    background: #10b981;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 14px;
}
.carte-popup-avatar.est-mien { background: rgb(var(--primary-rgb)); }
.carte-popup-cat { color: #888; font-size: 12px; }
.carte-popup-lieu {
    font-size: 12px;
    color: #666;
    margin-bottom: 8px;
}
.carte-popup-lieu i { margin-right: 4px; }
.carte-popup-chiffres {
    display: flex;
    gap: 12px;
    margin-bottom: 10px;
    padding: 8px 0;
    border-top: 1px solid #eee;
    border-bottom: 1px solid #eee;
}
.carte-popup-chiffres > div { text-align: center; flex: 1; }
.carte-popup-chiffres strong { font-size: 16px; }
.carte-popup-chiffres div div { font-size: 11px; color: #888; }
.carte-popup-chiffres .text-vert   { color: #10b981; }
.carte-popup-chiffres .text-violet { color: rgb(var(--primary-rgb)); }
.carte-popup-btn {
    width: 100%;
    padding: 7px;
    margin-top: 6px;
    background: rgb(var(--primary-rgb));
    color: #fff;
    border: 0;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    font-weight: 500;
}
.carte-popup-btn:first-of-type { margin-top: 0; }
.carte-popup-btn:hover { filter: brightness(1.1); }
.carte-popup-btn i { margin-right: 4px; }
.carte-popup-client {
    font-size: 11px;
    color: #aaa;
    margin-top: 6px;
}

.fiche-avatar-logo {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    object-fit: cover;
}
.fiche-avatar {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: linear-gradient(135deg, #10b981, #059669);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 16px;
    flex-shrink: 0;
}
.fiche-avatar i { font-size: 22px; }

/* =============================================
   Réseau du commerçant — onglet Carte
============================================= */
#carteReseau {
    height: 560px;
    width: 100%;
    border-radius: 0.5rem;
}
.carte-marqueur {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 3px solid #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 15px;
    cursor: pointer;
}
.carte-legende {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--default-text-color);
}
.carte-pastille {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    display: inline-block;
    flex-shrink: 0;
}
.carte-pastille.est-mien       { background: rgb(var(--primary-rgb)); }
.carte-pastille.est-partenaire { background: #0ea5e9; }
.carte-pastille.est-attente    { background: #f59e0b; }
.carte-pastille.est-decouvrir  { background: #10b981; }
.carte-popup-relation {
    font-size: 12px;
    font-weight: 600;
    margin-top: 6px;
}
#carteResume .carte-pastille {
    width: 12px;
    height: 12px;
}

/* =============================================
   Vidéothèque du commerçant
============================================= */

/* La vignette entière est le bouton d'ouverture : le rond de lecture était
   posé par-dessus sans être relié à quoi que ce soit, et cliquer ne faisait
   rien. */
.media-vignette {
    position: relative;
    display: block;
    width: 100%;
    height: 160px;
    padding: 0;
    border: 0;
    border-radius: 0.5rem 0.5rem 0 0;
    overflow: hidden;
    background: #111827;
    cursor: pointer;
}
.media-vignette img,
.media-vignette video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.media-vignette--vide {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgb(var(--light-rgb));
    color: var(--text-muted);
    cursor: default;
}
.media-vignette__loupe {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    border: 2px solid rgba(255, 255, 255, 0.85);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 19px;
    transition: background 0.15s, transform 0.15s;
}
.media-vignette:hover .media-vignette__loupe,
.media-vignette:focus-visible .media-vignette__loupe {
    background: rgb(var(--primary-rgb));
    transform: translate(-50%, -50%) scale(1.08);
}
.media-vignette__statut {
    position: absolute;
    top: 8px;
    right: 8px;
}

.media-lecteur {
    width: 100%;
    max-height: 78vh;
    border-radius: 8px;
    background: #000;
}

/* =============================================
   Page profil
============================================= */

/* L'avatar était une div à onclick, donc inatteignable au clavier ; c'est
   maintenant l'étiquette du champ de fichier, qui l'ouvre nativement. */
.profil-avatar {
    cursor: pointer;
}
.profil-avatar__image {
    width: 80px;
    height: 80px;
    object-fit: cover;
    border: 3px solid var(--default-border);
}
.profil-avatar__initiales {
    width: 80px;
    height: 80px;
    align-items: center;
    justify-content: center;
    background: rgba(var(--primary-rgb), 0.12);
    color: rgb(var(--primary-rgb));
    font-weight: 600;
    font-size: 28px;
}
.profil-avatar__appareil {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: rgb(var(--primary-rgb));
    border: 2px solid var(--custom-white);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 12px;
}
.profil-avatar:focus-within .profil-avatar__appareil {
    outline: 2px solid rgb(var(--primary-rgb));
    outline-offset: 2px;
}

/* ============================================================
   Notifications
   ============================================================ */
/* La ligne non lue portait un fond posé en dur dans l'attribut style
   (rgba(99,102,241,.04)), la couleur primaire d'un thème parmi d'autres :
   changer de teinte laissait ce violet derrière. Le liseré à gauche fait
   l'essentiel du travail — le fond seul, à 4 %, ne se voyait pas. */
.notif-ligne {
    border-inline-start: 3px solid transparent;
    transition: background-color .15s ease;
}
.notif-non-lue {
    background: color-mix(in srgb, rgb(var(--primary-rgb)) 8%, transparent);
    border-inline-start-color: rgb(var(--primary-rgb));
}
.notif-ligne:last-child {
    border-bottom: 0 !important;
}
/* Le « Voir » est un bouton de formulaire : il doit se lire comme le lien
   qu'il remplace, sans le soulignement ni le décalage vertical du bouton. */
.notif-ligne .btn-link {
    font-weight: 500;
    vertical-align: baseline;
}
.notif-ligne .btn-link:hover {
    text-decoration: underline;
}

/* ============================================================
   Fiche client — pages/admin/client_detail.php
   ============================================================ */

/* Vignettes 16:9. Le couple « aspect-ratio + object-fit » revenait sept fois
   en style en ligne, à l'identique. Le « contain » est voulu : une vidéo qui
   n'est pas au format tient dans son cadre au lieu d'être rognée. */
.fiche-vignette {
    aspect-ratio: 16 / 9;
}
.fiche-vignette > video,
.fiche-vignette > img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}
/* L'aperçu d'un template remplit son cadre : c'est une image de rendu déjà
   cadrée, pas une vidéo dont il faudrait préserver les bords. */
.tpl-card .fiche-vignette > img {
    object-fit: cover;
}

/* Logos de client et de site : carrés recadrés, jamais déformés. */
.fiche-logo {
    object-fit: cover;
}
.fiche-logo--client { width: 56px; height: 56px; }
.fiche-logo--site   { width: 44px; height: 44px; }
/* Le logo rappelé sous le champ d'envoi est vu en entier, pas recadré. */
.fiche-logo--apercu { height: 40px; object-fit: contain; }

/* L'enseigne en tête de playlist portait un dégradé figé sur #6366f1 et
   #8b5cf6, deux violets étrangers au thème. */
.avatar-enseigne {
    background: linear-gradient(135deg,
                rgb(var(--primary-rgb)),
                color-mix(in srgb, rgb(var(--primary-rgb)) 65%, #fff));
    color: #fff;
}

/* Choix d'un template.
   Le voile de confirmation ne s'est jamais affiché, pour deux raisons qui se
   cumulaient : il portait « inset-0 », une classe que Bootstrap 5.3 ne fournit
   pas — donc aucun décalage, le voile ne couvrait rien ; et son
   « display:none !important » posé en style en ligne l'emportait sur le
   « display:flex !important » de la feuille, un !important en ligne battant
   celui d'un sélecteur. D'où l'absence de « d-flex » sur l'élément : cette
   classe de Bootstrap est elle-même !important et rallumerait le voile en
   permanence. Tout est réglé ici, sans !important. */
.tpl-card {
    cursor: pointer;
}
.tpl-check {
    display: none;
    position: absolute;
    inset: 0;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, rgb(var(--primary-rgb)) 40%, transparent);
}
.tpl-card.selected {
    border-color: rgb(var(--primary-rgb));
}
.tpl-card.selected .tpl-check {
    display: flex;
}

/* Choix dans la vidéothèque. La case radio est masquée et c'est la carte qui
   porte l'état : le marquage se faisait en JavaScript, en réattachant un
   écouteur à chaque ouverture de la modale. */
.vth-choix {
    cursor: pointer;
    overflow: hidden;
}
/* Masquée par transparence et non par « display:none » : la case porte un
   « required », et le navigateur refuse de signaler un champ obligatoire qu'il
   ne peut pas atteindre — il abandonnait l'envoi sans un mot. Valider le
   formulaire sans avoir rien choisi ne faisait donc rien du tout. */
.vth-choix input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.vth-choix:has(input[type="radio"]:checked) {
    border-color: rgb(var(--primary-rgb));
    background: color-mix(in srgb, rgb(var(--primary-rgb)) 6%, transparent);
}
/* La case est invisible : sans cela, la navigation au clavier ne montre plus
   où l'on est. */
.vth-choix:focus-within {
    outline: 2px solid rgb(var(--primary-rgb));
    outline-offset: 2px;
}

/* Suggestions d'adresse (api-adresse.data.gouv.fr). Les deux listes, la même
   à l'écran, étaient réglées différemment en style en ligne — z-index 9999
   d'un côté, 2000 de l'autre — et sur un fond blanc en dur. */
.adresse-suggestions {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1000;
    display: none;
    max-height: 220px;
    overflow-y: auto;
    background: var(--custom-white);
    border: 1px solid var(--default-border);
    border-radius: 0 0 8px 8px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, .1);
}
.adresse-suggestion {
    padding: 10px 14px;
    cursor: pointer;
    border-bottom: 1px solid var(--default-border);
    font-size: 13px;
    color: var(--default-text-color);
}
.adresse-suggestion:last-child {
    border-bottom: 0;
}
.adresse-suggestion:hover {
    background: rgb(var(--light-rgb));
}
.adresse-suggestion .ti {
    color: rgb(var(--primary-rgb));
}
.adresse-suggestion__lieu {
    color: var(--text-muted);
    font-size: 12px;
}

/* Le champ et sa liste déroulante : le repère de positionnement. */
.champ-avec-suggestions {
    position: relative;
}

/* La grille de templates défile au lieu d'allonger la modale. */
.tpl-grille {
    max-height: 380px;
    overflow-y: auto;
}
/* La colonne des champs garde sa hauteur à vide : sans cela la modale sautait
   au moment où le premier template était choisi. */
.tpl-champs {
    min-height: 200px;
}

/* =============================================
   Pages de connexion et d'inscription
============================================= */

/* Le panneau de gauche, identique sur les deux pages, portait le même dégradé
   recopié en style en ligne — et il partait de l'indigo de Tailwind, pas du
   violet du thème. Il descend maintenant vers une version assombrie plutôt que
   vers un violet plus clair : le texte blanc posé dessus y gagne. */
.auth-visuel {
    min-height: 100vh;
    background: linear-gradient(135deg,
                rgb(var(--primary-rgb)) 0%,
                color-mix(in srgb, rgb(var(--primary-rgb)) 70%, #000) 100%);
}

/* =============================================
   Éditeur visuel de templates

   L'éditeur ouvre un plein écran sombre par-dessus une administration claire :
   c'est voulu, on y juge une image sur son fond. Son habillage tenait en style
   en ligne, recopié à l'identique dans le balisage PHP et dans les gabarits
   montés en JavaScript — deux jeux de couleurs sans aucun moyen de rester
   d'accord.

   Les teintes sont posées en variables sur #editeurOverlay. Le panneau de
   droite et les champs posés sur la vidéo sont montés par innerHTML à
   l'intérieur : ils en héritent sans avoir à les recopier.

   Deux choses restent volontairement en style en ligne :

   - les `display` de #editeurOverlay, #editeurVideo, #editeurApercu,
     #editeurFrame et #editeurPlaceholder. getCanvasEl() et
     afficherChampsSurCanvas() lisent `el.style.display` pour savoir laquelle
     du canvas ou de l'aperçu porte l'image. Déplacée ici, la propriété ne
     répondrait plus à cette lecture et plus aucun champ ne s'afficherait ;
   - la couleur du type de champ, passée en --champ-couleur : elle vient de la
     donnée, pas de l'habillage.
============================================= */

#editeurOverlay {
    --edit-fond:         #1a1a2e;
    --edit-panneau:      #16213e;
    --edit-filet:        #0f3460;
    --edit-scene:        #0d1117;
    --edit-champ-filet:  #333;
    --edit-texte:        #e0e0e0;
    --edit-texte-faible: #888;
    --edit-danger:       #f87171;

    position: fixed;
    inset: 0;
    z-index: 9999;
    background: var(--edit-fond);
    flex-direction: column;
}

/* --- Barre d'outils --- */
.editeur-barre {
    background: var(--edit-panneau);
    padding: 12px 20px;
    display: flex;
    align-items: center;
    gap: 12px;
    border-bottom: 1px solid var(--edit-filet);
}
.editeur-titre {
    color: #fff;
    margin: 0;
    font-size: 16px;
}
.editeur-pousse { flex: 1; }

/* --- Scène : la vidéo et les champs posés dessus --- */
.editeur-corps {
    display: flex;
    flex: 1;
    overflow: hidden;
}
.editeur-scene {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: var(--edit-scene);
    overflow: auto;
}
#editeurCanvas {
    position: relative;
    display: inline-block;
    max-width: 100%;
    max-height: 100%;
}
/* Le JavaScript reposait ces tailles à la main après chargement, alors
   qu'elles étaient déjà dans l'attribut style. Elles ne sont plus écrites
   qu'ici.

   Le canvas n'a jamais eu de hauteur maximale, à la différence de la vidéo et
   de l'aperçu : c'est lui qui porte l'image une fois la première image
   extraite, et une vidéo en portrait doit pouvoir dépasser 480 px. La
   distinction est conservée telle quelle. */
.editeur-media {
    max-width: 800px;
    max-height: 480px;
}
#editeurFrame {
    max-width: 800px;
}
#editeurPlaceholder {
    width: 800px;
    height: 450px;
    background: var(--edit-fond);
    border: 2px dashed #444;
    align-items: center;
    justify-content: center;
    color: #666;
    font-size: 14px;
}

/* --- Panneau de droite --- */
.editeur-panneau {
    width: 320px;
    background: var(--edit-panneau);
    border-left: 1px solid var(--edit-filet);
    overflow-y: auto;
}
.editeur-panneau-entete {
    padding: 16px;
    border-bottom: 1px solid var(--edit-filet);
}
.editeur-panneau-entete h6 {
    color: var(--edit-texte);
    margin: 0;
    font-size: 14px;
}
.editeur-aide {
    color: var(--edit-texte-faible);
    font-size: 12px;
    margin: 4px 0 0;
}
#listeChampsEditeur { padding: 12px; }
.editeur-infos {
    padding: 16px;
    border-top: 1px solid var(--edit-filet);
    margin-top: 8px;
}
.editeur-infos h6 {
    color: var(--edit-texte);
    font-size: 13px;
    margin-bottom: 12px;
}
.editeur-label {
    color: var(--edit-texte-faible);
    font-size: 12px;
}
/* Les champs de Bootstrap sont clairs. La règle de survol reprend le fond
   sombre : sans elle, un champ prenait le blanc du thème au moment où on
   cliquait dedans — ce que l'ancien style en ligne empêchait par sa seule
   position dans l'attribut. */
#editeurOverlay .form-control,
#editeurOverlay .form-select,
#editeurOverlay .form-control:focus,
#editeurOverlay .form-select:focus {
    background-color: var(--edit-scene);
    border-color: var(--edit-champ-filet);
    color: var(--edit-texte);
}

/* --- Fiche d'un champ dans le panneau --- */
.champ-vide {
    color: #666;
    font-size: 12px;
    text-align: center;
    margin-top: 20px;
}
.champ-carte {
    background: var(--edit-scene);
    border: 1px solid var(--edit-champ-filet);
    border-left: 3px solid var(--champ-couleur);
    border-radius: 6px;
    padding: 10px;
    margin-bottom: 8px;
    cursor: pointer;
}
.champ-carte.est-choisi {
    border-color: var(--champ-couleur);
}
.champ-carte-entete {
    display: flex;
    align-items: center;
    gap: 8px;
}
.champ-carte.est-choisi .champ-carte-entete {
    margin-bottom: 10px;
}
.champ-type {
    color: var(--champ-couleur);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
}
.champ-nom {
    flex: 1;
    color: #ccc;
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.champ-supprimer {
    background: none;
    border: 0;
    color: var(--edit-danger);
    cursor: pointer;
    padding: 0;
    font-size: 16px;
    line-height: 1;
    flex-shrink: 0;
}

/* --- Réglages du champ choisi --- */
.champ-reglages {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.champ-grille-2,
.champ-grille-3 {
    display: grid;
    gap: 6px;
}
.champ-grille-2 { grid-template-columns: 1fr 1fr; }
.champ-grille-3 { grid-template-columns: 1fr 1fr 1fr; }
.champ-label {
    color: var(--edit-texte-faible);
    font-size: 11px;
}
.champ-saisie {
    width: 100%;
    background: var(--edit-fond);
    border: 1px solid var(--edit-champ-filet);
    border-radius: 4px;
    padding: 4px 8px;
    color: var(--edit-texte);
    font-size: 12px;
}
.champ-typo {
    border-top: 1px solid #222;
    padding-top: 8px;
    margin-top: 2px;
}
.champ-typo > .champ-label {
    display: block;
    margin-bottom: 4px;
}
.champ-typo > select.champ-saisie { margin-bottom: 6px; }
.champ-couleur-bloc { margin-top: 6px; }
.champ-couleur-ligne {
    display: flex;
    gap: 6px;
    align-items: center;
}
.champ-pastille {
    width: 40px;
    height: 28px;
    border: 1px solid var(--edit-champ-filet);
    border-radius: 4px;
    background: var(--edit-fond);
    cursor: pointer;
}
/* Le champ texte de la couleur partage sa ligne avec la pastille : il prend la
   place restante au lieu des 100 % de .champ-saisie. */
.champ-couleur-ligne .champ-saisie {
    flex: 1;
    width: auto;
    min-width: 0;
}

/* --- Champ posé sur la vidéo ---
   Le fond reprenait la couleur du type suivie de « 22 », deux chiffres
   hexadécimaux d'opacité collés à la chaîne. Le procédé interdisait toute
   autre écriture de couleur ; color-mix calcule la même transparence sans
   rien supposer de la forme de la valeur. */
.champ-visuel {
    position: absolute;
    border: 2px solid var(--champ-couleur);
    border-radius: 4px;
    background: color-mix(in srgb, var(--champ-couleur) 13%, transparent);
    cursor: move;
    display: flex;
    align-items: center;
    padding: 4px 8px;
    gap: 6px;
    user-select: none;
    z-index: 10;
    box-sizing: border-box;
}
.champ-visuel.est-choisi {
    outline: 2px solid #fff;
}
.champ-visuel-icone {
    color: var(--champ-couleur);
    font-weight: 700;
    font-size: 11px;
    flex-shrink: 0;
}
.champ-visuel-nom {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.champ-visuel .champ-supprimer { font-size: 14px; }
.resize-handle {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 14px;
    height: 14px;
    background: var(--champ-couleur);
    cursor: se-resize;
    border-radius: 2px 0 4px 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Le lecteur de la fenêtre « lire la vidéo » d'admin/templates.php. */
.modal-lecteur {
    width: 100%;
    max-height: 75vh;
    border-radius: 8px;
    background: #000;
}

/* =============================================
   Mes sites — accès rapide à la playlist

   Le bandeau du clip principal ne faisait que constater ; il mène désormais à
   la playlist du site. Il est écrit ici plutôt qu'en badge Bootstrap : un
   badge n'est pas fait pour porter deux lignes et se comporter en lien.
============================================= */
.site-playlist-acces {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    border-radius: 8px;
    border: 1px solid transparent;
    text-align: start;
    text-decoration: none;
    transition: background 0.15s, border-color 0.15s;
}
.site-playlist-acces:focus-visible {
    outline: 2px solid rgb(var(--primary-rgb));
    outline-offset: 2px;
}
/* Le texte reste dans la couleur de texte du thème. Le vert du thème donne
   2,3:1 sur son propre fond teinté, l'orange 2,2:1 : au-dessous du seuil de
   4,5:1, et il s'agit ici de deux lignes à lire, pas d'un mot dans un badge.
   L'état passe donc par l'icône et le filet, qui ne sont pas du texte et
   relèvent du seuil de 3:1. C'est la règle posée en tête de ce fichier. */
.site-playlist-acces {
    color: var(--default-text-color);
}
.site-playlist-acces.est-prete {
    background: rgba(var(--success-rgb), 0.1);
}
.site-playlist-acces.est-prete > .ti-playlist {
    color: rgb(var(--success-rgb));
}
.site-playlist-acces.est-incomplete {
    background: rgba(var(--warning-rgb), 0.1);
}
.site-playlist-acces.est-incomplete > .ti-alert-triangle {
    color: rgb(var(--warning-rgb));
}
.site-playlist-acces.est-prete:hover,
.site-playlist-acces.est-prete:focus-visible {
    border-color: rgb(var(--success-rgb));
}
.site-playlist-acces.est-incomplete:hover,
.site-playlist-acces.est-incomplete:focus-visible {
    border-color: rgb(var(--warning-rgb));
}

/* --- Bandeau d'identité d'un site ---
   Quatre blocs sur une ligne, qui se replient d'eux-mêmes en dessous de
   768 px : les compteurs passent sous l'identité et le bouton prend la
   largeur. Écrit en flex plutôt qu'en grille de colonnes Bootstrap parce que
   les quatre n'ont pas la même nature — un logo fixe, une identité élastique,
   des compteurs de largeur propre, une action. */
.site-bandeau {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px 24px;
}
.site-bandeau-logo {
    width: 56px;
    height: 56px;
    border-radius: 10px;
    object-fit: cover;
    flex-shrink: 0;
}
.site-bandeau-identite {
    flex: 1 1 14rem;
    min-width: 0;
}
.site-bandeau-compteurs {
    display: flex;
    gap: 24px;
    margin: 0;
    /* Un filet plutôt qu'un simple écart : sans lui, les chiffres se lisaient
       comme la suite de l'adresse. */
    padding-inline-start: 24px;
    border-inline-start: 1px solid var(--default-border);
}
.site-bandeau-compteurs > div { text-align: center; }
.site-bandeau-compteurs dt {
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.2;
}
.site-bandeau-compteurs dd {
    margin: 0;
    font-size: 11px;
    color: var(--text-muted);
}
.site-bandeau-action { flex-shrink: 0; }

@media (max-width: 767.98px) {
    /* Le filet vertical n'a plus de sens quand le bloc passe à la ligne. */
    .site-bandeau-compteurs {
        padding-inline-start: 0;
        border-inline-start: 0;
        flex: 1 1 100%;
        justify-content: space-around;
    }
    .site-bandeau-action { flex: 1 1 100%; }
}

/* Le chevron du bloc replié suit l'état du bouton Bootstrap. */
.site-chevron { transition: transform 0.2s; }
.btn:not(.collapsed) > .site-chevron { transform: rotate(90deg); }
