/* ════════════════════════════════════════════════════════════════════
   evalab : Contrôles partagés
   ════════════════════════════════════════════════════════════════════

   Les quelques composants rendus par PLUSIEURS gabarits, qui n'appar-
   tiennent donc à la feuille d'aucun d'entre eux.

   ── Pourquoi ce fichier existe ─────────────────────────────────────
   La bascule de thème est rendue par l'en-tête partagé (vitrine, fil)
   ET par le gabarit d'authentification, qui n'a pas cet en-tête. Ses
   règles vivaient dans ev-vitrine.css : partout ailleurs, le bouton
   s'affichait donc avec ses DEUX icônes visibles à la fois et son
   libellé de secours : destiné aux seuls lecteurs d'écran, bien en
   évidence à l'écran.

   Les déplacer dans ev-chrome.css aurait réglé le cas du fil, pas celui
   des pages de connexion : ce gabarit-là ne charge pas ev-chrome.css,
   dont il n'a pas l'usage (en-tête, pied de page, correctifs du
   template acheté). D'où ce fichier, chargé par les trois.

   Dépend de ev-tokens.css, qui doit être chargé AVANT.
   ════════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════════
   1. Bascule clair / sombre
   ════════════════════════════════════════════════════════════════════
   Les deux icônes sont présentes en permanence dans le DOM ; le CSS
   n'en montre qu'une, selon `[data-ev-theme]` sur <html>. Basculer par
   CSS plutôt qu'en réécrivant le SVG en JavaScript évite un temps mort
   visible au clic.
   ════════════════════════════════════════════════════════════════════ */

.ev-theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid var(--ev-border);
  border-radius: 999px;
  background: var(--ev-surface);
  color: var(--ev-text-muted);
  cursor: pointer;
  transition: background-color .2s var(--ev-ease), color .2s var(--ev-ease);
}
.ev-theme-toggle:hover { background: var(--ev-surface-offset); color: var(--ev-text); }
.ev-theme-toggle:focus-visible { outline: 2px solid var(--ev-blue); outline-offset: 2px; }

/* Une seule des deux icônes est visible à la fois. */
.ev-theme-toggle .ev-icon-moon { display: none; }
:root[data-ev-theme="dark"] .ev-theme-toggle .ev-icon-moon { display: block; }
:root[data-ev-theme="dark"] .ev-theme-toggle .ev-icon-sun  { display: none; }

/* La vitrine suit aussi la préférence système, tant qu'aucun choix
   explicite n'a été posé. */
@media (prefers-color-scheme: dark) {
  :root[data-ev-theme-auto]:not([data-ev-theme="light"]) .ev-theme-toggle .ev-icon-moon { display: block; }
  :root[data-ev-theme-auto]:not([data-ev-theme="light"]) .ev-theme-toggle .ev-icon-sun  { display: none; }
}

/* ════════════════════════════════════════════════════════════════════
   2. Masqué à l'œil, lu par les technologies d'assistance
   ════════════════════════════════════════════════════════════════════
   `display: none` retirerait le texte de l'arbre d'accessibilité : le
   contenu doit rester rendu, mais réduit à un pixel et détouré.
   ════════════════════════════════════════════════════════════════════ */

.ev-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ════════════════════════════════════════════════════════════════════
   3. Image absente du disque
   ════════════════════════════════════════════════════════════════════
   Quand ev-motion.js ne peut pas confier le repli au conteneur, parce
   que celui-ci porte autre chose que l'image -, c'est l'IMAGE elle-même
   qui est marquée. Elle garde alors ses dimensions et sa forme, et rien
   ne déborde autour.

   `color: transparent` masque le texte de remplacement que le
   navigateur afficherait sinon en travers du cadre ; l'attribut `alt`
   reste lu par les lecteurs d'écran.
   ════════════════════════════════════════════════════════════════════ */

img.ev-img-failed {
  background-color: var(--ev-surface-offset);
  background-image:
    radial-gradient(circle at 50% 36%, var(--ev-border) 0 18%, transparent 18.5%),
    radial-gradient(ellipse 34% 26% at 50% 88%, var(--ev-border) 0 99%, transparent 100%);
  background-repeat: no-repeat;
  color: transparent;
  font-size: 0;
}

/* ════════════════════════════════════════════════════════════════════
   4. Bouton de dictée
   ════════════════════════════════════════════════════════════════════
   Posé par ev-dictation.js dans le coin bas-droit de chaque zone de
   texte. Il est positionné en absolu ; c'est le script qui calcule ses
   coordonnées, ici on ne décrit que son apparence.
   ════════════════════════════════════════════════════════════════════ */

.ev-dictate-btn {
  position: absolute;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--ev-border);
  border-radius: 999px;
  background: var(--ev-surface);
  color: var(--ev-text-faint);
  cursor: pointer;
  /* Le champ reste cliquable sous le bouton tant qu'on ne le survole
     pas : une zone de texte se clique souvent près de son coin. */
  opacity: .55;
  transition: opacity .18s var(--ev-ease), color .18s var(--ev-ease),
              border-color .18s var(--ev-ease), background-color .18s var(--ev-ease);
}
.ev-dictate-btn svg { width: 15px; height: 15px; }

.ev-dictate-btn:hover,
.ev-dictate-btn:focus-visible { opacity: 1; color: var(--ev-text); }
.ev-dictate-btn:focus-visible { outline: 2px solid var(--ev-blue); outline-offset: 2px; }

/* En écoute. Le halo pulse pour qu'on sache que le micro est ouvert,
   c'est une information qu'on ne peut pas laisser deviner. */
.ev-dictate-btn.is-listening {
  opacity: 1;
  border-color: var(--ev-error);
  background: var(--ev-error-highlight);
  color: var(--ev-error);
  animation: ev-dictate-pulse 1.6s ease-in-out infinite;
}

@keyframes ev-dictate-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--ev-error-highlight); }
  50%      { box-shadow: 0 0 0 5px transparent; }
}

/* Message transitoire : micro refusé, absent, ou erreur. */
.ev-dictate-note {
  position: absolute;
  z-index: 3;
  inset-inline-end: 8px;
  transform: translateY(6px);
  max-width: min(280px, 90%);
  padding: 7px 11px;
  border: 1px solid var(--ev-error-border);
  border-radius: var(--ev-radius-sm);
  background: var(--ev-error-highlight);
  color: var(--ev-error-text);
  font-family: var(--ev-ff-body);
  font-size: 12.5px;
  line-height: 1.45;
  box-shadow: var(--ev-shadow-lift);
}

@media (prefers-reduced-motion: reduce) {
  .ev-dictate-btn.is-listening { animation: none; }
}

/* Interrupteur (case à cocher en bascule) : <label class="ev-toggle"><input type="checkbox" role="switch"> libellé</label> */
.ev-toggle { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: 14px; color: var(--ev-text); line-height: 1.4; }
.ev-toggle input { -webkit-appearance: none; appearance: none; flex: 0 0 38px; width: 38px; height: 22px; margin: 0; border: 0; border-radius: 999px; background: var(--ev-border-mid, #c9d2dc); position: relative; cursor: pointer; transition: background .15s; }
.ev-toggle input::after { content: ''; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: transform .15s; }
.ev-toggle input:checked { background: var(--ev-blue, #1b74d9); }
.ev-toggle input:checked::after { transform: translateX(16px); }
.ev-toggle input:focus-visible { outline: 2px solid var(--ev-blue, #1b74d9); outline-offset: 2px; }

/* ── Bouton en cours d'envoi (js/ev-submit-once.js) ─────────────────
   Retour visuel pendant qu'un formulaire attend la réponse du serveur,
   pour qu'on ne reclique pas. */
.ev-is-busy { cursor: progress !important; opacity: .85; }
.ev-is-busy::before {
  content: "";
  display: inline-block;
  width: 1em;
  height: 1em;
  margin-right: .5em;
  vertical-align: -.15em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: ev-busy-spin .7s linear infinite;
}
@keyframes ev-busy-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ev-is-busy::before { animation-duration: 2s; } }
