:root {
  --ink: #2c1f45;
  --ink-soft: #5b4a72;
  --paper: #f4ecfb;
  --paper-line: #ddc9ec;
  --accent: #7c4fd1;
  --accent-dark: #7D09E4;
  /* Rose/pink accent (kept the old --gold name so every existing usage stays wired up) */
  --gold: #e0629b;
  --success: #2f9e56;
  --rose: #FFD4F7;

  --font-display: "Fredoka", sans-serif;
  --font-body: "Nunito Sans", sans-serif;

  /* --- Refonte "verre dépoli" (branche redesign, 2026-08-21) : tokens dédiés
     au "chrome" applicatif (listes, modales, boutons, pastilles, nav) qui
     flotte DIRECTEMENT sur le fond aquarelle de body::before — jamais
     réutilisés pour le contenu "papier" d'une fiche/d'un examen (qui reste
     volontairement blanc/lisible comme du papier, voir .sheet-tile-view et
     consorts, non touchés ici). Tokens séparés de --ink/--paper ci-dessus
     plutôt que de les redéfinir : ces deux-là restent utilisés tels quels
     par du contenu papier qu'on ne veut pas casser. */
  --glass-bg: rgba(255, 255, 255, 0.08);
  --glass-bg-strong: rgba(255, 255, 255, 0.14);
  --glass-border: rgba(255, 255, 255, 0.22);
  --glass-ink: #f4eeff;
  --glass-ink-soft: rgba(244, 238, 255, 0.68);
  --cyan: #40eae8;

  --pill-success-bg: rgba(74, 222, 128, 0.18);
  --pill-success-ink: #86f5b0;
  --pill-danger-bg: rgba(255, 143, 192, 0.2);
  --pill-danger-ink: #ffb3d9;
  --pill-pending-bg: rgba(255, 255, 255, 0.14);
  --pill-pending-ink: rgba(244, 238, 255, 0.8);
  --pill-upcoming-bg: rgba(64, 234, 232, 0.16);
  --pill-upcoming-ink: #40eae8;
  --pill-warn-bg: rgba(255, 207, 107, 0.16);
  --pill-warn-ink: #ffcf6b;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100vh;
  /* flex column, SANS flex:1 0 auto sur <main> (retiré : le pied de page
     collé en bas du viewport sur une page courte laissait un grand vide
     au-dessus, jugé pire que le pied de page qui remonte juste après le
     contenu — retour explicite de l'utilisateur). Le flex column reste
     utile pour le width:100% ci-dessous, voir son commentaire. */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  /* Dégradé linéaire haut-droite -> bas-gauche, gardé en commentaire pour
     pouvoir revenir en arrière d'un coup :
  background: linear-gradient(to bottom left, #8b36df 0%, #8b36df 100%);
  */
  color: var(--ink);
  font-family: var(--font-body);
  line-height: 1.6;
}

/* Fond sur un calque séparé (pas le background de body directement), même
   principe qu'avant (position:fixed = jamais déformé ni coupé sur une page
   longue, le contenu défile par-dessus sans bouger le fond).
   Redesign (branche "redesign" uniquement) : demandé explicitement — plus
   d'image aquarelle, un violet foncé uni avec juste un très léger dégradé
   concentré en bas, pour matcher le fond des cartes "screen" du mockup
   validé (mêmes deux teintes que .attendance-session-modal-card). */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, #6a3fc9 0%, #6a3fc9 65%, #7d4fd6 100%);
}

/* Sélecteurs génériques (pas des classes) : chaque page a un header/main/
   footer en enfants directs de <body> — un seul point d'entretien plutôt
   qu'une règle par page/par classe (.admin-main, .prestations-main...).
   "width: 100%" sur les trois est CRUCIAL, pas juste ceinture-bretelles :
   quasiment tous les conteneurs de page (.site-header, .admin-main,
   .prestations-main, .auth-main...) se centrent avec "max-width + margin: 0
   auto". Dans un flex container, des marges horizontales auto sur un enfant
   annulent le stretch de align-items (l'enfant revient à la largeur de son
   contenu au lieu de remplir l'espace, avant même que son propre max-width
   n'entre en jeu) — repéré via une vraie capture d'écran headless après le
   passage de body en flex column pour le footer collant, qui a cassé TOUT
   ce centrage sans qu'aucune classe individuelle n'ait été touchée. Forcer
   width:100% ici contourne ce piège pour de bon : la largeur n'est plus
   "auto", donc le stretch flex n'a plus son mot à dire, et le max-width +
   margin:auto de chaque page reprend son comportement normal par-dessus. */
body > header,
body > main,
body > footer {
  width: 100%;
}

#snow-canvas {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* Flou déplacé ici (composité une fois par frame par le GPU) plutôt que
     via ctx.filter dans snow.js (recalculé à la main pour chacun des
     flocons à chaque frame) — bien moins coûteux, corrige le ralentissement
     perçu introduit par le flou. */
  filter: blur(2px);
}

.site-header {
  max-width: 720px;
  margin: 0 auto;
  /* padding-top réduit : n'a plus besoin de réserver de la place sous un nav
     flottant (voir .top-nav, passé en position:sticky ci-dessus) — la barre
     réserve maintenant son propre espace toute seule. */
  padding: 2.5rem 1.5rem 2.5rem;
  text-align: center;
}

.eyebrow {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #ffffff;
  font-weight: 600;
  font-style: italic;
  /* Halo flou collé aux lettres (pas un panneau derrière tout le bloc) pour
     rester lisible par-dessus le fond image, quelle que soit la zone de
     l'image derrière. */
  text-shadow: 0 0 6px rgba(61, 20, 102, 0.55), 0 0 14px rgba(61, 20, 102, 0.35);
}

.site-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.2rem, 6vw, 3.6rem);
  letter-spacing: -0.01em;
  color: #40EAE8;
  /* Halo désactivé pour test (comparaison avec .toc-label) :
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.322), 0 0 22px rgba(255, 255, 255, 0.55);
  */
}

.tagline {
  margin: 0.9rem 0 0;
  color: #ffffff;
  font-size: 1.05rem;
}

main {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 1.5rem 4rem;
}

/* Même "boîte vitre" que .about-text/.prestation-text/.faq-item, demandée
   explicitement pour ce texte aussi. */
.welcome {
  text-align: center;
  color: #ffffff;
  margin: 0 auto 2.75rem;
  max-width: 620px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 1.5rem 1.75rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.welcome p {
  margin: 0 auto;
  max-width: 52ch;
}

.toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--paper-line);
}

.toc-item {
  border-bottom: 1px solid var(--paper-line);
}

.toc-item a {
  display: flex;
  /* "baseline" convenait au chiffre texte d'origine, mais désaligne les
     nouvelles icônes .toc-index (image) par rapport au label — chaque icône
     ayant sa propre marge interne (halo/étincelles), un centrage vertical
     simple est plus cohérent visuellement d'une ligne à l'autre. */
  align-items: center;
  gap: 1.25rem;
  padding: 1.15rem 0.25rem;
  text-decoration: none;
  color: var(--ink);
  position: relative;
  transition: padding-left 0.2s ease, color 0.2s ease;
}

.toc-item a:hover,
.toc-item a:focus-visible {
  padding-left: 0.6rem;
  color: #40EAE8;
}

.toc-item a::after {
  content: "→";
  margin-left: auto;
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  color: var(--cyan);
}

.toc-item a:hover::after,
.toc-item a:focus-visible::after {
  opacity: 1;
  transform: translateX(0);
}

/* Même badge plein que "Mon espace"/"Thoát" */
.toc-index {
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  object-fit: contain;
  transition: transform 0.15s ease;
}

/* Balancement continu + pop au survol — même traitement "vivant" que
   .flashcard-sway/.flashcard-flip-btn, demandé explicitement par Lily après
   le passage des chiffres en rose ("un peu d'animation comme les
   flashcards"), puis amplifié ("je veux que ça bouge bien") : rotation plus
   large + pulsation de taille, rythme plus rapide. Désynchronisé par item
   (durée/délai propres à chacun) pour que les 7 chiffres ne se balancent pas
   au même rythme. */
@keyframes toc-index-sway {
  0%, 100% { transform: rotate(-8deg) scale(1); }
  50% { transform: rotate(8deg) scale(1.08); }
}
.toc-index {
  animation: toc-index-sway 1.9s ease-in-out infinite;
  transform-origin: 50% 85%;
}
.toc-list .toc-item:nth-child(2) .toc-index { animation-duration: 2.15s; animation-delay: -0.7s; }
.toc-list .toc-item:nth-child(3) .toc-index { animation-duration: 1.7s; animation-delay: -1.3s; }
.toc-list .toc-item:nth-child(4) .toc-index { animation-duration: 2.0s; animation-delay: -0.35s; }
.toc-list .toc-item:nth-child(5) .toc-index { animation-duration: 1.8s; animation-delay: -1.05s; }
.toc-list .toc-item:nth-child(6) .toc-index { animation-duration: 2.05s; animation-delay: -1.6s; }
.toc-list .toc-item:nth-child(7) .toc-index { animation-duration: 1.75s; animation-delay: -0.95s; }

.toc-item a:hover .toc-index,
.toc-item a:focus-visible .toc-index {
  animation: none;
  transform: scale(1.22) rotate(-6deg);
}

.toc-text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

/* Pastille "Nouveau" à côté d'un lien du menu d'accueil (voir "Les petits +")
   — demandé pour "sauter un peu aux yeux" sans être agressif : rose de la DA
   (plus visible que .tab-badge-new, pensée discrète pour un onglet interne)
   avec une pulsation douce et continue plutôt qu'un clignotement. */
@keyframes toc-badge-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(224, 98, 155, 0.5); }
  50% { transform: scale(1.08); box-shadow: 0 0 0 5px rgba(224, 98, 155, 0); }
}
.toc-badge-new {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.12rem 0.55rem;
  border-radius: 999px;
  background: var(--gold);
  color: #fff;
  font-family: var(--font-display);
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  vertical-align: middle;
  animation: toc-badge-pulse 2.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .toc-badge-new {
    animation: none;
  }
}

/* var(--accent-dark) (violet) était pensé pour l'ancien fond aquarelle
   plus clair — devenu quasi illisible sur le nouveau fond violet uni
   (contraste trop faible entre deux violets proches), remonté explicitement
   ("dur à lire"). Cyan, comme le reste des accents du redesign. */
.toc-label {
  font-family: var(--font-display);
  font-size: 1.08rem;
  font-weight: bold;
  color: var(--cyan);
  transition: color 0.2s ease;
}

.toc-item a:hover .toc-label,
.toc-item a:focus-visible .toc-label {
  color: #ffffff;
}

.toc-desc {
  font-size: 0.88rem;
  color: #ffffff;
}

.toc-item--locked .toc-label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.lock {
  width: 1.275rem;
  height: 1.275rem;
  vertical-align: -0.25rem;
  opacity: 0.7;
}

.site-footer {
  text-align: center;
  padding: 2rem 1.5rem 3rem;
  color: #ffffff;
  font-size: 0.85rem;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .toc-item a,
  .toc-item a::after,
  .toc-index {
    transition: none;
  }
  .toc-index {
    animation: none;
  }
}

@media (max-width: 480px) {
  .toc-item a {
    gap: 0.9rem;
  }
  .toc-item a::after {
    display: none;
  }
}

/* --- Page d'inscription --- */

.tagline a {
  color: #ffffff;
}

.auth-main {
  max-width: 420px;
  margin: 0 auto;
  padding: 0 1.5rem 4rem;
}

.google-btn-wrapper {
  display: flex;
  justify-content: center;
  min-height: 44px;
}

.divider {
  display: flex;
  align-items: center;
  text-align: center;
  color: #FFFFFF;
  font-size: 0.85rem;
  margin: 1.75rem 0;
}

.divider::before,
.divider::after {
  content: "";
  flex: 1;
  border-bottom: 1px solid var(--paper-line);
}

.divider span {
  padding: 0 0.9rem;
}

.auth-form {
  display: flex;
  flex-direction: column;
}

.auth-form[hidden] {
  display: none;
}

.auth-form label {
  font-size: 0.88rem;
  font-weight: 600;
  margin-bottom: 0.35rem;
  margin-top: 1rem;
  /* Pas de carte sur ces pages (connexion, mot de passe oublié,
     réinitialisation) — directement sur le fond, il faut donc sa propre
     couleur plutôt que d'hériter du noir par défaut du site. */
  color: #40EAE8;
}

.auth-form input {
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  background: #fff;
  color: var(--ink);
}

.auth-form input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.field-hint {
  margin: 0.3rem 0 0;
  font-size: 0.78rem;
  color: var(--ink-soft);
}

.schedule-current-status {
  margin: 0 0 0.6rem;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  background: #f2ecfb;
  color: var(--accent-dark);
  font-size: 0.95rem;
  font-weight: 600;
  text-shadow: 0 1px 0 #fff;
}

/* Éditeur de description de cours : mise en forme minimale (gras/surligné/
   barré), rendu en texte classique du site — pas de police/taille au choix,
   contrairement aux blocs de fiche (voir sheet-editor-architecture). */
.rich-text-toolbar {
  display: flex;
  gap: 0.4rem;
  margin: 0.5rem 0;
}

.rich-text-btn {
  width: 32px;
  height: 32px;
  font-family: var(--font-body);
  font-size: 0.85rem;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: #fff;
  color: var(--ink);
  cursor: pointer;
}

.rich-text-btn:hover {
  border-color: var(--accent);
}

.rich-text-btn.rich-text-btn--active {
  border-color: var(--accent);
  background: #f2ecfb;
}

.rich-text-editor {
  min-height: 8rem;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  background: #fff;
}

.rich-text-editor:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Couleur de surlignage thématique (violet/rose du site) plutôt que le jaune
   vif par défaut du navigateur, qui jurerait avec la palette. */
.rich-text-editor mark,
.student-list-desc mark {
  background: #f6d8ea;
  color: var(--ink);
  border-radius: 2px;
}

/* Bouton d'action principal repris du mockup validé : pastille cyan, texte
   foncé (meilleur contraste sur cyan qu'un texte blanc) — remplace l'ancien
   rectangle violet plein, gardé nulle part ailleurs pour rester cohérent. */
.btn-primary {
  margin-top: 1.6rem;
  padding: 0.75rem 1.3rem;
  border: none;
  border-radius: 999px;
  background: var(--cyan);
  color: #133b3a;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease;
}

.btn-primary:hover {
  background: #6ff4f2;
}

.btn-primary:active {
  transform: scale(0.98);
}

.form-message {
  margin-top: 1rem;
  font-size: 0.9rem;
  min-height: 1.2em;
}

.form-message--error {
  color: #b3261e;
}

.form-message--success {
  color: var(--accent-dark);
}

/* Texte secondaire (messages d'état vide type "Aucune séance programmée
   pour l'instant.", indications de champ type "Choisis ce qui te prévient
   ...") — .form-message/.access-list-empty/.field-hint utilisent tous
   var(--ink-soft), un gris-violet pensé pour un fond blanc (modales) —
   illisible posé directement sur le fond violet du redesign, remonté
   explicitement ("les textes en gris sont dur à lire"). Scopé à
   .admin-panel (le conteneur commun à TOUS les onglets Cours/Examens/
   Inscriptions/Utilisateurs/Mes cours/Mes examens/Présences/Mes informations
   — jamais les modales, qui restent en dehors de .admin-panel dans le DOM et
   gardent donc leur gris d'origine, toujours correct sur fond blanc). :not()
   pour ne jamais repasser par-dessus une erreur/succès (qui gardent leurs
   couleurs propres). */
.admin-panel .form-message:not(.form-message--error):not(.form-message--success),
.admin-panel .access-list-empty,
.admin-panel .field-hint {
  color: var(--glass-ink-soft);
}

.tabs {
  display: flex;
  border-bottom: 1px solid var(--glass-border);
  margin-bottom: 0.5rem;
}

/* Reprend le mockup : onglets inactifs en blanc discret, l'actif bascule en
   cyan + soulignement cyan (inversé par rapport à l'ancien blanc-actif/
   cyan-inactif, mais c'est exactement ce que montrent les captures
   validées). */
.tab {
  flex: 1;
  padding: 0.6rem 0;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--glass-ink-soft);
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}

.tab--active {
  color: var(--cyan);
  border-bottom-color: var(--cyan);
}

.tab:hover {
  color: var(--cyan);
}

/* Sur mobile, 8 onglets en flex:1 se compressent au point de se chevaucher
   (signalé sur téléphone le 25/08/2026) — on bascule en défilement
   horizontal, chaque onglet gardant sa largeur naturelle. */
@media (max-width: 760px) {
  .tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    flex-wrap: nowrap;
  }
  .tab {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 0.6rem 0.9rem;
  }
}

/* Pastille "Nouveau" à côté d'un onglet fraîchement ajouté (voir
   #tab-attendance) — même patron que .student-list-badge, en blanc
   translucide plutôt que rose pour rester discret à côté du libellé. */
.tab-badge-new {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  color: var(--glass-ink);
  font-family: var(--font-display);
  font-size: 0.6rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: middle;
}

/* --- Onglet "Accès" (plan "Onglet Accès", option B "vue partagée" validée le
   21/08/2026, voir admin-access-overview.js) : liste compacte à gauche,
   détail de l'élément sélectionné à droite — posé directement sur le fond
   violet de .admin-panel, donc en tokens "verre" comme le reste du chrome
   applicatif (jamais --paper/--ink, réservés au contenu "papier"). Même
   patron flex-qui-se-empile-sous-640px que .user-profile-access-columns. --- */
.access-overview {
  display: flex;
  gap: 1.25rem;
  align-items: flex-start;
}

@media (max-width: 760px) {
  .access-overview {
    flex-direction: column;
  }
}

.access-overview-list-col {
  width: 280px;
  flex-shrink: 0;
}

@media (max-width: 760px) {
  .access-overview-list-col {
    width: 100%;
  }
}

.access-overview-search {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  background: var(--glass-bg-strong);
  color: var(--glass-ink);
  margin-bottom: 0.75rem;
}

.access-overview-search::placeholder {
  color: var(--glass-ink-soft);
}

.access-overview-list {
  max-height: 480px;
  overflow-y: auto;
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  background: var(--glass-bg);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.access-overview-group-label {
  margin: 0;
  padding: 0.6rem 0.9rem 0.3rem;
  font-family: var(--font-display);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--glass-ink-soft);
}

.access-overview-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  width: 100%;
  padding: 0.65rem 0.9rem;
  background: none;
  border: none;
  border-top: 1px solid var(--glass-border);
  color: var(--glass-ink);
  font-family: var(--font-body);
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
}

.access-overview-group-label + .access-overview-list-item,
.access-overview-list:first-child > .access-overview-list-item:first-child {
  border-top: none;
}

.access-overview-list-item:hover {
  background: var(--glass-bg-strong);
}

.access-overview-list-item--active {
  background: var(--glass-bg-strong);
  box-shadow: inset 2px 0 0 var(--cyan);
}

.access-overview-list-item-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--cyan);
  font-family: var(--font-display);
  font-weight: 600;
}

.access-overview-list-item-count {
  flex-shrink: 0;
  background: var(--glass-bg-strong);
  border-radius: 999px;
  padding: 0.05rem 0.5rem;
  font-size: 0.72rem;
  color: var(--glass-ink-soft);
}

.access-overview-list-item--active .access-overview-list-item-count {
  color: var(--cyan);
}

.access-overview-detail {
  flex: 1;
  min-width: 0;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1.25rem 1.5rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.access-overview-detail-empty {
  margin: 0;
  color: var(--glass-ink-soft);
}

.access-overview-detail-title {
  font-size: 1.2rem;
  color: var(--cyan);
}

.access-overview-detail-sub {
  margin: 0.2rem 0 1.25rem;
  font-size: 0.85rem;
  color: var(--glass-ink-soft);
}

.access-overview-detail-group + .access-overview-detail-group {
  margin-top: 1.1rem;
}

.access-overview-detail-group-label {
  margin: 0 0 0.5rem;
  font-family: var(--font-display);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--glass-ink-soft);
}

.access-overview-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.access-overview-chip {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: 0.25rem 0.65rem 0.25rem 0.25rem;
  font-size: 0.8rem;
  color: var(--glass-ink);
}

.access-overview-chip .user-avatar-small {
  margin-right: 0;
}

/* Chip "VIP" (cours extra en dehors du site) : fond tranchant pour repérer
   ces élèves d'un coup d'œil dans l'onglet Accès. */
.access-overview-chip--vip {
  background: var(--rose);
  border-color: var(--rose);
  color: var(--ink);
}

.access-overview-vip-filter {
  display: inline-flex;
  margin: 0.75rem 0;
  color: var(--glass-ink, #fff);
}

.access-overview-manage-btn {
  margin-top: 1.25rem;
}

/* --- Barre de navigation en haut à droite (lien connexion) --- */

/* Barre pleine largeur, collante en haut (position:sticky réserve un vrai
   espace dans le flux, contrairement à l'ancien position:fixed qui flottait
   par-dessus le contenu) : plus jamais de contenu qui passe "derrière" le
   nav sur petit écran, même si son contenu passe sur 2 lignes (flex-wrap) —
   la barre grandit simplement, elle ne peut plus rien recouvrir. Fond
   légèrement teinté + flou pour rester lisible par-dessus le contenu qui
   défile en dessous une fois qu'on a scrollé. */
.top-nav {
  position: sticky;
  top: 0;
  z-index: 10;
  width: 100%;
  padding: 0.9rem 1.5rem;
  /* Blanc translucide plutôt qu'une teinte violette plate : avec le nouveau
     fond en dégradé "mesh" (voir body ci-dessus), une couleur plate ici
     créait une bande nette là où elle rencontre le dégradé qui varie
     en dessous. Le blanc très translucide + flou laisse transparaître
     le dégradé du dessous ("verre dépoli") au lieu de le couper. */
  background: rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  /* flex + align-items:center : alignement vertical fiable de l'avatar par
     rapport au texte, plutôt que de dépendre de vertical-align en flux inline
     (c'est ce qui faisait apparaître l'icône "à un endroit bizarre"). */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem 0;
}

/* Réseaux sociaux, à gauche de la barre (le reste — connexion/compte — reste
   à droite grâce à justify-content:space-between ci-dessus). */
/* Bandeau d'annonce défilant (25/08/2026), voir public/js/site-banner.js —
   inséré juste après .site-header sur les pages qui incluent ce script. */
/* .sheet-title-input force "display: block", ce qui écrase l'attribut
   [hidden] sur ce champ (même bug de spécificité que .vitrine-preview-overlay
   avec le pop-up flashcards, 25/08/2026) — sans ça il reste visible même
   caché. */
#banner-link-url-input[hidden] {
  display: none;
}

/* Même piège [hidden]/.sheet-title-input que #banner-link-url-input ci-dessus,
   sur le champ "type de mot personnalisé" de la modale flashcards. */
#flashcard-word-type-custom-input[hidden] {
  display: none;
}

.site-banner-ticker {
  display: block;
  overflow: hidden;
  background: #FFD4F7;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--glass-border);
  padding: 0.5rem 0;
  text-decoration: none;
}

.site-banner-ticker-track {
  display: flex;
  width: max-content;
  animation: site-banner-scroll linear infinite;
}

.site-banner-ticker-track span {
  flex-shrink: 0;
  padding: 0 3rem;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  color: #7D09E4;
  white-space: nowrap;
}

@keyframes site-banner-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .site-banner-ticker-track {
    animation: none;
    overflow-x: auto;
  }
}

.social-icons {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

.social-icons-label {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--cyan);
  white-space: nowrap;
}

.social-icon {
  display: flex;
  color: var(--accent-dark); /* utilisé par l'icône mail (fill="currentColor"), les logos Insta/Facebook/Threads ont leurs propres couleurs de marque */
  border-bottom: none !important; /* .top-nav a met un soulignement au survol, pas voulu ici */
  transition: opacity 0.15s ease;
}

.social-icon svg {
  width: 19px;
  height: 19px;
}

.social-icon:hover,
.social-icon:focus-visible {
  opacity: 0.7;
}

/* --- Cloche de notifications (item 11), insérée par notifications-widget.js
   dans #top-nav-account --- */
.notif-bell-wrapper {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin-right: 0.6rem;
}

.notif-bell-btn {
  position: relative;
  background: none;
  border: none;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.2rem 0.3rem;
  display: inline-flex;
  align-items: center;
}

.notif-bell-icon {
  width: 1.65rem;
  height: 1.65rem;
  display: block;
}

.notif-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 3px;
  border-radius: 999px;
  background: #b3261e;
  color: #fff;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

.notif-dropdown[hidden],
.notif-badge[hidden] {
  display: none;
}

.notif-dropdown {
  position: absolute;
  top: 130%;
  right: 0;
  width: 300px;
  max-width: 85vw;
  max-height: 380px;
  overflow-y: auto;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 20px 50px rgba(44, 31, 69, 0.28);
  text-align: left;
  z-index: 50;
}

/* Sur téléphone en portrait, .top-nav passe souvent sur 2 lignes (voir
   flex-wrap sur .top-nav) et la cloche se retrouve alors collée au bord
   gauche — le "right: 0" ci-dessus ancré sur .notif-bell-wrapper fait alors
   déborder tout le menu hors de l'écran vers la gauche (signalé sur
   téléphone le 25/08/2026). En dessous de 640px, on ancre au VIEWPORT
   plutôt qu'à la cloche : reste visible peu importe où elle atterrit. */
@media (max-width: 640px) {
  .notif-dropdown {
    position: fixed;
    top: 6.5rem;
    left: 0.75rem;
    right: 0.75rem;
    width: auto;
    max-width: none;
  }
}

.notif-dropdown-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.65rem 0.85rem;
  border-bottom: 1px solid var(--paper-line);
  font-weight: 600;
  color: var(--ink);
  font-size: 0.85rem;
}

.notif-mark-all-btn {
  background: none;
  border: none;
  color: var(--accent-dark);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
}

.notif-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.notif-item {
  padding: 0.6rem 0.85rem;
  border-bottom: 1px solid var(--paper-line);
  cursor: pointer;
}

.notif-item:last-child {
  border-bottom: none;
}

.notif-item:hover {
  background: var(--paper);
}

.notif-item--unread {
  background: #f6d8ea33;
  position: relative;
}

.notif-item--unread .notif-item-title {
  font-weight: 700;
}

.notif-item-title {
  margin: 0 0 0.15rem;
  font-size: 0.85rem;
  color: var(--ink);
}

.notif-item-date {
  margin: 0;
  font-size: 0.72rem;
  color: var(--ink-soft);
}

.notif-list-empty {
  padding: 1rem 0.85rem;
  text-align: center;
  color: var(--ink-soft);
  font-size: 0.85rem;
}

/* --- Préférences de notifications (globales, site/email), écran "Mes
   informations" de cours.html --- */
.notif-prefs-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.5rem;
}

.notif-pref-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  color: var(--ink);
  cursor: pointer;
}

.notif-pref-toggle input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--accent-dark);
  cursor: pointer;
}

/* --- Coupure de notif pour UN cours/examen précis (vues détail élève) --- */
/* var(--ink-soft) (gris-violet) illisible sur le fond violet du redesign —
   toujours utilisée sur des pages élève (jamais dans une modale blanche),
   donc changée directement plutôt que scopée. */
.notif-mute-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.4rem 0 0.75rem;
  font-size: 0.82rem;
  color: var(--glass-ink-soft);
  cursor: pointer;
}

.notif-mute-toggle input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--cyan);
  cursor: pointer;
}

/* --- Ligne titre + coupure de notif (vues détail cours/examen élève) : le
   titre garde sa police/taille habituelle (.admin-subtitle), la case passe
   sur la même ligne, tout à droite. --- */
.detail-header-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
}

.detail-header-row .admin-subtitle {
  margin: 0;
  flex: 1;
  min-width: 200px;
}

.detail-header-row .notif-mute-toggle {
  margin: 0;
  flex-shrink: 0;
}

/* Chronomètre d'examen (voir student-courses-exams.js) : visible en
   permanence dans l'en-tête de la vue "passage d'examen" (une seule question
   affichée à la fois par le pager, donc pas besoin de sticky pour rester
   visible en scrollant). Passe en rouge dans la dernière minute. */
.exam-take-timer {
  flex-shrink: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  padding: 0.3rem 0.8rem;
  border-radius: 999px;
  background: var(--accent-dark);
  color: #fff;
}

.exam-take-timer--low {
  background: #e0455f;
}

.top-nav a {
  font-size: 0.85rem;
  font-weight: 600;
  color: #40EAE8;
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease;
}

.top-nav a:hover,
.top-nav a:focus-visible {
  border-bottom-color: var(--accent-dark);
}

.top-nav-greeting {
  font-size: 0.85rem;
  color: #ffffff;
  margin-right: 0.35rem;
}

/* "Mon espace" en rose brillant, seul lien du nav à ressortir ainsi —
   Repensé en petit bouton plein (texte noir sur fond turquoise rectangulaire)
   plutôt qu'un texte qui brille — demandé explicitement, l'ancien glow rose
   n'aurait plus de sens sur un fond plein.
   Sélecteur "a.top-nav-space-link" (pas juste ".top-nav-space-link") :
   nécessaire pour battre ".top-nav a" en spécificité (classe+élément bat
   une seule classe, peu importe l'ordre dans le fichier) — sinon la
   couleur turquoise de base gagnait quand même. */
a.top-nav-space-link {
  color: #0b1a1a;
  background: var(--cyan);
  font-weight: 700;
  text-decoration: none;
  padding: 0.2rem 0.6rem;
  border-radius: 6px;
  white-space: nowrap;
}

/* Même spécificité que .top-nav a:hover (classe+pseudo-classe+élément) —
   gagne par ordre de déclaration (plus bas dans le fichier) : sans ça, le
   soulignement générique du nav réapparaîtrait sous ce badge plein, ce qui
   n'a pas de sens visuellement. */
a.top-nav-space-link:hover,
a.top-nav-space-link:focus-visible {
  border-bottom-color: transparent;
}

.top-nav-sep {
  font-size: 0.85rem;
  color: var(--paper-line);
  margin-right: 0.5rem;
}

/* Même badge plein que "Mon espace" (a.top-nav-space-link) — demandé
   explicitement, même traitement. */
#logout-link {
  font-size: 0.85rem;
  font-weight: 700;
  color: #0b1a1a;
  background: var(--cyan);
  text-decoration: none;
  padding: 0.2rem 0.6rem;
  border-radius: 6px;
  white-space: nowrap;
}

/* Sans ça, le soulignement générique de .top-nav a:hover (border-bottom-color,
   propriété non redéfinie ci-dessus) réapparaîtrait sous ce badge plein. */
#logout-link:hover,
#logout-link:focus-visible {
  border-bottom-color: transparent;
}

/* --- Page admin --- */

.admin-main {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1.5rem 4rem;
}

/* --- Template de cours "Livre" (voir student-courses-exams.js openSheetView) :
   la fiche prend toute la largeur, juste l'en-tête du site au-dessus (pas
   dans .admin-main, donc inchangé sans rien faire de spécial ici). Classe
   posée/retirée dynamiquement sur .admin-main, jamais dans le HTML statique. --- */
.admin-main--book {
  max-width: none;
  padding: 0 0.75rem 4rem;
}

.admin-panel {
  padding-top: 1.5rem;
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}

.admin-table th {
  text-align: left;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #40EAE8;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--paper-line);
}

.admin-table td button + button {
  margin-left: 0.5rem;
}

.admin-table td {
  padding: 0.65rem 0.6rem;
  border-bottom: 1px solid var(--paper-line);
  color: #ffffff;
}

/* Badge "cours extra en dehors du site" (24/08/2026) : repère visuel dans
   la liste Utilisateurs, purement informatif — voir setUserExternalCourses. */
.user-external-courses-badge {
  display: inline-block;
  margin-left: 0.4rem;
  font-size: 1.15rem;
  vertical-align: text-bottom;
}

.user-external-courses-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: #fff;
  font-size: 0.9rem;
  cursor: pointer;
}

.user-external-courses-filter select {
  font-family: var(--font-body);
  font-size: 0.88rem;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: var(--cyan);
  color: var(--ink);
}

/* Ligne "VIP" (cours extra en dehors du site) : fond tranchant pour repérer
   ces utilisateurs d'un coup d'œil dans la liste. */
.user-row--vip {
  background: var(--rose);
}

.user-row--vip td {
  color: var(--ink);
}

/* Boutons "Profil"/"Supprimer" pensés pour un fond violet foncé (verre clair
   sur foncé) : sur le fond rose clair des lignes VIP ils devenaient illisibles,
   on leur donne des couleurs adaptées à un fond clair. */
.user-row--vip .btn-secondary {
  background: #fff;
  border-color: var(--ink);
  color: var(--ink);
}

.user-row--vip .btn-secondary:hover {
  background: var(--paper-line, #f0f0f0);
}

.user-row--vip .btn-delete {
  background: #fff;
  border-color: #d6336c;
  color: #d6336c;
}

.user-row--vip .btn-delete:hover {
  background: #d6336c;
  color: #fff;
}

.role-select {
  font-family: var(--font-body);
  font-size: 0.88rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: var(--cyan);
  color: var(--ink);
}

.admin-placeholder {
  color: #ffffff;
  text-align: center;
  padding: 2rem 0;
}

.btn-delete {
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.4rem 0.8rem;
  border: 1.5px solid var(--pill-danger-ink);
  border-radius: 999px;
  background: var(--pill-danger-bg);
  color: var(--pill-danger-ink);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}

.btn-delete:hover {
  background: var(--pill-danger-ink);
  color: #3a0d1f;
}

/* --- Gestion des cours / fiches --- */

.admin-subtitle {
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: #40EAE8;
  margin: 0.5rem 0 0;
}

.admin-toolbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.25rem 0;
}

/* Même piège [hidden]/display:flex que .chat-panel/.book-field-panel ailleurs
   dans ce fichier : sans ça, [hidden] reste sans effet sur .admin-toolbar
   (ex: #my-exam-book-take-submit-row visible malgré son attribut hidden). */
.admin-toolbar[hidden] {
  display: none;
}

/* --- Navigation "une question à la fois" (examens + exercices de fiche,
   voir question-pager.js) --- */
.question-pager-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 1.25rem 0;
}

.question-pager-counter {
  font-size: 0.9rem;
  font-weight: 600;
  color: #ffffff;
}

.btn-small {
  margin-top: 0;
  padding: 0.55rem 0.9rem;
  font-size: 0.88rem;
}

/* Souligne uniquement les liens/boutons "Quay lại" (jamais "Về trang chủ",
   qui partage pourtant le même wrapper .tagline) — classe dédiée plutôt
   qu'un sélecteur par texte (impossible en CSS). */
.link-underline {
  text-decoration: underline;
}

.btn-link {
  display: inline-block;
  background: none;
  border: none;
  padding: 0;
  margin-bottom: 1rem;
  color: #40EAE8;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

/* Bouton secondaire "verre" : contour translucide plutôt qu'un rectangle
   blanc plein, pour rester dans le même registre que .student-list-item —
   remplit légèrement au survol au lieu de s'inverser complètement. */
.btn-secondary {
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.4rem 0.8rem;
  border: 1.5px solid var(--glass-border);
  border-radius: 999px;
  background: var(--glass-bg);
  color: var(--glass-ink);
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.btn-secondary:hover {
  background: var(--glass-bg-strong);
  border-color: var(--cyan);
}

.simple-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--paper-line);
}

.simple-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 0.25rem;
  border-bottom: 1px solid var(--paper-line);
  color: #ffffff;
}

/* .simple-list est partagée avec les panneaux admin directement sur le
   fond dégradé (blanc y est correct) — la modale "Voir les soumissions"
   d'un élève est maintenant une carte "verre" comme le reste du redesign
   (voir .user-submissions-modal-card plus bas), donc le blanc de base
   redevient correct ici aussi ; plus besoin de l'ancien override sombre
   posé quand cette modale était encore une carte blanche. */

.item-actions {
  display: flex;
  gap: 0.5rem;
  flex-shrink: 0;
  flex-wrap: wrap;
}

/* --- Pastille "copies en attente de correction", devant le nom d'un cours/
   fiche/examen (même rouge que .chat-badge/.notif-badge, cohérence
   site-wide pour "quelque chose demande ton attention") --- */
.pending-correction-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  margin-right: 0.45rem;
  border-radius: 999px;
  background: #b3261e;
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  vertical-align: middle;
}

/* --- Fil d'ariane des sous-catégories de cours --- */
.category-breadcrumb {
  margin: 0.5rem 0 1rem;
  font-size: 0.9rem;
}

.category-breadcrumb-item {
  color: #ffffff;
  text-decoration: none;
  font-weight: 600;
}

a.category-breadcrumb-item:hover,
a.category-breadcrumb-item:focus-visible {
  text-decoration: underline;
}

.category-breadcrumb-sep {
  color: var(--paper-line);
  margin: 0 0.15rem;
}

/* --- Sous-catégorie dans la liste des fiches (façon dossier) --- */
.category-list-item span:first-child {
  font-weight: 700;
}

.sheet-move-select {
  max-width: 220px;
}

.sheet-title-input {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 1.05rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  margin: 0.5rem 0 1.25rem;
  background: #fff;
  color: var(--ink);
}

/* Popup natif de "Cours lié" (<select>) : sans indication, le navigateur le
   rend en clair ou en sombre selon le thème système de l'appareil — d'où le
   fond blanc chez Gauthier contre fond noir chez Lily. color-scheme force le
   même rendu sombre partout (demandé par Lily, 28/08/2026), et les couleurs
   sur <option> couvrent Firefox qui respecte ce style même en popup natif. */
#attendance-session-course {
  color-scheme: dark;
}

#attendance-session-course option {
  background: #1a1330;
  color: #fff;
}

.attendance-label-autocomplete {
  position: relative;
}

.attendance-label-suggestions-list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 20;
  margin: -1rem 0 0;
  padding: 0.25rem 0;
  max-height: 12rem;
  overflow-y: auto;
  list-style: none;
  background: #1a1330;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.attendance-label-suggestions-list li {
  padding: 0.5rem 0.75rem;
  font-size: 1rem;
  color: #fff;
  cursor: pointer;
}

.attendance-label-suggestions-list li:hover,
.attendance-label-suggestions-list li:active {
  background: rgba(255, 255, 255, 0.12);
}

/* --- Éditeur de fiche en grille libre (gridstack.js) --- */

.sheet-blocks-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.5rem 0 1.25rem;
}

/* Cadre "page" : une vraie feuille blanche posée sur le fond crème du site,
   avec de la marge tout autour, pour que la zone d'édition se distingue
   nettement du reste de la page admin au lieu de s'y fondre. */
.sheet-page-frame {
  background: var(--rose);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.14), 0 2px 8px rgba(44, 31, 69, 0.07);
  padding: 2.5rem 2rem;
  margin: 0.5rem 0 1.5rem;
}

#sheet-grid {
  /* Anciennement 720px fixe ("hauteur de page généreuse") — laissé bien trop
     de vide visible dès qu'une fiche a peu de blocs (signalé 2026-08-18).
     GridStack dimensionne déjà la grille au contenu réel ; une petite valeur
     suffit juste à garder un peu de zone cliquable/visible sur une fiche
     vide, sans page fantôme derrière le contenu. */
  min-height: 120px;
  /* Quadrillage qui rend la grille magnétique visible pendant l'édition.
     background-size EN POURCENTAGE (pas en pixels fixes comme avant) : la
     largeur réelle d'une colonne GridStack est (largeur du cadre ÷ nombre de
     colonnes), qui varie avec la largeur d'écran — un quadrillage à taille
     fixe ne coïncidait avec les vraies colonnes que sur un cadre pile à
     672px de large, et dérivait sur tout autre écran, donnant l'impression
     que le magnétisme "ne tombe pas juste" (signalé 2026-08-18). La hauteur,
     elle, reste en pixels fixes (30px = cellHeight) : contrairement à la
     largeur, GridStack ne fait JAMAIS varier la hauteur d'une rangée selon
     l'écran, donc rien à rendre proportionnel ici. --sheet-grid-columns est
     posée par admin-courses.js (SHEET_GRID_COLUMNS), seule source de vérité
     du nombre de colonnes. */
  background-image: linear-gradient(rgba(91, 44, 150, 0.18) 1px, transparent 1px),
    linear-gradient(90deg, rgba(91, 44, 150, 0.18) 1px, transparent 1px);
  background-size: calc(100% / var(--sheet-grid-columns, 24)) 30px;
  background-position: -1px -1px;
}

/* Les poignées se positionnent via des variables CSS que GridStack calcule
   lui-même (--gs-item-margin-*), et qui semblent partir n'importe où pour un
   bloc avec beaucoup d'espace de grille vide en dessous (notre cas : tous nos
   blocs de test ont une grande zone vide sous eux) — d'où le décalage "fou"
   observé en bas. On fige ces variables à 0 pour un positionnement fiable,
   collé pile aux bords du bloc, quoi que GridStack calcule par ailleurs. */
.grid-stack-item {
  --gs-item-margin-top: 0px !important;
  --gs-item-margin-right: 0px !important;
  --gs-item-margin-bottom: 0px !important;
  --gs-item-margin-left: 0px !important;
}

/* Poignées de redimensionnement GridStack : par défaut, une icône flèche
   diagonale assez massive à chaque coin. On la remplace par un petit carré
   neutre centré dans chaque poignée (coin ou bord) — la zone cliquable
   d'origine ne change pas, seul son rendu devient plus discret ("à la
   Paint" : juste de petites accroches, le reste du cadre sert à déplacer).
   Ces poignées sont des enfants directs de ".grid-stack-item" (pas de
   ".sheet-tile"/".grid-stack-item-content", qui n'est qu'un frère) : le
   sélecteur doit cibler ce parent-là pour matcher quoi que ce soit. */
.grid-stack-item > .ui-resizable-handle {
  background-image: none !important;
}

.grid-stack-item > .ui-resizable-handle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  margin: -4px 0 0 -4px;
  background: #fff;
  border: 1px solid var(--ink-soft);
}

/* Les poignées de coin sont elles-mêmes tournées à 45° par GridStack (pour
   orienter son icône d'origine) : sans ça, notre carré hérite de cette
   rotation et devient un losange. On la neutralise en sens inverse. */
.grid-stack-item > .ui-resizable-nw::after,
.grid-stack-item > .ui-resizable-se::after {
  transform: rotate(45deg);
}

.grid-stack-item > .ui-resizable-ne::after,
.grid-stack-item > .ui-resizable-sw::after {
  transform: rotate(-45deg);
}

/* Les poignées de coin de GridStack font 20x20px par défaut : bien plus gros
   que le petit carré qu'on y dessine, et surtout ça mange une bonne partie du
   pourtour du bloc, qui doit rester libre pour le déplacer (voir le
   padding de .sheet-tile-body ci-dessous). On les réduit à 12px. */
.grid-stack-item > .ui-resizable-nw,
.grid-stack-item > .ui-resizable-ne,
.grid-stack-item > .ui-resizable-se,
.grid-stack-item > .ui-resizable-sw {
  width: 12px !important;
  height: 12px !important;
}

/* Par défaut ces poignées de bord s'étirent sur (quasi) toute la longueur du
   bord (ex : "n"/"s" ne laissent que 25px de marge de chaque côté) — donc en
   pratique, tout le pourtour du bloc redimensionne, et il ne reste presque
   plus rien pour l'attraper et le déplacer (repéré à l'usage : au doigt sur
   tablette, quasi impossible d'éviter de tomber dedans). On les réduit à une
   petite zone centrée sur chaque bord, alignée avec le petit carré qu'on y
   dessine — le reste du pourtour redevient disponible pour déplacer. */
.grid-stack-item > .ui-resizable-n,
.grid-stack-item > .ui-resizable-s {
  height: 8px !important;
  left: calc(50% - 15px) !important;
  right: calc(50% - 15px) !important;
}

.grid-stack-item > .ui-resizable-e,
.grid-stack-item > .ui-resizable-w {
  width: 8px !important;
  top: calc(50% - 15px) !important;
  bottom: calc(50% - 15px) !important;
}

.sheet-tile {
  position: relative;
  height: 100%;
  /* Fond "verre" comme le reste du redesign (auparavant rose "à la Paint")
     — demandé explicitement, y compris pour les blocs individuels de
     l'éditeur, pas seulement le cadre de la fiche. */
  background: var(--glass-bg);
  /* Cadre pointillé, sans ombre ni coin arrondi : un bloc "à la Paint", le
     plus dépouillé possible, plutôt qu'une carte avec des bords francs.
     Plus opaque que var(--glass-border) (0.22) : ce pointillé doit rester
     bien visible pendant le glisser/redimensionner, pas juste décoratif. */
  border: 1px dashed rgba(255, 255, 255, 0.45);
  border-radius: 0;
  overflow: hidden;
  cursor: move;
}

/* Bouton d'action propre au bloc (ex: "Changer l'image"), en bas à gauche —
   toujours visible, pas juste au survol. */
.sheet-tile-action {
  position: absolute;
  left: 12px;
  bottom: 12px;
  z-index: 2;
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.35rem 0.65rem;
  border-radius: 5px;
  cursor: pointer;
  border: 1px solid var(--accent-dark);
  background: #fff;
  color: var(--accent-dark);
}

/* Bouton supprimer : une simple croix en haut à droite plutôt qu'un gros
   bouton texte, pour rester aussi discret que possible sur le bloc. */
.sheet-tile-delete {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 3;
  width: 20px;
  height: 20px;
  padding: 0;
  line-height: 18px;
  text-align: center;
  font-size: 0.95rem;
  font-weight: 700;
  border-radius: 50%;
  border: 1px solid var(--ink-soft);
  background: #fff;
  color: var(--ink-soft);
  cursor: pointer;
}

.sheet-tile-delete:hover {
  background: #b3261e;
  border-color: #b3261e;
  color: #fff;
}

.sheet-tile-body {
  height: 100%;
  box-sizing: border-box;
  /* Seulement vertical : un débordement horizontal (mot trop long, "AAAA..."
     sans espaces, etc.) ferait apparaître une barre de défilement collée en
     bas du bloc, exactement là où se trouve la poignée de redimensionnement
     du bord bas — elle devenait alors impossible à attraper. */
  overflow-y: auto;
  overflow-x: hidden;
  /* GridStack ignore volontairement les clics qui démarrent sur du texte
     éditable pour démarrer un déplacement (sinon impossible de cliquer dans
     le texte sans faire bouger le bloc) — donc si le texte occupe tout le
     bloc jusqu'au bord, il ne reste plus aucune zone pour l'attraper et le
     déplacer. Ce padding (non-éditable, contrairement au texte qu'il
     entoure, voir la règle suivante) est ce qui reste cliquable pour
     déplacer le bloc en attrapant son pourtour, comme sur les pointillés. */
  padding: 1rem;
}

.sheet-tile-body [contenteditable] {
  cursor: text;
  overflow-wrap: break-word;
}

/* Le texte occupe naturellement peu de hauteur : sans ça, seule la ligne de
   texte elle-même est cliquable pour éditer, et le reste du bloc (en dessous)
   ne fait rien au clic. On étire la zone éditable sur toute la hauteur
   disponible du bloc pour qu'on puisse cliquer n'importe où dedans. */
.sheet-tile-body > [contenteditable] {
  min-height: 100%;
  box-sizing: border-box;
}

.sheet-tile-body > *:first-child {
  margin-top: 0;
}

.sheet-tile-body > *:last-child {
  margin-bottom: 0;
}

/* Contour/boîte optionnel autour d'un bloc texte/citation/liste — bouton
   "Contour" de #sheet-text-toolbar (admin-courses.js), persisté par bloc
   (dataset.bordered / block.bordered). Générique, pas scopé à l'admin : la
   même classe est posée côté élève par buildReadOnlyBlockElement
   (student-courses-exams.js) pour que le rendu soit identique. */
.sheet-text-el--bordered {
  border: 2px solid var(--glass-border);
  border-radius: 8px;
  padding: 0.75rem 1rem;
}

.sheet-tile-body [contenteditable]:focus {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

.sheet-tile-image {
  position: relative;
  height: 100%;
  background: var(--glass-bg);
}

.sheet-tile-image img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sheet-tile-video {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.sheet-tile-video video {
  flex: 1;
  min-height: 0;
  width: 100%;
  object-fit: contain;
  background: #000;
}

.sheet-tile-video-input {
  flex-shrink: 0;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.78rem;
  padding: 0.3rem 0.5rem;
  border: none;
  border-top: 1px solid var(--paper-line);
}

/* Barre flottante police/taille, partagée par tous les blocs texte/citation/
   liste (voir #sheet-text-toolbar dans admin.html) : affichée au-dessus de la
   grille au lieu d'être répétée à demeure dans chaque bloc, pour que le bloc
   lui-même ne montre que son contenu final ("à la Paint"). */
.sheet-text-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin: 0 0 0.75rem;
  padding: 0.5rem 0.65rem;
  border-radius: 6px;
  background: #f2ecfb;
  border: 1px solid var(--accent);
}

.sheet-text-font,
.sheet-text-size {
  font-family: var(--font-body);
  font-size: 0.72rem;
  padding: 0.15rem 0.3rem;
  border: 1px solid var(--paper-line);
  border-radius: 4px;
  background: #fff;
  color: var(--ink-soft);
}

/* Boutons gras/italique/souligné/barré : réutilisent .rich-text-btn (voir
   plus bas) mais un peu plus petits pour rester à l'échelle de cette barre
   compacte, à côté des contrôles police/taille. */
.sheet-text-toolbar .rich-text-btn {
  width: 26px;
  height: 26px;
  font-size: 0.72rem;
}

.sheet-text-size {
  width: 3.4rem;
}

/* Bouton "Contour" : .btn-secondary de base utilise --glass-bg/--glass-ink
   (pensé pour le fond violet foncé de la page), quasi invisible sur le fond
   clair (#f2ecfb) de cette barre flottante — repris en violet, cohérent avec
   .annotation-draw-toggle--on juste au-dessus (état "actif" du bouton). */
#sheet-text-border-toggle {
  border-color: var(--accent-dark);
  color: var(--accent-dark);
  background: #fff;
}

#sheet-text-border-toggle:hover {
  background: var(--accent-dark);
  color: #fff;
}

/* --- Contenu d'une fiche de cours (rendu public + aperçu dans l'éditeur) --- */

.sheet-content {
  /* Volontairement plus large que la colonne de lecture du reste du site
     (672px) : une fiche est une grille de blocs (pas juste du texte qui
     coule), donc autant utiliser la largeur du cadre "page" plutôt que de
     laisser une grosse marge blanche inutilisée de chaque côté. En
     "max-width" (pas "width"), ça reste fluide : le contenu (en flux normal,
     pas en position absolue) se réduit et s'empile tout seul sur
     tablette/mobile, sans jamais rien pousser hors champ. */
  max-width: 1040px;
  margin: 0 auto;
}

.sheet-content h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.8rem;
  line-height: 1.25;
  color: var(--accent-dark);
  margin: 1.75rem 0 0.75rem;
}

.sheet-content h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.3rem;
  line-height: 1.3;
  color: var(--accent-dark);
  margin: 1.4rem 0 0.6rem;
}

.sheet-content p {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  margin: 0 0 1rem;
}

.sheet-content blockquote {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.1rem;
  line-height: 1.5;
  color: var(--ink-soft);
  border-left: 3px solid var(--accent);
  margin: 1.5rem 0;
  padding: 0.4rem 0 0.4rem 1.25rem;
}

.sheet-content ul {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink);
  margin: 0 0 1rem;
  padding-left: 1.25rem;
}

.sheet-content li {
  margin-bottom: 0.4rem;
}

.sheet-content img {
  max-width: 100%;
  height: auto;
  border-radius: 6px;
}

.sheet-content hr {
  border: none;
  border-top: 1px solid var(--paper-line);
  margin: 1.75rem 0;
}

/* --- Cadre + blocs d'une fiche (contenu) en style "verre" comme le reste du
   redesign — demandé explicitement, y compris côté prof (éditeur
   #sheet-grid) : le fond rose "à la Paint" des blocs individuels
   (.sheet-tile, plus bas) passe aussi en verre, donc éditeur et vues lecture
   (élève + consigne réaffichée en correction, voir
   renderCorrectionSheetContent) partagent maintenant le même style de bout
   en bout — un seul modificateur suffit. */
.sheet-page-frame--view {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: none;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.sheet-page-frame--view .sheet-content h2,
.sheet-page-frame--view .sheet-content h3 {
  color: var(--cyan);
}

.sheet-page-frame--view .sheet-content p,
.sheet-page-frame--view .sheet-content ul {
  color: var(--glass-ink);
}

.sheet-page-frame--view .sheet-content blockquote {
  color: var(--glass-ink-soft);
  border-left-color: var(--cyan);
}

.sheet-page-frame--view .sheet-content hr {
  border-top-color: var(--glass-border);
}

/* --- Éditeur d'examen QCM --- */

.exam-description-input {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  margin: 0.5rem 0 1.25rem;
  background: #fff;
  color: var(--ink);
  resize: vertical;
}

.exam-scoring-panel {
  /* .exam-scoring-row label est en blanc (voir plus bas) : sur fond blanc,
     le texte devenait invisible (signalé 2026-08-19). */
  background: var(--rose);
  border: 1px solid var(--paper-line);
  border-radius: 8px;
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem;
}

.exam-scoring-title {
  font-family: var(--font-display);
  font-size: 1.1rem;
  color: var(--accent-dark);
  margin: 0 0 1rem;
}

.exam-scoring-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.exam-scoring-row:last-child {
  margin-bottom: 0;
}

.exam-scoring-row label {
  font-size: 0.88rem;
  color: var(--ink);
}

.exam-scoring-input {
  font-family: var(--font-body);
  font-size: 0.88rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: #fff;
  color: var(--ink);
  flex-shrink: 0;
}

.exam-scoring-row select.exam-scoring-input {
  max-width: 60%;
}

.exam-scoring-row input.exam-scoring-input {
  width: 5rem;
  text-align: right;
}

#exam-questions-list {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.exam-question {
  background: var(--rose);
  border: 1px solid var(--paper-line);
  border-radius: 8px;
  padding: 1.25rem 1.5rem;
  box-shadow: 0 2px 8px rgba(44, 31, 69, 0.06);
}

.exam-question-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.75rem;
}

.exam-question-index {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--accent-dark);
}

.exam-question-text {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  background: #fff;
  color: var(--ink);
  resize: vertical;
  margin-bottom: 0.75rem;
}

.exam-question-media {
  margin-bottom: 0.75rem;
}

.exam-question-media img,
.exam-question-media video {
  display: block;
  max-width: 100%;
  max-height: 260px;
  border-radius: 6px;
  margin-bottom: 0.5rem;
}

.exam-question-media audio {
  display: block;
  width: 100%;
  margin-bottom: 0.5rem;
}

.exam-media-remove {
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 600;
  color: #b3261e;
  cursor: pointer;
}

.exam-media-buttons {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

/* .btn-delete/.btn-secondary sont pensés pour le fond violet foncé "verre"
   (--pill-danger-ink, --glass-ink : clairs sur foncé) ; sur le fond rose clair
   d'une carte de question (.exam-question, voir --rose), ce même clair-sur-clair
   les rend quasi invisibles. Surcharge scopée à ce contexte avec des teintes
   foncées de la même DA (--accent-dark, --gold) plutôt que retoucher les
   tokens de base et casser leur usage sur fond glass ailleurs. */
.exam-question .btn-delete {
  border-color: #b3261e;
  background: rgba(179, 38, 30, 0.08);
  color: #b3261e;
}

.exam-question .btn-delete:hover {
  background: #b3261e;
  color: #fff;
}

.exam-question .btn-secondary {
  border-color: var(--accent-dark);
  background: rgba(125, 9, 228, 0.08);
  color: var(--accent-dark);
}

.exam-question .btn-secondary:hover {
  background: var(--accent-dark);
  color: #fff;
}

.exam-options-list {
  list-style: none;
  margin: 0 0 0.5rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.exam-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.exam-option-correct {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  accent-color: var(--accent-dark);
  cursor: pointer;
}

.exam-option-text {
  flex: 1;
  min-width: 0;
  font-family: var(--font-body);
  font-size: 0.92rem;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: #fff;
  color: var(--ink);
}

.exam-option-delete {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  line-height: 22px;
  text-align: center;
  padding: 0;
  border: 1px solid var(--paper-line);
  border-radius: 50%;
  background: #fff;
  color: var(--ink-soft);
  font-size: 0.95rem;
  cursor: pointer;
}

.exam-option-delete:hover {
  background: #b3261e;
  border-color: #b3261e;
  color: #fff;
}

.exam-add-option {
  background: none;
  border: none;
  padding: 0.4rem 0;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent-dark);
  cursor: pointer;
}

.exam-add-option:hover {
  text-decoration: underline;
}

/* --- Modale générique (choix du type d'examen pour l'instant) --- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(44, 31, 69, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  z-index: 100;
}

/* Sans ça, "display: flex" ci-dessus écrase le "display: none" par défaut
   du navigateur pour [hidden], et la modale reste visible en permanence. */
.modal-overlay[hidden] {
  display: none;
}

.modal-card {
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 20px 50px rgba(44, 31, 69, 0.28);
  padding: 2rem;
  width: 100%;
  max-width: 420px;
  text-align: center;
}

.modal-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.4rem;
  color: var(--accent-dark);
  margin: 0 0 1.25rem;
}

.modal-option-list {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.modal-option-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  width: 100%;
  padding: 0.85rem 1rem;
  border: 1px solid var(--paper-line);
  border-radius: 8px;
  background: #fff;
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.modal-option-btn:hover:not(:disabled) {
  border-color: var(--accent-dark);
  background: var(--paper);
}

.modal-option-btn:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.modal-option-label {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.98rem;
  color: var(--ink);
}

.modal-option-desc {
  font-size: 0.8rem;
  color: var(--ink-soft);
}

/* --- Modale d'accès élèves (cours + examens) --- */

/* Carte "verre" comme le reste du redesign (demandé explicitement, même
   modale partagée Cours/Examens/onglet "Accès") — remplace l'ancien fond
   blanc. Tous les enfants ci-dessous étaient réglés pour ce fond clair
   (texte foncé) ; surchargés plus bas, scopés à .access-modal-card comme
   .attendance-session-modal-card/.user-profile-modal-card ailleurs dans ce
   fichier. */
.access-modal-card {
  max-width: 480px;
  text-align: left;
  background: linear-gradient(155deg, #6a3fc9, #8a5cf0);
  color: var(--glass-ink);
  /* Portée + case "Groupe automatique" + liste d'élèves peuvent dépasser la
     hauteur d'écran sur tablette — même bug/correctif déjà vu sur
     .attendance-session-modal-card/.user-profile-modal-card, ici sur la
     classe générique donc valable pour toute modale qui la réutilise. */
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.access-modal-card .modal-title {
  text-align: center;
  color: var(--glass-ink);
}

/* --- Modale "Nouveau cours" (choix du template) --- */

#course-template-modal label {
  display: block;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
  text-align: left;
}

#course-template-title-input {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  margin: 0.4rem 0 1rem;
  background: #fff;
  color: var(--ink);
}

/* --- Modale "Déplacer / Convertir" (fiches, sous-catégories, examens) --- */

.move-item-modal-card {
  max-width: 480px;
  text-align: left;
}

.move-item-modal-card .modal-title {
  text-align: center;
}

#move-item-mode-row {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

/* Même piège [hidden]/display:flex que documenté ailleurs dans ce fichier :
   sans ça, le JS (modeRow.hidden = true) ne masquait jamais réellement cette
   ligne — elle restait visible même pour les flux qui n'offrent pas de choix
   déplacer/copier. */
#move-item-mode-row[hidden] {
  display: none;
}

/* .radio-option (partagée avec inscription.html, texte blanc voulu là-bas
   sur fond violet) tombe ici sur la carte MODALE blanche — texte invisible
   sans cette surcharge. */
.move-item-modal-card .radio-option {
  color: var(--ink);
}

#move-item-destination-rows label {
  display: block;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0.75rem 0 0.3rem;
}

#move-item-destination-rows select {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.92rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  background: #fff;
  color: var(--ink);
}

/* Checklist "Portée de l'accès" (cours entier, exclusif, OU plusieurs
   sous-catégories à la fois — voir db/migration_add_category_access.sql) —
   couleur de texte explicite (contrairement à .radio-option/.checkbox-option
   ailleurs dans ce fichier, en blanc pour un fond violet) : cette modale a
   une carte blanche, voir le bug "texte invisible" déjà rencontré sur la
   modale déplacer/copier. */
#access-scope-row > label {
  display: block;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 0.3rem;
}

.access-scope-checklist {
  max-height: 180px;
  overflow-y: auto;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
  margin-bottom: 1rem;
}

.access-scope-option {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.92rem;
  color: var(--ink);
  padding: 0.2rem 0;
  cursor: pointer;
}

.access-scope-option--whole {
  font-weight: 600;
  border-bottom: 1px solid var(--paper-line);
  margin-bottom: 0.2rem;
  padding-bottom: 0.4rem;
}

.access-search {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.92rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  margin-bottom: 0.75rem;
  background: #fff;
  color: var(--ink);
}

/* Recherche de la liste Utilisateurs (onglet admin) : même turquoise que le
   filtre "Afficher" et les selects "Statut" juste à côté. */
#users-search {
  background: var(--cyan);
  color: var(--ink);
}

#users-search::placeholder {
  color: var(--ink);
  opacity: 0.65;
}

/* --- "Groupe automatique" (voir utils/autoGroup.js), en haut de la même
   modale d'accès (cours + examens). --- */
.access-auto-group-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 0.35rem;
  cursor: pointer;
}

.access-modal-card > .field-hint {
  margin: 0 0 0.75rem;
}

.access-list {
  list-style: none;
  margin: 0 0 0.5rem;
  padding: 0;
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
}

.access-item {
  border-bottom: 1px solid var(--paper-line);
}

.access-item:last-child {
  border-bottom: none;
}

.access-item label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.75rem;
  cursor: pointer;
}

.access-item label:hover {
  background: var(--paper);
}

.access-item input[type="checkbox"] {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  accent-color: var(--accent-dark);
  cursor: pointer;
}

.access-item-name {
  font-size: 0.92rem;
  color: var(--ink);
  font-weight: 600;
}

.access-item-email {
  font-size: 0.8rem;
  color: var(--ink-soft);
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.access-list-empty {
  padding: 1rem;
  text-align: center;
  color: var(--ink-soft);
  font-size: 0.88rem;
}

.access-modal-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 0.75rem;
}

/* --- Overrides "verre" de tout ce qui précède, scopés à .access-modal-card
   (base blanche pensée pour d'autres modales pas encore repassées au
   redesign — même risque documenté sur .attendance-session-modal-card). --- */
.access-modal-card #access-scope-row > label,
.access-modal-card .access-scope-option,
.access-modal-card .access-auto-group-label {
  color: var(--glass-ink);
}

.access-modal-card .field-hint {
  color: var(--glass-ink-soft);
}

.access-modal-card .access-scope-checklist {
  border-color: var(--glass-border);
  background: rgba(255, 255, 255, 0.04);
}

.access-modal-card .access-scope-option--whole {
  border-bottom-color: var(--glass-border);
}

.access-modal-card .access-search {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--glass-ink);
}

.access-modal-card .access-search::placeholder {
  color: var(--glass-ink-soft);
}

.access-modal-card .access-list {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--glass-border);
}

.access-modal-card .access-item {
  border-bottom-color: var(--glass-border);
}

.access-modal-card .access-item label:hover {
  background: rgba(255, 255, 255, 0.06);
}

.access-modal-card .access-item-name {
  color: var(--glass-ink);
}

.access-modal-card .access-item-email,
.access-modal-card .access-list-empty {
  color: var(--glass-ink-soft);
}

.access-modal-card .form-message {
  color: var(--glass-ink);
}

.access-modal-card .form-message--error {
  color: var(--pill-danger-ink);
}

.access-modal-card .form-message--success {
  color: var(--pill-success-ink);
}

/* --- Modale "Profil" d'un utilisateur (onglet Utilisateurs) --- */
/* Carte "verre" comme le reste du redesign (demandé explicitement) —
   remplace l'ancien fond rose translucide. Tous les enfants ci-dessous
   étaient réglés pour ce fond clair (texte foncé) ; surchargés ici, scopés
   à cette seule modale (jamais .access-modal-card générique, encore blanche
   ailleurs). */
.user-profile-modal-card {
  max-width: 720px;
  background: linear-gradient(155deg, #6a3fc9, #8a5cf0);
  color: var(--glass-ink);
  text-align: left;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  /* Sur petit écran (tablette), le contenu (avatar/infos/présences/notes/
     accès cours+examens) dépasse la hauteur visible et le bouton
     Enregistrer devient inatteignable — même bug que
     .attendance-session-modal-card, même correctif. */
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
}

.user-profile-modal-card .modal-title {
  color: var(--glass-ink);
  text-align: left;
}

.user-profile-modal-card h3 {
  color: var(--glass-ink);
}

.user-profile-modal-card .form-message {
  color: var(--glass-ink);
}

.user-profile-modal-card .form-message--error {
  color: var(--pill-danger-ink);
}

.user-profile-modal-card .form-message--success {
  color: var(--pill-success-ink);
}

.user-profile-modal-card .access-list,
.user-profile-modal-card .access-list-empty {
  color: var(--glass-ink-soft);
}

.user-profile-modal-card .access-list {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--glass-border);
}

.user-profile-modal-card .access-item {
  border-bottom-color: var(--glass-border);
}

.user-profile-modal-card .access-item label:hover {
  background: rgba(255, 255, 255, 0.06);
}

.user-profile-modal-card .access-item-name {
  color: var(--glass-ink);
}

.user-profile-modal-card .access-item-email {
  color: var(--glass-ink-soft);
}

/* --- Accès partiel par sous-catégorie depuis la modale Profil (bouton de
   dépliage sur chaque cours) : réutilise .access-scope-checklist/
   .access-scope-option de la modale "Accès" (admin-access.js), pensées pour
   une carte blanche — mêmes overrides glass que le reste de cette modale
   ci-dessus. --- */
.access-item-row {
  display: flex;
  align-items: center;
  padding-left: 0.5rem;
}

.user-profile-course-expand-btn {
  flex-shrink: 0;
  width: 1.4rem;
  height: 1.4rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 4px;
  color: var(--glass-ink-soft);
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
}

.user-profile-course-expand-btn:hover,
.user-profile-course-expand-btn:focus-visible {
  color: var(--cyan);
}

.user-profile-course-categories[hidden] {
  display: none;
}

.user-profile-course-categories {
  padding: 0 0.75rem 0.6rem 2.1rem;
}

.user-profile-modal-card .access-scope-checklist {
  border-color: var(--glass-border);
  background: rgba(255, 255, 255, 0.04);
}

.user-profile-modal-card .access-scope-option {
  color: var(--glass-ink);
}

.user-profile-modal-card .access-search {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--glass-ink);
}

.user-profile-modal-card .access-search::placeholder {
  color: var(--glass-ink-soft);
}

/* --- Modale "Voir les soumissions"/"Voir les présences" (ouvertes depuis la
   modale Profil) : même carte "verre" que le reste. --- */
.user-submissions-modal-card {
  max-width: 560px;
  background: linear-gradient(155deg, #6a3fc9, #8a5cf0);
  color: var(--glass-ink);
  text-align: left;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.user-submissions-modal-card .modal-title {
  color: var(--glass-ink);
  text-align: left;
}

.user-submissions-modal-card .form-message {
  color: var(--glass-ink);
}

.user-submissions-modal-card .form-message--error {
  color: var(--pill-danger-ink);
}

/* .field-hint (gris pensé pour une carte blanche, voir .admin-panel .field-hint
   plus haut pour le même correctif) tombe ici sur la carte "verre" violette du
   profil élève — quasi illisible sans ça. Scopé à .user-profile-modal-card
   (la vraie classe de la modale Profil, pas .user-submissions-modal-card qui
   ne sert qu'aux modales "Voir les soumissions/présences" — erreur de portée
   à la première passe, ce correctif ne s'appliquait donc jamais réellement). */
.user-profile-modal-card .field-hint,
.user-submissions-modal-card .field-hint {
  color: var(--glass-ink-soft);
}

/* --- Modale "Nouvelle/Modifier vitrine" (23/08/2026) : même carte "verre"
   que le reste (voir .user-profile-modal-card ci-dessus) — la version
   d'origine utilisait la carte blanche par défaut (.modal-card), avec
   .rich-text-editor.student-list-desc dedans : texte clair pensé pour un
   fond violet, sur fond BLANC -> quasi invisible (signalé par Gauthier
   23/08/2026). Les champs (titre/cours/description) passent en "verre"
   plutôt que blancs, cohérent avec .access-search plus haut. --- */
.vitrine-modal-card {
  max-width: 480px;
  background: linear-gradient(155deg, #6a3fc9, #8a5cf0);
  color: var(--glass-ink);
  text-align: left;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.vitrine-modal-card .modal-title {
  color: var(--glass-ink);
  text-align: left;
}

.vitrine-modal-card .field-label {
  color: var(--glass-ink-soft);
}

.vitrine-modal-card .form-message {
  color: var(--glass-ink);
}

.vitrine-modal-card .form-message--error {
  color: var(--pill-danger-ink);
}

.vitrine-modal-card .sheet-title-input,
.vitrine-modal-card .role-select,
.vitrine-modal-card .rich-text-editor {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--glass-ink);
}

.vitrine-modal-card .role-select option {
  color: var(--ink);
}

/* Même souci que .field-hint ci-dessus : .access-list-empty ("Aucune séance
   programmée...") est gris pensé pour une carte blanche, illisible sur la
   carte "verre" violette. .user-profile-modal-card l'a déjà (voir plus haut) ;
   ici pour .user-submissions-modal-card (modales "Voir les soumissions"/
   "Voir les présences"). */
.user-submissions-modal-card .access-list-empty {
  color: var(--glass-ink-soft);
}

/* Historique de présences compact (modale "Voir les présences", voir
   openUserAttendanceModal) : petites boîtes date+icône plutôt que des cartes
   pleine largeur, pour en voir beaucoup plus d'un coup. Le conteneur défile
   lui-même (titre/bouton Fermer restent fixes) — même bug "on ne voit pas
   tout" déjà rencontré et corrigé sur la modale de gestion de séance. */
.attendance-history-grid {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0.25rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 0.5rem;
  max-height: min(50vh, 420px);
  overflow-y: auto;
}

.attendance-history-cell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.4rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  padding: 0.45rem 0.6rem;
  cursor: default;
}

.attendance-history-date {
  font-size: 0.76rem;
  color: var(--glass-ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.attendance-history-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.3rem;
  height: 1.3rem;
  border-radius: 50%;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
}

.attendance-history-icon--present {
  background: var(--pill-success-bg);
  color: var(--pill-success-ink);
}

.attendance-history-icon--absent,
.attendance-history-icon--not-answered {
  background: var(--pill-danger-bg);
  color: var(--pill-danger-ink);
}

.attendance-history-icon--upcoming {
  background: var(--pill-upcoming-bg);
  color: var(--pill-upcoming-ink);
}

.user-profile-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.user-profile-header-actions {
  margin-left: auto;
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.user-profile-avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.user-profile-avatar[hidden] {
  display: none;
}

.user-profile-access-columns {
  display: flex;
  gap: 1.25rem;
}

.user-profile-access-col {
  flex: 1;
  min-width: 0;
}

.user-profile-access-col h3 {
  margin: 0 0 0.4rem;
  font-size: 0.95rem;
}

@media (max-width: 640px) {
  .user-profile-access-columns {
    flex-direction: column;
  }
}

/* --- Espace élève (cours.html) --- */

.student-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.student-list-item {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  backdrop-filter: blur(6px);
}

.student-list-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--glass-ink);
  margin: 0 0 0.3rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Titres "dossier" côté élève (cours, examens, sous-catégories) en turquoise,
   demandé explicitement — jamais les titres de fiche individuelle, qui
   partagent le même conteneur (#my-course-sheets-list) mais sans icône de
   dossier, d'où le :has() pour ne cibler que les sous-catégories là-dedans.
   .student-list-title est aussi réutilisée ailleurs (noms d'élèves en
   présences/inscriptions admin) — jamais touchée, scopée aux conteneurs
   élève ci-dessous uniquement. */
#my-courses-list .student-list-title,
#my-exams-list .student-list-title,
#my-course-sheets-list .student-list-title:has(.student-list-icon),
#concepts-list .student-list-title {
  color: var(--cyan);
}

/* Vitrine (23/08/2026) : TOUS les titres en turquoise ici, dossiers ET
   fiches individuelles — contrairement à #my-course-sheets-list ci-dessus,
   demandé explicitement pour que la liste floutée reste bien mise en valeur
   d'un bout à l'autre (c'est une vitrine, pas la vraie navigation). */
#vitrine-preview-content .student-list-title {
  color: var(--cyan);
}

/* Icône de dossier (sous-catégorie), voir buildStudentListItem/images/dossier.png */
.student-list-icon {
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  object-fit: contain;
}

/* Cours/examen archivé, visible seulement grâce à "afficher les passés" */
.student-list-item--archived {
  background: rgba(255, 255, 255, 0.04);
  opacity: 0.75;
}

.student-list-badge {
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--gold);
  color: #fff;
}

.student-list-desc {
  font-size: 0.88rem;
  color: var(--glass-ink-soft);
  margin: 0 0 0.5rem;
}

/* .student-list-desc est aussi réutilisée dans la liste des examens (carte
   blanche, doit rester lisible en foncé) — la description de COURS et,
   depuis l'ajout des descriptions de sous-catégorie, la description de
   CATÉGORIE, affichées directement sur le dégradé (admin ET élève, pas de
   carte), ont besoin de leur propre couleur ici plutôt que de changer la
   classe entière. */
#course-description-preview,
#my-course-detail-desc,
#category-description-preview,
#my-category-description,
#my-sheet-category-description {
  color: #ffffff;
}

/* Les éditeurs eux-mêmes (#course-description-editor / #category-description-editor)
   sont dans la modale BLANCHE classique (.modal-card), pas sur le dégradé comme les
   aperçus ci-dessus : ils héritent quand même de .student-list-desc (couleur claire),
   texte quasi invisible sur fond blanc (signalé par Gauthier 27/08/2026). */
/* !important nécessaire : du contenu sauvegardé pendant que le bug était actif
   contient du style inline color:#fff figé par l'éditeur contenteditable
   (capture de la couleur calculée à chaque frappe) — une règle de classe
   normale ne bat pas un style inline. */
#course-description-editor,
#course-description-editor *,
#category-description-editor,
#category-description-editor * {
  color: var(--ink) !important;
}

/* .category-breadcrumb-item est normalement utilisée inline dans le fil
   d'ariane (nav flex) — ici en <p> autonome au-dessus d'une fiche, besoin
   d'une petite marge propre plutôt que la marge de paragraphe par défaut. */
#my-sheet-category-name {
  margin: 0 0 0.3rem;
}

/* Séparation discrète entre le fil d'ariane et la description de
   sous-catégorie (les deux se suivaient sans repère visuel, difficile à
   distinguer du reste). Sans effet quand l'élément est masqué (hors d'une
   sous-catégorie) : [hidden] passe en display:none, la bordure ne s'affiche
   pas dans le vide. */
#category-description-preview,
#my-category-description {
  margin-top: 0.5rem;
  padding-top: 0.6rem;
  border-top: 1px solid rgba(255, 255, 255, 0.25);
}

.student-list-meta {
  font-size: 0.76rem;
  color: var(--glass-ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 0;
}

.auth-form--student-info {
  max-width: 420px;
}

.auth-form--student-info input:disabled {
  color: var(--ink-soft);
  background: var(--paper);
  cursor: not-allowed;
}

.student-list-item--clickable {
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.student-list-item--clickable:hover,
.student-list-item--clickable:focus-visible {
  border-color: var(--cyan);
  box-shadow: 0 2px 14px rgba(64, 234, 232, 0.18);
  outline: none;
}

/* Fiche/examen déjà rempli : badge "Corrigé ✓"/"En attente" + note à droite
   (voir buildStudentListItem) — seuls les éléments avec un statut passent en
   flex ici, les autres listes construites à la main sur les mêmes classes
   (ex. admin-registrations.js) restent inchangées. */
.student-list-item--with-status {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.student-list-item-main {
  min-width: 0;
  flex: 1;
}

.student-list-status {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.3rem;
}

.student-list-status .exercise-status-badge {
  margin: 0;
  white-space: nowrap;
}

.student-list-status-score {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.25rem;
  color: #e11d48;
  margin: 0;
}

/* --- Lecture d'une fiche (rendu figé, sans le chrome de l'éditeur) --- */

.sheet-tile-view {
  height: 100%;
}

.sheet-tile-view-media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 6px;
}

/* --- Passage d'un examen (élève) --- */

.exam-take-questions {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* Carte "verre" comme les listes/menus (voir .student-list-item) — demandé
   explicitement, remplace l'ancienne carte blanche opaque qui jurait au
   milieu du reste du redesign. */
.exam-take-question {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1.25rem 1.5rem;
  backdrop-filter: blur(6px);
  /* .exercise-answer-display (dedans, réponse libre) a une largeur fixe
     volontaire — voir son commentaire. Même filet de sécurité qu'sur
     .exercise-editor-card. */
  overflow-x: auto;
}

.exam-take-question-index {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  color: var(--cyan);
  margin: 0 0 0.4rem;
}

.exam-take-question-text {
  font-size: 1rem;
  color: var(--glass-ink);
  margin: 0 0 0.75rem;
}

.exam-take-question-media {
  display: block;
  max-width: 100%;
  max-height: 260px;
  border-radius: 6px;
  /* Centré horizontalement dans son conteneur (souvent plus large que
     l'image, notamment sur les cartes d'exercice) plutôt que collé à gauche. */
  margin: 0 auto 0.75rem;
}

/* Image cliquable pour l'agrandir (voir openImageLightbox/makeImageZoomable
   dans student-courses-exams.js) — fiches et questions d'examen, jamais les
   vidéos (elles ont déjà leurs propres contrôles natifs). */
.zoomable-image {
  cursor: zoom-in;
  transition: opacity 0.15s ease;
}

.zoomable-image:hover {
  opacity: 0.88;
}

.image-lightbox-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  background: rgba(44, 31, 69, 0.85);
  cursor: zoom-out;
}

.image-lightbox-frame {
  position: relative;
  /* inline-block (pas inline-flex) : épouse la taille de l'image sans
     dépendre d'un pourcentage de hauteur en cascade (voir plus bas). */
  display: inline-block;
  line-height: 0; /* pas d'espace fantôme sous l'image en inline-block */
  border-radius: 8px; /* même arrondi que .image-lightbox-img, pour que le
    overflow:hidden de .watermark-host ne laisse pas le filigrane déborder
    des coins arrondis */
}

.image-lightbox-img {
  display: block;
  /* vw/vh plutôt que % : un % de hauteur ne se résout PAS à travers un
     conteneur (.image-lightbox-frame) dont la propre hauteur est
     automatique (dépend de son contenu, donc "indéfinie" au sens CSS) —
     l'image se retrouvait avec sa hauteur non contrainte. 4rem = les 2rem
     de padding de .image-lightbox-overlay de chaque côté. */
  max-width: calc(100vw - 4rem);
  max-height: calc(100vh - 4rem);
  border-radius: 8px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}

.exam-take-options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.exam-take-option label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.95rem;
  color: var(--glass-ink);
  cursor: pointer;
}

.exam-take-option-checkbox {
  width: 18px;
  height: 18px;
  accent-color: var(--cyan);
  cursor: pointer;
}

/* var(--accent-dark) (violet) illisible sur le nouveau fond violet uni du
   redesign — même bug que .toc-label/.exam-take-question-index. */
.exam-result-score {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 2.5rem;
  color: var(--glass-ink);
  text-align: center;
  margin: 2rem 0;
}

/* Le chiffre (score/maxScore) seul, en rouge comme .exercise-result-score
   (note QCM d'une fiche) — le reste du texte (corrigé par X / en attente de
   correction) garde le blanc de .exam-result-score ci-dessus. */
.exam-result-score-number {
  color: #e11d48;
}

/* --- Détail d'une copie côté prof : bonnes réponses en vert, mauvaises
   cases cochées en rouge --- */

.submission-option {
  padding: 0.35rem 0.6rem;
  border-radius: 5px;
  border: 1px solid transparent;
}

.submission-option--correct {
  background: rgba(47, 158, 86, 0.12);
  border-color: var(--success);
}

.submission-option--wrong {
  background: rgba(179, 38, 30, 0.08);
  border-color: #b3261e;
}

.submission-option-marker {
  font-size: 1rem;
}

/* --- Bandeau "afficher les cours/examens passés" (mes-cours.html) ---
   Désactivé pour l'instant : ça suppose une notion de date de fin qui
   n'existe pas encore sur les cours/examens. */

.past-toggle {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.5rem 0 1.25rem;
  font-size: 0.88rem;
  color: #ffffff;
}

.past-toggle label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
}

.past-toggle input {
  cursor: pointer;
  accent-color: var(--accent-dark);
}

/* --- Page d'erreur 404 --- */

.error-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.5rem;
}

.error-card {
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.14), 0 2px 8px rgba(44, 31, 69, 0.07);
  padding: 2.5rem 2.5rem 3rem;
  max-width: 420px;
  width: 100%;
  text-align: center;
}

.error-image {
  max-width: 220px;
  width: 100%;
  height: auto;
  margin: 0 auto 1.5rem;
  display: block;
}

.error-text {
  font-family: var(--font-display);
  font-size: 1.2rem;
  color: var(--ink);
  margin: 0 0 1.5rem;
}

.error-home-link {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.95rem;
  color: #fff;
  background: var(--accent-dark);
  padding: 0.65rem 1.4rem;
  border-radius: 999px;
  text-decoration: none;
  transition: background 0.2s ease;
}

.error-home-link:hover,
.error-home-link:focus-visible {
  background: var(--accent);
}

/* --- Exercices de fiche (édition, réponse élève, correction manuelle) --- */

#sheet-exercises-list,
#exercise-correction-list,
.exercise-answer-form ul {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* Même piège [hidden]/display:flex que .book-field-bubble/.book-field-panel
   (voir project-infra-and-gotchas) : sans ça, .hidden=true sur ces deux
   éléments (mis par openBookCorrectionForStudent pour une fiche "Livre") ne
   les masquait pas réellement — la vue de correction classique restait
   affichée par-dessus/à côté de la vue "Livre". */
#exercise-correction-list[hidden] {
  display: none;
}

#exercise-correction-actions[hidden] {
  display: none;
}

/* Carte "verre" comme .exam-take-question/.student-list-item — remplace
   l'ancien fond rose plein. Utilisée pour les 3 vues (édition admin, réponse
   élève, correction admin manuelle), voir admin-sheet-exercises.js/
   student-sheet-exercises.js. Ce changement corrige au passage un vrai bug :
   les options QCM en lecture seule réutilisent .exam-take-option (voir
   student-sheet-exercises.js), dont le texte est passé en blanc pour la
   carte "verre" de .exam-take-question — invisible sur l'ancien fond rose,
   remonté explicitement ("les qcm, avant et après correction"). Redevient
   correct maintenant que cette carte est sombre elle aussi. */
.exercise-editor-card {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1.25rem 1.5rem;
  backdrop-filter: blur(6px);
  /* .exercise-answer-display (dedans) a une largeur fixe volontaire — voir
     son commentaire. Absorbe le débordement en défilement local plutôt que
     de faire défiler toute la page si la fenêtre est plus étroite que ça. */
  overflow-x: auto;
}

.exercise-editor-card--voice-recording {
  background: none;
  border: none;
  backdrop-filter: none;
  padding: 1.25rem 0;
}

.exercise-editor-card .exam-question-index {
  display: block;
  margin-bottom: 0.5rem;
  /* var(--accent-dark), la couleur de base de .exam-question-index, est
     pensée pour l'éditeur d'examen (resté sur une carte claire, pas touché
     ici) — invisible sur cette carte désormais sombre, donc surchargée
     seulement dans ce contexte précis. */
  color: var(--cyan);
}

.exercise-type-select {
  display: block;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: #fff;
  color: var(--ink);
  margin-bottom: 0.6rem;
}

.exercise-qcm-options {
  margin-top: 0.75rem;
}

/* Second bloc texte/média optionnel d'un exercice (voir
   migration_add_sheet_exercise_second_media.sql, admin-sheet-exercises.js) —
   léger cadre pointillé pour le distinguer visuellement du bloc principal. */
.exercise-secondary-content {
  margin-top: 0.5rem;
  padding-top: 0.75rem;
  border-top: 1px dashed var(--border-color, #ddd);
}

.exam-question-text-2 {
  margin-bottom: 0.5rem;
}

.exercise-answer-question {
  font-weight: 600;
  color: var(--glass-ink);
  margin: 0 0 0.75rem;
  /* Les sauts de ligne tapés dans la consigne (textarea admin) doivent être
     conservés à l'affichage — un <p> normal les ignore par défaut. */
  white-space: pre-line;
}

/* Cours "30 jours" : pas de "Exercice N" affiché (voir
   student-sheet-exercises.js), la consigne reprend la couleur qu'avait le
   numéro caché. */
.exercise-answer-question--scheduled {
  color: var(--cyan);
}

.exercise-free-text-input,
.exercise-teacher-comment {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  color: var(--ink);
  margin-top: 0.5rem;
}

/* Ancre pour le calque de dessin (annotation-canvas), posé par-dessus en
   position absolute : doit rester positionné pour ça.
   Largeur volontairement FIXE (pas responsive) : les traits de stylet sont
   stockés en fractions 0..1 de ce rectangle (voir canvas-annotation.js), donc
   si sa largeur variait (fenêtre redimensionnée, écran différent entre la
   prof qui corrige et l'élève qui relit), le texte à l'intérieur se
   ré-empaquetterait différemment (retours à la ligne à d'autres endroits) et
   les traits se retrouveraient à côté du mot visé au lieu de dessus — bug
   réel constaté avec des captures à deux largeurs de fenêtre différentes. En
   gardant TOUJOURS la même largeur, le texte se ré-empaquette toujours pareil
   et les fractions restent valables partout. .exercise-editor-card et
   .exam-take-question ont overflow-x:auto pour absorber le cas (rare) où
   cette largeur fixe dépasse une fenêtre très étroite, sans faire défiler
   toute la page horizontalement. */
.exercise-answer-display {
  position: relative;
  padding: 0.75rem 1rem;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  margin-bottom: 0.5rem;
  width: 720px;
}

.exercise-answer-text {
  margin: 0;
  color: var(--glass-ink);
  white-space: pre-wrap;
}

.exercise-answer-file-image {
  display: block;
  max-width: 100%;
  border-radius: 6px;
}

.exercise-teacher-comment-display {
  margin: 0.5rem 0 0;
  padding: 0.6rem 0.75rem;
  background: var(--paper);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  font-size: 0.9rem;
  color: var(--ink);
}

/* Exercice "Enregistrer la voix" + réponse vocale du prof (24/08/2026) —
   voir public/js/voice-recorder.js, partagé élève/prof. */
.voice-recorder {
  margin: 0.5rem 0;
}

.voice-recorder-controls {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.voice-recorder-btn {
  font-family: var(--font-body);
  font-size: 0.88rem;
  font-weight: 600;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--accent-soft, #f0e9fb);
  color: var(--accent-dark, var(--accent));
  cursor: pointer;
}

.voice-recorder-btn--recording {
  background: #e11d48;
  border-color: #e11d48;
  color: #fff;
  animation: voice-recorder-pulse 1.4s ease-in-out infinite;
}

@keyframes voice-recorder-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(225, 29, 72, 0.35); }
  50% { box-shadow: 0 0 0 6px rgba(225, 29, 72, 0); }
}

.voice-recorder-timer {
  font-family: var(--font-mono, monospace);
  font-size: 0.88rem;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.voice-recorder-status {
  margin: 0;
}

.voice-recorder-player {
  display: block;
  width: 100%;
  max-width: 320px;
  margin-top: 0.5rem;
}

.voice-recorder-teacher-reply .field-hint {
  margin: 0 0 0.5rem;
  color: var(--cyan);
}

.voice-recorder-fallback {
  display: block;
  margin-top: 0.4rem;
  font-size: 0.85rem;
}

.answer-explanation-display {
  margin: 0.5rem 0 0;
  padding: 0.6rem 0.75rem;
  background: rgba(64, 234, 232, 0.12);
  border: 1px solid rgba(64, 234, 232, 0.4);
  border-radius: 4px;
  font-family: var(--font-display);
  font-size: 0.9rem;
  color: var(--cyan);
  white-space: pre-wrap;
}

/* --- Types d'exercices "Livre" (voir public/js/admin-sheet-exercises.js et
   student-sheet-exercises.js) : fill_blanks (liste de cases à remplir) et
   underline_choice (choix inline dans une phrase). --- */

.exercise-fill-blanks-editor {
  margin-top: 0.5rem;
}

.exercise-fill-blank-input {
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  width: 60%;
}

.exercise-fill-blanks-list,
.exercise-fill-blanks-display {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  columns: 2;
  column-gap: 2rem;
}

.exercise-fill-blanks-list li,
.exercise-fill-blanks-display li {
  break-inside: avoid;
  margin: 0 0 0.6rem;
  color: var(--glass-ink);
}

.exercise-fill-blank-answer-input {
  width: 3.5rem;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.25rem 0.4rem;
  border: none;
  border-bottom: 2px solid var(--accent);
  background: transparent;
  text-align: center;
  margin-right: 0.4rem;
}

.exercise-fill-blank-value {
  display: inline-block;
  min-width: 2.5rem;
  padding: 0.1rem 0.5rem;
  border-bottom: 2px solid var(--cyan);
  font-weight: 600;
  color: var(--cyan);
  margin-right: 0.4rem;
}

.exercise-underline-choice-text {
  margin: 0;
  color: var(--glass-ink);
  line-height: 2;
}

.exercise-underline-choice-group {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0 0.2rem;
}

.exercise-underline-choice-option {
  font-family: var(--font-body);
  font-size: 0.92rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid var(--paper-line);
  border-radius: 999px;
  background: #fff;
  color: var(--ink);
  cursor: pointer;
}

.exercise-underline-choice-option.selected {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 600;
}

.exercise-underline-choice-answer {
  font-weight: 700;
  text-decoration: underline;
  color: var(--cyan);
}

.exercise-status-badge {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  margin: 0 0 1rem;
}

/* Couleurs alignées sur les tokens --pill-* (voir :root) : re-tunées pour
   rester lisibles sur les cartes "verre" translucides du redesign — l'ancien
   --refused (rouge foncé #b3261e) devenait illisible sur fond violet foncé,
   remplacé par le rose vif du mockup validé. */
.exercise-status-badge--pending {
  background: var(--pill-pending-bg);
  color: var(--pill-pending-ink);
}

.exercise-status-badge--corrected {
  background: var(--pill-success-bg);
  color: var(--pill-success-ink);
}

.exercise-status-badge--refused {
  background: var(--pill-danger-bg);
  color: var(--pill-danger-ink);
}

/* Réutilisé pour "Cours à venir" (voir admin-attendance.js/student-attendance.js) */
.exercise-status-badge--upcoming {
  background: var(--pill-upcoming-bg);
  color: var(--pill-upcoming-ink);
}

/* --- Note QCM d'une fiche (voir student-sheet-exercises.js), affichée à
   côté du badge "Corrigé" plutôt qu'au-dessus (contrairement à
   .exam-result-score, la note d'examen, volontairement pas touchée ici). --- */
.exercise-result-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 0 0 1rem;
}

.exercise-result-row .exercise-status-badge {
  margin: 0;
}

.exercise-result-score {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.5rem;
  color: #e11d48;
}

/* --- Historique des tentatives précédentes (voir "Seconde tentative",
   student-sheet-exercises.js buildPreviousAttemptsHistory) : replié par
   défaut, un simple cadre discret par tentative pour ne pas rivaliser
   visuellement avec la tentative en cours au-dessus. --- */
.exercise-attempts-history {
  margin-top: 1.5rem;
}

.exercise-attempts-history-title {
  font-weight: 600;
  color: var(--glass-ink, #4c1d95);
  margin: 0 0 0.5rem;
}

.exercise-attempt-details {
  border: 1px solid rgba(124, 58, 237, 0.25);
  border-radius: 0.75rem;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.5rem;
}

.exercise-attempt-details summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--glass-ink, #4c1d95);
}

/* --- Mini-onglets de navigation entre tentatives côté correction prof (voir
   admin-sheet-exercises.js openExerciseCorrection). --- */
.exercise-attempts-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0.5rem 0 1rem;
}

/* --- Note QCM d'une fiche (voir student-sheet-exercises.js), affichée à
   côté du badge "Corrigé" plutôt qu'au-dessus (contrairement à
   .exam-result-score, la note d'examen, volontairement pas touchée ici). --- */
.exercise-result-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 0 0 1rem;
}

.exercise-result-row .exercise-status-badge {
  margin: 0;
}

.exercise-result-score {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.5rem;
  color: #e11d48;
}

/* --- Calque de dessin (canvas-annotation.js) --- */

.annotation-canvas {
  position: absolute;
  inset: 0;
  touch-action: none;
}

/* Verrouille le scroll de TOUTE la page (souris ET tactile) tant qu'au moins
   un calque de dessin est actif — voir lockPageScroll/unlockPageScroll dans
   canvas-annotation.js. touch-action:none en plus d'overflow:hidden : sur
   tablette, un doigt qui glisse peut encore déclencher un scroll "élastique"
   du body sur certains navigateurs avec overflow:hidden seul. */
body.annotation-scroll-locked {
  overflow: hidden;
  touch-action: none;
}

/* Bouton de secours "Débloquer le défilement" (voir ensureScrollLockEscapeBtn
   dans canvas-annotation.js) — toujours fixed, centré en haut, et au-dessus
   de TOUT (z-index 500 : au-dessus des panneaux flottants ✏️/📑 qui montent
   déjà à 210) : c'est le seul filet de sécurité garanti accessible si le
   bouton toggle normal se retrouve hors champ pendant que le scroll est
   bloqué. Visible en permanence dès qu'une page permet de dessiner (pas
   seulement pendant que le scroll est réellement verrouillé), donc DEUX
   états visuels distincts nécessaires — sans ça le bouton semblait actionnable
   en permanence alors qu'il n'y avait souvent rien à débloquer (remonté comme
   "ne fait rien au clic"). Gris/inerte par défaut (rien à débloquer,
   disabled) ; --armed = rouge vif + cliquable dès que le scroll est
   VRAIMENT verrouillé (voir updateScrollLockEscapeBtnState). */
.annotation-scroll-lock-escape {
  position: fixed;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  border: none;
  border-radius: 999px;
  background: #9ca3af;
  color: #fff;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  padding: 0.55rem 1rem;
  cursor: default;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
  z-index: 500;
  opacity: 0.75;
}

.annotation-scroll-lock-escape--armed {
  background: #b3261e;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  opacity: 1;
}

.annotation-scroll-lock-escape[hidden] {
  display: none;
}

.annotation-canvas--editable {
  cursor: crosshair;
}

.annotation-toolbar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.5rem 0 0.75rem;
  flex-wrap: wrap;
}

.annotation-color-group {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  position: relative;
}

.annotation-color-btn {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid transparent;
  padding: 0;
  cursor: pointer;
  /* Sans ça, un rond clair (ex: le rose) se fond dans un fond de la même
     teinte (barre d'outils, page rose) et devient invisible. */
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

.annotation-color-btn--active {
  border-color: var(--ink);
}

/* Sélecteur de couleur natif (spectre + intensité), stylé en pastille ronde
   pour matcher les 4 boutons de couleur fixe à côté — cliqué DIRECTEMENT,
   pas de bouton décoratif par-dessus + input caché déclenché par
   procuration (cette astuce précédente causait des artefacts visuels et
   cassait le clic selon les navigateurs). Le fond affiché est simplement la
   couleur actuellement choisie (géré nativement par le navigateur), donc
   toujours cohérent, jamais de double-rendu. */
.annotation-color-input {
  -webkit-appearance: none;
  appearance: none;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 50%;
  cursor: pointer;
  background: none;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

.annotation-color-input::-webkit-color-swatch-wrapper {
  padding: 0;
  border-radius: 50%;
}

.annotation-color-input::-webkit-color-swatch {
  border: none;
  border-radius: 50%;
}

.annotation-color-input::-moz-color-swatch {
  border: none;
  border-radius: 50%;
}

/* Icône 🎨 superposée à l'input color pour signaler "choisir une autre
   couleur" (sinon indiscernable d'une 5e pastille fixe) — voir
   canvas-annotation.js : <input> ne pouvant pas avoir d'enfant, l'icône est
   un élément séparé positionné par-dessus, avec pointer-events:none pour
   laisser le clic traverser jusqu'à l'input réel en-dessous. */
.annotation-color-input-wrap {
  position: relative;
  display: inline-flex;
}

.annotation-color-input-icon {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  pointer-events: none;
  filter: drop-shadow(0 0 1.5px rgba(255, 255, 255, 0.9)) drop-shadow(0 0 1.5px rgba(255, 255, 255, 0.9));
}

.annotation-width-group {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.annotation-width-input {
  width: 90px;
  accent-color: var(--accent-dark);
}

.annotation-toolbar-btn {
  font-size: 0.8rem;
  padding: 0.35rem 0.7rem;
}

.annotation-draw-toggle--on {
  border-color: var(--accent-dark);
  color: var(--accent-dark);
}

/* Gomme active (23/08/2026, voir canvas-annotation.js buildAnnotationToolbar)
   — fond plein plutôt qu'un simple changement de bordure/texte comme
   .annotation-draw-toggle--on ci-dessus : demandé explicitement pour que le
   mode actif se voie plus clairement (un bouton parmi d'autres au look très
   proche sinon). */
.annotation-eraser-toggle--active {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
  color: #fff;
}

/* Pastille montrant la zone effacée par la gomme, visible seulement pendant
   qu'on appuie (voir showEraserCursor/hideEraserCursor dans
   canvas-annotation.js). Centrée sur le point exact via translate, comme un
   trait à bouts ronds (lineCap "round"). */
.annotation-eraser-cursor {
  position: absolute;
  border-radius: 50%;
  border: 2px solid var(--accent-dark);
  background: rgba(255, 255, 255, 0.35);
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 5;
}

/* --- Pages "Livre" : l'image de la page + des champs à position libre
   (voir public/js/admin-book-page.js, public/js/student-book-page.js). Le
   PDF EST le contenu, pas de "boîte" autour — juste un conteneur relatif
   pour ancrer l'image + les champs + le calque de dessin. --- */

#book-page-canvas-wrap,
#my-book-page-wrap,
#book-correction-canvas-wrap,
#book-exam-canvas-wrap,
#book-exam-correction-canvas-wrap,
#my-exam-book-take-wrap {
  position: relative;
  width: 100%;
}

/* Mode "placement" du prochain champ (voir admin-book-page.js,
   startPlacingBookField, et admin-book-exam.js) : curseur en croix pour
   indiquer que le prochain clic pose le champ à cet endroit précis. */
#book-page-canvas-wrap.book-page-canvas-wrap--placing,
#book-exam-canvas-wrap.book-page-canvas-wrap--placing {
  cursor: crosshair;
}

/* Aperçu en direct pendant le clique-glisse qui dessine un nouveau champ
   (voir admin-book-page.js, onMove dans le pointerdown de placement). */
.book-field-draw-preview {
  position: absolute;
  border: 2px dashed var(--accent-dark);
  background: rgba(125, 9, 228, 0.1);
  border-radius: 4px;
  pointer-events: none;
}

/* Pile de pages empilées (voir migration_add_book_multi_page.sql) : chaque
   page = une image pleine largeur, l'une sous l'autre en flux normal — c'est
   ce qui donne à #book-page-canvas-wrap (position:relative) sa hauteur
   totale, dont dépendent les positions en % des champs posés dessus. Léger
   espace entre deux pages (accepté explicitement : "quitte à ce qu'il y ait
   une légère séparation naturelle entre les pages") plutôt qu'un vrai visuel
   de coupure — juste assez pour distinguer une page de la suivante au scroll. */
.book-page-stack-image {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: 6px;
}

.book-page-stack-item {
  position: relative;
}

.book-page-stack-item .book-field-delete {
  top: 4px;
  right: 4px;
}

.book-field {
  position: absolute;
  box-sizing: border-box;
}

.book-field:not(.book-field--readonly) {
  border: 1.5px dashed rgba(124, 58, 237, 0.6);
  background: rgba(255, 255, 255, 0.55);
  border-radius: 4px;
}

/* Zone à souligner : couleur distincte de la zone de texte (même forme de
   rectangle vide sinon, confusion possible en édition — voir aussi le badge
   .book-field-type-label ci-dessous). */
.book-field--draw_zone:not(.book-field--readonly) {
  border-color: rgba(224, 98, 155, 0.75); /* var(--gold) */
  background: rgba(255, 245, 250, 0.6);
}

/* Zone "Fichier audio" : pas de cadre pointillé ni de fond — juste le bouton
   (éditeur) ou le lecteur (élève/correction), tel quel, sans boîte visible
   autour (remonté explicitement : la boîte gênait côté élève et décalait le
   lecteur de sa position réelle). Taille ignorée côté rendu (posW/posH
   restent enregistrés mais inertes ici) : le lecteur audio a sa propre
   taille native, on ne la force plus — seule la position (left/top) compte,
   ce qui la rend enfin précise au pixel près plutôt qu'approximée par une
   boîte qui ne correspondait pas à la taille réelle du contrôle.
   .book-field--readonly (correction admin) garde son padding, pas de raison
   de la retirer là où il n'y a pas de fond à masquer. */
.book-field--audio:not(.book-field--readonly) {
  border: none;
  background: none;
  width: auto !important;
  height: auto !important;
}

/* Badge texte dans le coin d'un champ, éditeur admin uniquement (jamais
   montré à l'élève) — voir buildBookFieldElement, BOOK_FIELD_EDITOR_BADGE. */
.book-field-type-label {
  position: absolute;
  top: 2px;
  left: 4px;
  font-size: 0.6rem;
  font-family: var(--font-body);
  color: var(--ink-soft);
  opacity: 0.75;
  pointer-events: none;
  white-space: nowrap;
}

.book-field--readonly {
  display: block;
}

/* Les zones de texte (réponse libre) sont peintes APRÈS (donc au-dessus de)
   le calque de dessin dans l'ordre du DOM (#book-exam-correction-fields
   vient après #book-exam-correction-images dans admin.html) — sans ça, le
   clic est capté par le texte (sélection) au lieu du canvas en-dessous,
   empêchant justement de dessiner dans la seule zone où on veut l'autoriser
   (voir isPointAllowed dans canvas-annotation.js). On laisse le clic
   traverser jusqu'au canvas ; les boutons +/- de zoom (au-dessus, cf.
   .book-field-zoom-ctrl) restent cliquables via leur propre pointer-events.
   Pas touché pour case à cocher/zone à souligner/audio : elles ont besoin de
   rester interactives (lecteur audio) ou gèrent déjà leur propre dessin
   (zone à souligner). */
.book-field--readonly:not(.book-field--checkbox):not(.book-field--draw_zone):not(.book-field--audio) {
  pointer-events: none;
  /* Discret rappel visuel de la zone où le dessin de correction est
     autorisé (voir isPointAllowed dans canvas-annotation.js) — sans ça, rien
     ne distingue une zone de texte du reste de la page, la prof ne pouvait
     que deviner où le trait allait "accrocher". */
  border: 1px dashed rgba(124, 58, 237, 0.35);
  border-radius: 4px;
  /* Les zones "à trou" (un mot) sont souvent placées minuscules dans
     l'éditeur — bien assez pour la saisie élève, illisible en correction. On
     agrandit donc le plancher ici (correction uniquement, jamais l'éditeur
     ni la vue élève) pour que le texte de réponse reste lisible même dans
     une boîte d'origine étroite ; le +/- par boîte reste dispo au-delà. */
  min-width: 2.6rem;
  min-height: 1.7rem;
}

/* Texte de la réponse en correction, séparé de .book-field--readonly pour
   laisser la place à .book-field-zoom-ctrl (boutons +/- collés à la boîte,
   demandé explicitement plutôt qu'un réglage global) sans qu'il écrase le
   textContent à chaque re-rendu. */
.book-field-answer-text {
  position: relative; /* ancre .book-field-word-count en filigrane, voir plus bas */
  width: 100%;
  height: 100%;
  overflow: auto;
  font-family: var(--font-body);
  font-size: 1.1rem;
  color: var(--ink);
  white-space: pre-wrap;
  padding: 0.2rem 0.25rem;
  box-sizing: border-box;
  /* Fond légèrement opaque pour que le texte reste lisible par-dessus une
     page scannée chargée (lignes, images) — demandé après relecture d'une
     copie où le texte se fondait dans le fond. */
  background: rgba(255, 255, 255, 0.75);
  border-radius: 3px;
}

.book-field-zoom-ctrl {
  position: absolute;
  top: -0.6rem;
  right: -0.6rem;
  display: flex;
  gap: 2px;
  z-index: 2;
  pointer-events: auto;
}

/* Compteur de mots des zones de texte "Livre" (examens + fiches), côté prof
   uniquement — en filigrane par-dessus le texte (ancré à .book-field-answer-text,
   voir position:relative ci-dessus) plutôt que dans le flux : sur les toutes
   petites boîtes ("1 mot") le badge en flux forçait à lui seul un
   rétrécissement de la police (voir fitBookFieldFontSize), pour un gain de
   lisibilité nul. En absolu il ne compte plus dans le calcul de hauteur. */
.book-field-word-count {
  position: absolute;
  right: 0.15rem;
  bottom: 0.05rem;
  font-size: 0.65rem;
  font-weight: 600;
  color: var(--accent-dark, #7c3aed);
  opacity: 0.55;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.6);
  border-radius: 2px;
  padding: 0 2px;
  line-height: 1.3;
}

.book-field-zoom-btn {
  width: 1.1rem;
  height: 1.1rem;
  line-height: 1;
  padding: 0;
  border: 1px solid var(--accent-dark, #7c3aed);
  border-radius: 50%;
  background: #fff;
  color: var(--accent-dark, #7c3aed);
  font-size: 0.7rem;
  font-weight: bold;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.book-field-zoom-btn:hover {
  background: var(--accent-dark, #7c3aed);
  color: #fff;
}

.book-field-input {
  width: 100%;
  height: 100%;
  border: none;
  outline: none;
  resize: none;
  overflow: hidden; /* Safari ignore resize:none seul et garde son coin de redimensionnement natif */
  background: none;
  font-family: var(--font-body);
  font-size: 1.15rem;
  color: var(--ink);
  padding: 0.2rem 0.25rem;
}

/* Une case à cocher n'a pas besoin du padding pensé pour le texte (voir
   .book-field-input ci-dessus) — en le gardant, la case native rendait plus
   petite que sa boîte et décalée selon le navigateur (padding sur un
   <input type="checkbox"> se comporte de façon incohérente d'un moteur à
   l'autre). accent-color aligne aussi sa couleur sur le violet du site
   plutôt que le bleu par défaut du navigateur. */
.book-field--checkbox .book-field-input {
  cursor: pointer;
  display: block;
  padding: 0;
  margin: 0;
  accent-color: var(--accent-dark);
}

/* Filigrane prof "bonne réponse" (voir admin-book-page.js
   buildBookAnswerFieldElement) : masque léger posé par-dessus la case,
   jamais interactif (pointer-events: none) et jamais envoyé à l'élève. */
.book-field-checkbox-watermark {
  position: absolute;
  inset: -3px;
  border-radius: 4px;
  background: rgba(125, 9, 228, 0.18);
  outline: 1.5px dashed rgba(125, 9, 228, 0.55);
  outline-offset: 1px;
  pointer-events: none;
}

/* "Zone à caractères limités" : rappel de la réponse attendue en vue de
   correction prof (voir buildBookAnswerFieldElement), même esprit discret que
   le filigrane des cases à cocher ci-dessus. */
.book-field-restricted-expected {
  font-size: 0.7rem;
  color: #1a9c5c;
  margin-top: 0.15rem;
}

.book-field-delete {
  position: absolute;
  top: -0.6rem;
  right: -0.6rem;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: none;
  background: #b3261e;
  color: #fff;
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.book-field-resize-handle {
  position: absolute;
  bottom: -4px;
  right: -4px;
  width: 10px;
  height: 10px;
  background: var(--accent-dark);
  border-radius: 2px;
  cursor: nwse-resize;
}

/* Zone "Fichier audio" (voir buildBookFieldElement, admin-book-page.js) :
   bouton pour lier/changer le fichier + mini lecteur de test, tous deux
   compacts pour tenir dans une petite zone. */
.book-field-audio-link-btn {
  border: 1px solid var(--accent-dark);
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  color: var(--accent-dark);
  font-size: 0.75rem;
  padding: 0.3rem 0.6rem;
  white-space: nowrap;
}

.book-field-audio-link-player {
  display: block;
}

/* Transcription écrite d'un audio : saisie dans l'éditeur de fiche (voir
   .book-field-audio-transcript-input plus bas), lecture seule + repliable en
   vue de correction prof uniquement (voir admin-book-page.js
   buildAudioTranscriptControl) — le champ audio lui-même est minuscule
   (juste l'icône + le lecteur), donc ce bloc déborde volontairement
   par-dessus le reste de la page au besoin. */
.book-field-transcript-wrap {
  position: relative;
  z-index: 5;
  margin-top: 0.3rem;
}

.book-field-transcript-toggle {
  border: 1px solid rgba(125, 9, 228, 0.4);
  background: #fff;
  color: var(--accent-dark);
  border-radius: 6px;
  padding: 0.15rem 0.5rem;
  font-size: 0.75rem;
  white-space: nowrap;
  cursor: pointer;
}

.book-field-transcript-panel {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 0.25rem;
  width: 280px;
  max-width: 60vw;
  background: #fff;
  border: 1px solid rgba(125, 9, 228, 0.35);
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
  padding: 0.5rem;
  font-size: 0.8rem;
  white-space: pre-wrap;
}

/* Saisie de la transcription dans l'éditeur (buildBookFieldElement, champ
   audio) — sous le bouton/lecteur, toujours visible en édition. */
.book-field-audio-transcript-label {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.7rem;
  color: #666;
}

.book-field-audio-transcript-input {
  display: block;
  width: 220px;
  min-height: 60px;
  resize: vertical;
  font: inherit;
  font-size: 0.78rem;
  border: 1px solid #ddd;
  border-radius: 6px;
  padding: 0.35rem;
  margin-top: 0.2rem;
  box-sizing: border-box;
}

.book-field-audio-link-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Nombre d'écoutes max (examens "Livre" uniquement, voir
   migration_add_exam_audio_max_plays.sql) — champ compact posé sous le
   bouton "Choisir un fichier" dans admin-book-exam.js. */
.book-field-audio-maxplays-label {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.7rem;
  color: var(--ink-soft);
}

.book-field-audio-maxplays-input {
  width: 4rem;
  padding: 0.15rem 0.3rem;
  border: 1px solid var(--border-color, #ddd);
  border-radius: 4px;
  font-size: 0.75rem;
}

/* Groupe de cases exclusives + réponse attendue (voir
   migration_add_book_checkbox_grouping.sql), admin-book-exam.js et
   admin-book-page.js : la boîte d'une case est minuscule par défaut (24x24px,
   voir BOOK_EXAM_FIELD_DEFAULT_SIZE_PX), ces contrôles débordent donc
   volontairement en dessous plutôt que de forcer la case à s'agrandir. */
.book-field-checkbox-controls {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 2px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: #fff;
  border: 1px solid var(--border-color, #ddd);
  border-radius: 4px;
  padding: 3px 5px;
  z-index: 2;
  white-space: nowrap;
}

.book-field-checkbox-group-label,
.book-field-checkbox-correct-label {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.65rem;
  color: var(--ink-soft);
}

.book-field-checkbox-group-input {
  width: 4.5rem;
  padding: 0.1rem 0.25rem;
  border: 1px solid var(--border-color, #ddd);
  border-radius: 4px;
  font-size: 0.7rem;
}

.book-field-checkbox-correct-select {
  padding: 0.1rem 0.2rem;
  border: 1px solid var(--border-color, #ddd);
  border-radius: 4px;
  font-size: 0.7rem;
}

/* Indicateur cliquable de réponse attendue (remplace le select "Attendu",
   voir buildBookExamFieldElement) — occupe toute la case (24x24px par
   défaut) pour rester visible même minuscule, sans déborder comme
   .book-field-checkbox-controls. */
.book-field-checkbox-mark {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  font-weight: bold;
  line-height: 1;
  cursor: pointer;
  pointer-events: none;
  border-radius: 3px;
}

.book-field-checkbox-mark--checked {
  color: #1a9c5c;
  background: rgba(26, 156, 92, 0.25);
}

.book-field-checkbox-mark--unchecked {
  color: #d13c3c;
  background: rgba(209, 60, 60, 0.2);
}

/* "Revoir ma copie" côté élève (voir student-book-exam.js
   buildBookExamFieldElement) : colore la case elle-même plutôt qu'une icône
   à côté, pour rester lisible même sur une case minuscule (quelques px de
   large sur une page scannée). La bonne réponse est toujours en vert (cochée
   ou non, pour montrer ce qu'il fallait répondre) ; une case cochée à tort
   passe en rouge — jamais les deux classes en même temps sur une case. */
.book-field-checkbox--correct-answer {
  outline: 2px solid #1a9c5c;
  outline-offset: 1px;
  background: rgba(26, 156, 92, 0.55) !important;
  border-radius: 3px;
}

.book-field-checkbox--wrong {
  outline: 2px solid #d13c3c;
  outline-offset: 1px;
  background: rgba(209, 60, 60, 0.55) !important;
  border-radius: 3px;
}

/* "Bonne réponse : X" sous une zone à caractères limités ratée (voir
   restrictedAnswerReveal, student-book-page.js/student-book-exam.js) —
   positionné sous le champ plutôt que dedans (souvent trop petit pour du
   texte en plus de la réponse de l'élève), pastille blanche pour rester
   lisible par-dessus l'image scannée. */
.book-field-restricted-answer-reveal {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 0.2rem;
  padding: 0.1rem 0.35rem;
  background: #ffffff;
  color: #1a9c5c;
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
  border-radius: 3px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
  z-index: 5;
}

/* Lecteur audio restreint côté élève (student-book-exam.js) : juste un
   bouton, pas de <audio controls> natif (pause/avance interdits une fois
   lancé, voir buildBookExamAudioField). */
.book-field-audio-restricted {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.book-field-audio-restricted-status {
  font-size: 0.7rem;
}

/* Curseur de volume (voir buildBookExamAudioField) — seul réglage laissé
   libre à l'élève sur ce lecteur, tout le reste (play/pause/seek) est bloqué. */
.book-field-audio-volume {
  display: flex;
  align-items: center;
  gap: 0.2rem;
  font-size: 0.85rem;
}

.book-field-audio-volume-slider {
  width: 4.5rem;
  accent-color: var(--accent-dark);
}

/* Zone "Enregistrement vocal" élève (voir buildVoiceRecorder) : le composant
   partagé est pensé pour une carte d'exercice pleine largeur, ici la boîte
   est petite — on tasse ses propres contrôles pour qu'ils tiennent. */
.book-field--voice_recording .voice-recorder {
  width: 100%;
  height: 100%;
  overflow: auto;
}

.book-field--voice_recording .voice-recorder-controls {
  flex-wrap: wrap;
}

.book-field--voice_recording .voice-recorder-btn {
  font-size: 0.75rem;
  padding: 0.3rem 0.5rem;
}

.book-field--voice_recording .voice-recorder-player {
  width: 100%;
  max-height: 2.2rem;
}

/* Bulle "+ Champ" (éditeur admin) et bulle 🖊️ (correction admin) — même
   patron que la bulle de chat (chat-widget.js, .chat-bubble), décalées à
   gauche pour ne jamais se superposer si le chat est aussi ouvert. */
.book-field-bubble,
.book-pen-bubble {
  position: fixed;
  bottom: 1.5rem;
  left: 1.5rem;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  background: var(--accent-dark);
  color: #fff;
  font-size: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(44, 31, 69, 0.3);
  z-index: 200;
}

/* Même piège [hidden]/display:flex déjà géré pour les panneaux ci-dessous
   (voir project-infra-and-gotchas) — oublié ici pour les bulles elles-mêmes :
   sans ça, .hidden=true en JS ne les masquait jamais réellement. */
.book-field-bubble[hidden],
.book-pen-bubble[hidden] {
  display: none;
}

.book-field-bubble:hover,
.book-pen-bubble:hover {
  background: var(--accent);
}

.book-field-panel,
.book-pen-panel {
  position: fixed;
  bottom: 5.5rem;
  left: 1.5rem;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.2);
  padding: 0.75rem;
  /* Au-dessus de 200 : sinon, si le panneau grandit (ajout d'options) au
     point de dépasser en hauteur la bulle "pages" voisine (même z-index,
     peinte après dans le DOM), celle-ci resterait visible par-dessus le
     panneau ouvert — demandé explicitement à corriger partout où ce duo
     bulle/panneau + bulle "pages" apparaît. */
  z-index: 210;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.book-pen-panel {
  flex-direction: row;
  flex-wrap: wrap;
  max-width: 320px;
}

/* .btn-secondary est pensé pour un fond violet foncé "verre" (--glass-ink,
   quasi blanc) — illisible ici car .book-field-panel/.book-pen-panel ont un
   fond blanc opaque plein. Surcharge locale en couleurs sombres. */
.book-field-panel .btn-secondary,
.book-pen-panel .btn-secondary {
  background: #fff;
  border-color: var(--accent-dark);
  color: var(--accent-dark);
}

.book-field-panel .btn-secondary:hover,
.book-pen-panel .btn-secondary:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
  color: #fff;
}

/* Même piège [hidden]/display:flex que .chat-panel ailleurs dans ce fichier :
   sans ça, [hidden] resterait sans effet sur ces panneaux. */
.book-field-panel[hidden],
.book-pen-panel[hidden] {
  display: none;
}

/* Bulle "aller à une page" côté admin (éditeur ET correction, voir
   admin-book-page.js's setupBookAdminPageNav) — empilée AU-DESSUS de la
   bulle ✏️/🖊️ (demandé explicitement), assez haut pour ne pas chevaucher
   leur panneau respectif (qui s'ouvre juste au-dessus d'elles, voir
   .book-field-panel/.book-pen-panel ci-dessus). */
.book-admin-page-nav-bubble {
  position: fixed;
  bottom: 8rem;
  left: 1.5rem;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  background: var(--accent-dark);
  color: #fff;
  font-size: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(44, 31, 69, 0.3);
  z-index: 200;
}

.book-admin-page-nav-bubble[hidden] {
  display: none;
}

.book-admin-page-nav-bubble:hover {
  background: var(--accent);
}

/* Bouton flottant "Valider la correction" (examens "Livre") — même patron
   que .book-pen-bubble/.book-admin-page-nav-bubble (fixed, ombre, même
   z-index), mais à droite plutôt qu'à gauche pour ne jamais chevaucher la
   bulle 🖊️/la bulle "pages" empilées à gauche, et assez haut (6rem) pour
   rester au-dessus de la bulle de chat (.chat-bubble, bottom:1.5rem right)
   qui partage ce coin de l'écran. Bouton texte direct (pas de bulle+panneau
   à replier) : contrairement à ✏️/📑, il n'y a rien à replier, juste une
   action à déclencher une fois la correction terminée. */
.book-exam-validate-btn {
  position: fixed;
  bottom: 6rem;
  right: 1.5rem;
  border: none;
  border-radius: 999px;
  background: var(--accent-dark);
  color: #fff;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.9rem;
  padding: 0.75rem 1.25rem;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(44, 31, 69, 0.3);
  z-index: 200;
}

.book-exam-validate-btn[hidden] {
  display: none;
}

.book-exam-validate-btn:hover {
  background: var(--accent);
}

.book-exam-validate-btn:disabled {
  opacity: 0.7;
  cursor: default;
}

.book-admin-page-nav-panel {
  position: fixed;
  bottom: 12rem;
  left: 1.5rem;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.2);
  padding: 0.75rem;
  z-index: 210;
  display: grid;
  grid-template-columns: repeat(5, 2.2rem);
  gap: 0.4rem;
  max-height: 60vh;
  max-width: calc(100vw - 3rem);
  overflow-y: auto;
}

.book-admin-page-nav-panel[hidden] {
  display: none;
}

/* Bulle "aller à une page" (élève, voir student-book-page.js) — même
   position/patron que les bulles admin ci-dessus (jamais affichées en même
   temps, chrome différent), décalée à gauche pour ne jamais se superposer à
   la bulle de chat qui, elle, est à droite sur ces mêmes pages élève. */
.book-page-nav-bubble {
  position: fixed;
  bottom: 1.5rem;
  left: 1.5rem;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  background: var(--accent-dark);
  color: #fff;
  font-size: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(44, 31, 69, 0.3);
  z-index: 200;
}

.book-page-nav-bubble[hidden] {
  display: none;
}

.book-page-nav-bubble:hover {
  background: var(--accent);
}

.book-page-nav-panel {
  position: fixed;
  bottom: 5.5rem;
  left: 1.5rem;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.2);
  padding: 0.75rem;
  z-index: 210;
  display: grid;
  grid-template-columns: repeat(5, 2.2rem);
  gap: 0.4rem;
  max-height: 60vh;
  max-width: calc(100vw - 3rem);
  overflow-y: auto;
}

.book-page-nav-panel[hidden] {
  display: none;
}

/* Remontée au-dessus de la bulle 🖊️ personnelle (prof/webmaster consultant
   "Mon espace", voir student-book-page.js) — même principe que
   .book-admin-page-nav-bubble côté correction. Classe modificatrice plutôt
   qu'une position fixe : un élève, qui ne voit jamais la bulle 🖊️, garde la
   bulle 📑 tout en bas comme avant. */
.book-page-nav-bubble--raised {
  bottom: 8rem;
}

.book-page-nav-panel--raised {
  bottom: 12rem;
}

/* Bulle 🖊️ (dessin personnel prof/webmaster sur "Mon espace"/"Mes cours",
   voir student-book-page.js) — même patron que .book-pen-bubble côté
   correction admin, dupliquée ici par convention du projet (un fichier CSS
   par contexte de page, voir .book-page-nav-bubble ci-dessus). */
.book-page-pen-bubble {
  position: fixed;
  bottom: 1.5rem;
  left: 1.5rem;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  background: var(--accent-dark);
  color: #fff;
  font-size: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(44, 31, 69, 0.3);
  z-index: 200;
}

.book-page-pen-bubble[hidden] {
  display: none;
}

.book-page-pen-bubble:hover {
  background: var(--accent);
}

.book-page-pen-panel {
  position: fixed;
  bottom: 5.5rem;
  left: 1.5rem;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.2);
  padding: 0.75rem;
  z-index: 210;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  max-width: 320px;
  gap: 0.5rem;
}

.book-page-pen-panel[hidden] {
  display: none;
}

/* .btn-secondary (base de .annotation-toolbar-btn, voir canvas-annotation.js
   buildAnnotationToolbar — réutilisée telle quelle ici) est stylée pour le
   fond violet du redesign : texte quasi blanc, fond/bordure translucides.
   .book-pen-panel/.book-page-pen-panel sont restés blancs (voir plus haut,
   jamais repassés au redesign) — texte blanc sur blanc, illisible, remonté
   explicitement. Le toggle "Dessin activé" (accent-dark) était déjà correct,
   restauré ci-dessous après l'override générique. */
.book-pen-panel .annotation-toolbar-btn,
.book-page-pen-panel .annotation-toolbar-btn {
  background: #fff;
  border-color: var(--paper-line);
  color: var(--ink);
}

.book-pen-panel .annotation-toolbar-btn:hover,
.book-page-pen-panel .annotation-toolbar-btn:hover {
  background: var(--paper);
  border-color: var(--accent-dark);
}

.book-pen-panel .annotation-draw-toggle--on,
.book-page-pen-panel .annotation-draw-toggle--on {
  border-color: var(--accent-dark);
  color: var(--accent-dark);
}

.book-pen-panel .annotation-eraser-toggle--active,
.book-page-pen-panel .annotation-eraser-toggle--active {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
  color: #fff;
}

.book-page-nav-btn {
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 6px;
  border: 1px solid var(--border-color, #ddd);
  background: #fff;
  color: var(--accent-dark);
  font-size: 0.85rem;
  cursor: pointer;
}

.book-page-nav-btn:hover {
  background: var(--accent-dark);
  color: #fff;
}

/* --- Photo de profil --- */

.top-nav-avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  margin-right: 0.35rem;
}

/* Petit avatar réutilisé partout où un nom d'utilisateur apparaît côté admin
   (liste des utilisateurs, accès, copies reçues...) — voir public/js/avatar.js */
.user-avatar-small {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  object-fit: cover;
  vertical-align: middle;
  margin-right: 0.4rem;
  flex-shrink: 0;
}

.profile-photo-picker {
  position: relative;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  border: 2px dashed var(--paper-line);
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  overflow: hidden;
  margin: 0 auto 0.5rem;
  transition: border-color 0.2s ease;
}

.profile-photo-picker:hover,
.profile-photo-picker:focus-visible {
  border-color: var(--accent-dark);
  outline: none;
}

.profile-photo-preview {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.profile-photo-placeholder {
  font-size: 0.8rem;
  color: var(--ink-soft);
  text-align: center;
  padding: 0 0.75rem;
}

/* --- Bulle de messagerie flottante (prof <-> élèves) --- */

.chat-bubble {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: none;
  /* Turquoise plein comme le reste des CTA du redesign (nav, badges) —
     un bouton flottant a besoin de rester opaque/bien visible par-dessus
     n'importe quel contenu, jamais en "verre" translucide comme les cartes. */
  background: var(--cyan);
  color: #0b1a1a;
  font-size: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(44, 31, 69, 0.35);
  z-index: 200;
  transition: background 0.2s ease, transform 0.15s ease;
}

.chat-bubble:hover,
.chat-bubble:focus-visible {
  background: #6ff2f0;
  transform: scale(1.05);
  outline: none;
}

.chat-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 20px;
  height: 20px;
  padding: 0 4px;
  border-radius: 999px;
  background: #b3261e;
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid #fff;
}

.chat-panel {
  position: fixed;
  bottom: 5.5rem;
  right: 1.5rem;
  width: 320px;
  max-width: calc(100vw - 2rem);
  height: 440px;
  max-height: calc(100vh - 8rem);
  /* Même carte "verre" (dégradé violet plein + flou) que les modales du
     redesign (.user-profile-modal-card, etc.) — jamais le fond blanc
     "papier" d'origine. */
  background: linear-gradient(155deg, #6a3fc9, #8a5cf0);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  box-shadow: 0 20px 50px rgba(44, 31, 69, 0.35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: 200;
}

/* Même piège que .modal-overlay plus haut : "display: flex" ci-dessus (et sur
   .chat-badge / .chat-thread) écrase le "display: none" par défaut du
   navigateur pour [hidden] — sans ces règles, basculer .hidden en JS n'a
   aucun effet visuel et l'élément reste affiché en permanence. */
.chat-panel[hidden],
.chat-badge[hidden],
.chat-thread[hidden] {
  display: none;
}

/* Vue "agrandie" façon Discord (demandée en plus de simplement agrandir la
   bulle de base, voir public/js/chat-widget.js toggleChatExpand) : liste de
   contacts + fil ouvert visibles ensemble en permanence, plutôt que l'unique
   colonne qui alterne entre les deux (mode compact, inchangé). Grandit
   depuis le même coin bas-droit que le panneau compact (bottom/right
   inchangés) — jamais repositionné, juste agrandi. Gardée entièrement dans
   ce media query : en dessous de 700px, .chat-panel--expanded n'a AUCUN
   effet (même si la classe est déjà posée, ex. fenêtre redimensionnée après
   coup) — repli automatique sur le mode compact plutôt qu'une grille cassée
   sur petit écran. */
@media (min-width: 700px) {
  .chat-panel--expanded {
    width: min(920px, 94vw);
    height: min(640px, 88vh);
    display: grid;
    grid-template-columns: 280px 1fr;
    grid-template-rows: auto auto 1fr;
    grid-template-areas:
      "header header"
      "toolbar thread"
      "list thread";
  }

  .chat-panel--expanded > .chat-panel-header {
    grid-area: header;
  }

  .chat-panel--expanded > .chat-list-toolbar {
    grid-area: toolbar;
    border-right: 1px solid var(--glass-border);
  }

  .chat-panel--expanded > .chat-contact-list {
    grid-area: list;
    border-right: 1px solid var(--glass-border);
  }

  .chat-panel--expanded > .chat-thread {
    grid-area: thread;
  }
}

@media (max-width: 699px) {
  .chat-expand-btn {
    display: none;
  }
}

.chat-panel-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.9rem 1rem;
  /* Se fond dans le dégradé de .chat-panel plutôt qu'une barre pleine à part
     — juste un filet pour marquer la séparation avec la liste en dessous. */
  border-bottom: 1px solid var(--glass-border);
  color: var(--glass-ink);
  flex-shrink: 0;
}

.chat-back-btn,
.chat-close-btn,
.chat-expand-btn {
  background: none;
  border: none;
  color: #fff;
  font-size: 1.1rem;
  cursor: pointer;
  padding: 0.1rem 0.3rem;
  line-height: 1;
}

.chat-panel-title {
  flex: 1;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
}

.chat-search {
  margin: 0.75rem 1rem 0.5rem;
  font-family: var(--font-body);
  font-size: 0.88rem;
  padding: 0.5rem 0.7rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 6px;
  color: var(--glass-ink);
  flex-shrink: 0;
}

.chat-search::placeholder {
  color: var(--glass-ink-soft);
}

.chat-contact-list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  flex: 1;
}

.chat-contact-empty {
  padding: 1rem;
  color: var(--glass-ink-soft);
  font-size: 0.88rem;
  text-align: center;
}

.chat-contact-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 1rem;
  cursor: pointer;
  border-bottom: 1px solid var(--glass-border);
}

.chat-contact-item:hover,
.chat-contact-item:focus-visible {
  background: rgba(255, 255, 255, 0.06);
  outline: none;
}

/* Épingle personnelle (voir public/js/chat-widget.js toggleChatPin) : léger
   fond distinctif, épinglés toujours en tête de liste côté serveur. Cyan
   plutôt que l'ancien rose, cohérent avec le reste des accents du redesign. */
.chat-contact-item--pinned {
  background: rgba(64, 234, 232, 0.1);
}

.chat-pin-btn {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.9rem;
  padding: 0.1rem;
  opacity: 0.3;
  filter: grayscale(1);
}

.chat-contact-item:hover .chat-pin-btn,
.chat-contact-item:focus-within .chat-pin-btn,
.chat-contact-item--pinned .chat-pin-btn {
  opacity: 1;
  filter: none;
}

.chat-contact-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.chat-contact-name {
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--glass-ink);
}

.chat-contact-role {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--cyan);
}

.chat-contact-preview {
  font-size: 0.78rem;
  color: var(--glass-ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chat-contact-badge {
  flex-shrink: 0;
  min-width: 20px;
  height: 20px;
  padding: 0 4px;
  border-radius: 999px;
  background: #b3261e;
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* --- Chat de groupe (voir public/js/chat-widget.js) --- */

.chat-list-toolbar {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.chat-list-toolbar .chat-search {
  flex: 1;
  min-width: 0;
}

.chat-create-group-btn {
  margin: 0.75rem 1rem 0.5rem 0;
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--glass-border);
  border-radius: 6px;
  background: var(--glass-bg);
  color: var(--glass-ink);
  cursor: pointer;
  white-space: nowrap;
}

.chat-create-group-btn:hover {
  background: rgba(255, 255, 255, 0.15);
}

.chat-manage-group-btn {
  background: none;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 999px;
  color: #fff;
  font-size: 0.72rem;
  font-weight: 600;
  padding: 0.2rem 0.6rem;
  cursor: pointer;
}

.chat-manage-group-btn:hover {
  background: rgba(255, 255, 255, 0.15);
}

.chat-group-icon {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
}

.chat-thread-participants {
  flex-shrink: 0;
  margin: 0.6rem 1rem 0;
  font-size: 0.78rem;
  color: var(--glass-ink-soft);
}

.chat-message-sender {
  margin: 0 0 0.15rem;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--cyan);
}

.chat-group-modal-title-input {
  width: 100%;
  margin: 0 0 0.75rem;
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--glass-border);
  border-radius: 6px;
  background: var(--glass-bg);
  color: var(--glass-ink);
}

.chat-group-modal-title-input::placeholder {
  color: var(--glass-ink-soft);
}

/* --- Modale "Créer un groupe"/"Gérer les membres" (chat-widget.js) : même
   carte "verre" que .chat-panel/.user-profile-modal-card, plutôt que
   .access-modal-card générique restée blanche. Réutilise .access-search/
   .access-list/.access-item comme la modale Profil — mêmes surcharges. */
.chat-group-modal-card {
  max-width: 420px;
  background: linear-gradient(155deg, #6a3fc9, #8a5cf0);
  color: var(--glass-ink);
  text-align: left;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.chat-group-modal-card .modal-title {
  color: var(--glass-ink);
  text-align: left;
}

.chat-group-modal-card .form-message {
  color: var(--glass-ink);
}

.chat-group-modal-card .form-message--error {
  color: var(--pill-danger-ink);
}

.chat-group-modal-card .access-search {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--glass-ink);
}

.chat-group-modal-card .access-search::placeholder {
  color: var(--glass-ink-soft);
}

.chat-group-modal-card .access-list,
.chat-group-modal-card .access-list-empty {
  color: var(--glass-ink-soft);
}

.chat-group-modal-card .access-list {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--glass-border);
}

.chat-group-modal-card .access-item {
  border-bottom-color: var(--glass-border);
}

.chat-group-modal-card .access-item label:hover {
  background: rgba(255, 255, 255, 0.06);
}

.chat-group-modal-card .access-item-name {
  color: var(--glass-ink);
}

.chat-group-modal-card .access-item-email {
  color: var(--glass-ink-soft);
}

.chat-thread {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* Recouvre tout le fil tant qu'aucune conversation n'est sélectionnée en vue
   agrandie (voir toggleChatExpand côté JS) — jamais affiché en mode compact,
   où .chat-thread reste simplement caché (hidden) dans ce cas. */
.chat-thread-empty {
  display: none;
}

.chat-thread--empty .chat-thread-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 2rem;
  background: var(--glass-bg);
  color: var(--glass-ink-soft);
  font-size: 0.9rem;
  z-index: 1;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 0.75rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.chat-message {
  position: relative;
  max-width: 78%;
  padding: 0.5rem 0.75rem;
  border-radius: 14px;
  font-size: 0.88rem;
  line-height: 1.4;
  word-break: break-word;
}

/* Supprimer soi-même un message — même patron de révélation au survol que
   .chat-pin-btn (opacité 0.3 par défaut, jamais 0 : reste repérable au
   toucher sur tablette, où :hover ne se déclenche jamais). */
.chat-message-delete-btn {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg-strong);
  color: var(--glass-ink);
  font-size: 0.7rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0.3;
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.chat-message--mine:hover .chat-message-delete-btn,
.chat-message--mine:focus-within .chat-message-delete-btn {
  opacity: 1;
}

.chat-message-delete-btn:hover {
  background: var(--pill-danger-bg);
  color: var(--pill-danger-ink);
  border-color: var(--pill-danger-ink);
}

.chat-message--mine {
  align-self: flex-end;
  background: var(--cyan);
  color: #0b1a1a;
  border-bottom-right-radius: 4px;
}

.chat-message--theirs {
  align-self: flex-start;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  color: var(--glass-ink);
  border-bottom-left-radius: 4px;
}

.chat-attachment-preview {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0.75rem 0.5rem;
  padding: 0.4rem 0.6rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  font-size: 0.8rem;
  color: var(--glass-ink-soft);
  flex-shrink: 0;
}

.chat-attachment-preview[hidden] {
  display: none;
}

.chat-attachment-preview-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-attachment-preview-remove {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--glass-ink-soft);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0.2rem;
}

.chat-attachment-preview-remove:hover {
  color: #b3261e;
}

.chat-message-text {
  margin: 0;
}

.chat-message-image {
  display: block;
  max-width: 100%;
  max-height: 220px;
  border-radius: 10px;
  margin-bottom: 0.3rem;
}

.chat-message-video {
  display: block;
  max-width: 100%;
  max-height: 220px;
  border-radius: 10px;
  margin-bottom: 0.3rem;
}

.chat-message-file-link {
  display: inline-block;
  color: inherit;
  text-decoration: underline;
  font-size: 0.85rem;
}

.chat-message-attachment-expired {
  margin: 0;
  font-size: 0.8rem;
  font-style: italic;
  opacity: 0.75;
}

/* --- Examens : questions "réponse libre" (correction manuelle) --- */

.exam-question-type-select {
  display: block;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: #fff;
  color: var(--ink);
  margin-bottom: 0.6rem;
}

/* Même piège [hidden]/display:flex que .chat-panel plus haut : .exam-options-list
   a display:flex, donc masquer via .hidden a besoin de cette règle explicite. */
.exam-options-list[hidden] {
  display: none;
}

.exam-take-free-text-input {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  color: var(--ink);
}

/* Simple conteneur de mise en page (la vraie "boîte" visuelle est
   .exercise-answer-display, réutilisée comme ancre du calque de dessin). */
.exam-free-text-review {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.exam-free-text-review[hidden] {
  display: none;
}

.exam-free-text-answer {
  margin: 0 0 0.6rem;
  color: var(--glass-ink);
  white-space: pre-wrap;
}

/* Compteur de mots discret sur les réponses libres, côté prof (correction
   d'examens ET d'exercices de fiche, voir buildAnswerWordCountEl dans
   admin.js) — jamais le focus, juste une info d'appoint en coin. */
.answer-word-count {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.75rem;
  color: var(--glass-ink-soft);
  text-align: right;
}

.exam-correct-toggle {
  display: flex;
  gap: 0.5rem;
}

.exam-correct-btn {
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.4rem 0.8rem;
  border-radius: 999px;
  border: 1px solid var(--paper-line);
  background: #fff;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.exam-correct-btn--correct.exam-correct-btn--active {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

.exam-correct-btn--incorrect.exam-correct-btn--active {
  background: #b3261e;
  border-color: #b3261e;
  color: #fff;
}

.exam-correct-badge {
  display: inline-block;
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
}

.exam-correct-badge--correct {
  background: rgba(47, 158, 86, 0.12);
  color: var(--success);
}

.exam-correct-badge--incorrect {
  background: rgba(179, 38, 30, 0.08);
  color: #b3261e;
}

/* --- Présences (onglet admin + onglet élève) --- */

/* Modale "verre" dédiée, reprenant le mockup validé ("+ Nouvelle séance") :
   dégradé violet identique à celui des cartes .screen du plan plutôt qu'un
   popup blanc classique, champs translucides, libellés Fredoka. Entièrement
   scopée à cette modale (jamais le .modal-card générique, réutilisé par
   d'autres popups pas encore repassés au redesign) — voir aussi
   project-infra-and-gotchas sur le risque de supposer une classe partagée
   safe sur un fond différent : chaque règle ci-dessous ne touche QUE ce
   qui vit réellement dans .attendance-session-modal-card.
   Hauteur : le contenu (date/heure/récurrence/cours/intitulé/élèves/
   exceptions) dépasse facilement la hauteur d'écran, surtout en édition
   (bouton Supprimer + section exceptions en plus) — .modal-card de base n'a
   pas de limite de hauteur, la modale débordait sans moyen d'atteindre
   "Enregistrer" (remonté explicitement). Le reste de la modale scrolle ;
   .access-list garde en plus son propre scroll interne pour la liste
   d'élèves, donc rien ne change là. */
.attendance-session-modal-card {
  background: linear-gradient(155deg, #6a3fc9, #8a5cf0);
  color: var(--glass-ink);
  text-align: left;
  max-height: calc(100vh - 3rem);
  overflow-y: auto;
}

.attendance-session-modal-card .modal-title {
  color: var(--glass-ink);
  text-align: left;
}

/* .radio-option est déjà blanc par défaut (pensée pour inscription.html /
   un fond violet) — correct tel quel maintenant que cette modale est sombre,
   AUCUN override nécessaire ici (contrairement à .move-item-modal-card,
   restée blanche, qui a besoin du sien). */

/* Base pour un modal-card blanc classique (ex. flashcard-pool-modal/
   flashcard-word-modal) — .attendance-session-modal-card ci-dessous la
   surcharge pour son propre fond "verre" (couleur claire plutôt que
   sombre). */
.field-label {
  display: block;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0.75rem 0 0.3rem;
}

.attendance-session-modal-card .field-label {
  display: block;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--glass-ink-soft);
  margin: 1rem 0 0.4rem;
}

.attendance-session-modal-card h2.modal-title + .field-label {
  margin-top: 0;
}

.attendance-session-modal-card .field-hint {
  color: var(--glass-ink-soft);
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
}

.attendance-session-modal-card .sheet-title-input,
.attendance-session-modal-card .access-search {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--glass-ink);
  border-radius: 10px;
  /* Fait rendre l'icône native du sélecteur date/heure en clair plutôt
     qu'en noir sur noir (comportement par défaut du navigateur, invisible
     sur ce fond) — voir capture remontée par l'utilisateur. */
  color-scheme: dark;
}

.attendance-session-modal-card .sheet-title-input::placeholder,
.attendance-session-modal-card .access-search::placeholder {
  color: var(--glass-ink-soft);
}

.attendance-session-modal-card .access-list {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--glass-border);
}

.attendance-session-modal-card .access-item {
  border-bottom-color: var(--glass-border);
}

.attendance-session-modal-card .access-item label:hover {
  background: rgba(255, 255, 255, 0.06);
}

.attendance-session-modal-card .access-item-name {
  color: var(--glass-ink);
}

.attendance-session-modal-card .access-item-email {
  color: var(--glass-ink-soft);
}

.attendance-session-modal-card .form-message {
  color: var(--glass-ink);
}

/* .form-message--error/--success de base sont taillés pour un fond blanc
   (rouge/violet foncés) — invisibles sur ce dégradé, mêmes tokens de
   pastille que le reste du redesign pour rester cohérent. */
.attendance-session-modal-card .form-message--error {
  color: var(--pill-danger-ink);
}

.attendance-session-modal-card .form-message--success {
  color: var(--pill-success-ink);
}

.attendance-recurrence-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin: 0.4rem 0 0.8rem;
}

.attendance-exception-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.4rem;
}

.attendance-status-wrap {
  align-items: flex-end;
  gap: 0.4rem;
}

.attendance-source-tag {
  margin: 0;
  font-size: 0.72rem;
  font-style: italic;
  color: var(--glass-ink-soft);
}

.attendance-quick-actions {
  display: flex;
  gap: 0.4rem;
}

.attendance-icon-btn {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: 700;
  border: 1.5px solid var(--glass-border);
  background: var(--glass-bg);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.attendance-icon-btn--ok {
  color: var(--pill-success-ink);
  border-color: rgba(74, 222, 128, 0.4);
}

.attendance-icon-btn--ok:hover {
  background: var(--pill-success-bg);
}

.attendance-icon-btn--no {
  color: var(--pill-danger-ink);
  border-color: rgba(255, 143, 192, 0.4);
}

.attendance-icon-btn--no:hover {
  background: var(--pill-danger-bg);
}

.attendance-manage-link {
  font-size: 0.78rem;
}

/* --- Calendrier de l'onglet Présences (25/08/2026) : simple relecture des
   lignes déjà chargées pour la liste, groupées par jour. Voir
   renderAttendanceCalendar dans admin-attendance.js. --- */
.admin-attendance-calendar {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1rem 1.1rem 1.2rem;
  margin: 1rem 0;
  max-width: 480px;
  backdrop-filter: blur(6px);
}

.admin-attendance-calendar-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-bottom: 0.8rem;
}

.admin-attendance-calendar-month {
  font-family: var(--font-display);
  font-weight: 600;
  color: #fff;
  text-transform: capitalize;
  min-width: 9rem;
  text-align: center;
}

.admin-attendance-calendar-nav {
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 50%;
  border: 1px solid var(--glass-border);
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1;
}

.admin-attendance-calendar-nav:hover {
  background: rgba(255, 255, 255, 0.18);
}

.admin-attendance-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.3rem;
}

.admin-attendance-calendar-dow {
  text-align: center;
  font-size: 0.7rem;
  color: var(--glass-ink-soft);
  text-transform: uppercase;
  padding-bottom: 0.2rem;
}

.admin-attendance-calendar-cell {
  aspect-ratio: 1;
  border: none;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  cursor: pointer;
}

.admin-attendance-calendar-cell:hover {
  background: rgba(255, 255, 255, 0.14);
}

.admin-attendance-calendar-cell--muted {
  opacity: 0.35;
}

.admin-attendance-calendar-cell--today {
  box-shadow: inset 0 0 0 1px var(--glass-border);
  font-weight: 700;
}

.admin-attendance-calendar-cell--selected {
  outline: 2px solid #40EAE8;
  outline-offset: -2px;
}

.admin-attendance-calendar-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
}

.admin-attendance-calendar-dot--present { background: #3fcf8e; }
.admin-attendance-calendar-dot--absent { background: #e5646b; }
.admin-attendance-calendar-dot--not_answered { background: #e8b93f; }
.admin-attendance-calendar-dot--upcoming { background: #40EAE8; }

.admin-attendance-calendar-day-detail {
  margin: 0 0 1.75rem;
}

.admin-attendance-calendar-day-detail .student-list-title {
  margin-bottom: 0.7rem;
}

.admin-attendance-calendar-day-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--glass-border);
}

.admin-attendance-calendar-day-row:first-of-type {
  border-top: none;
  padding-top: 0;
}

.admin-attendance-calendar-day-row-name {
  font-size: 0.92rem;
  color: var(--glass-ink);
}

.admin-attendance-calendar-day-row .exercise-status-badge {
  margin: 0;
  flex-shrink: 0;
}

/* --- Nom d'élève cliquable -> profil admin, + badge crédit "X/Y" (25/08/2026,
   demandé par Lily) — réutilisés partout où un nom d'élève apparaît dans
   Présences (liste à plat, en-tête groupé, détail du calendrier). --- */
.attendance-student-name-link {
  cursor: pointer;
}

.attendance-student-name-link:hover {
  text-decoration: underline;
}

.attendance-credit-badge {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: var(--cyan);
  color: #fff;
  font-family: var(--font-mono, monospace);
  font-size: 0.72rem;
  font-weight: 600;
  vertical-align: middle;
}

.attendance-credit-badge--warn {
  background: var(--pill-warn-ink);
}

.attendance-credit-badge--red {
  background: var(--pill-danger-ink);
}

/* --- Liste des séances repliée par défaut (25/08/2026) : même mécanique que
   .faq-answer sur tarifs.html (max-height 0/600px, piloté par la classe
   --open), adaptée au fond violet de l'admin. --- */
.attendance-list-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: none;
  border: none;
  border-top: 1px solid var(--glass-border);
  margin-top: 0.5rem;
  padding: 0.9rem 0.2rem;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  text-align: left;
}

.attendance-list-toggle:hover,
.attendance-list-toggle:focus-visible {
  color: #40EAE8;
}

.attendance-list-toggle-icon {
  font-size: 1.2rem;
  color: var(--gold);
}

.attendance-list-collapsible {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.attendance-list-collapsible--open {
  max-height: 4000px;
}

.attendance-list-collapsible-inner {
  padding-top: 0.9rem;
}

/* --- Récapitulatif élèves + note de séance (26/08/2026, demandé par Lily) :
   calendrier + récap côte à côte, empilés sur petit écran. Voir
   admin-attendance.js. --- */
.admin-attendance-top {
  display: flex;
  gap: 1.2rem;
  flex-wrap: wrap;
  align-items: flex-start;
}

.admin-attendance-calendar-col {
  flex: 1 1 480px;
  min-width: 0;
}

.admin-attendance-summary {
  flex: 1 1 320px;
  min-width: 280px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1rem 1.1rem 1.2rem;
  margin: 1rem 0;
  backdrop-filter: blur(6px);
}

.attendance-summary-student-item {
  cursor: pointer;
}

.attendance-summary-student-item:hover {
  color: var(--cyan);
}

.attendance-summary-back {
  background: none;
  border: none;
  color: var(--cyan);
  cursor: pointer;
  padding: 0;
  margin-bottom: 0.6rem;
  font-size: 0.85rem;
}

.attendance-summary-back:hover {
  text-decoration: underline;
}

.admin-attendance-summary-name {
  font-weight: 600;
  font-size: 1.05rem;
  margin: 0 0 0.8rem;
  color: var(--rose);
}

.admin-attendance-summary-label {
  font-size: 0.82rem;
  color: var(--text-muted, #b8b3c9);
  margin: 1rem 0 0.3rem;
}

.admin-attendance-summary-followed-list {
  max-height: 180px;
  overflow-y: auto;
}

.attendance-summary-payment-delete {
  background: none;
  border: none;
  color: var(--rose);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0.25rem;
  opacity: 1;
}

.admin-attendance-summary-payment-form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.8rem;
}

.admin-attendance-summary-payment-form input[type="date"],
.admin-attendance-summary-payment-form input[type="number"] {
  flex: 1 1 120px;
}

.admin-attendance-summary-payment-form input[type="text"] {
  flex: 1 1 100%;
}

/* --- Note libre par séance/groupe dans le détail-jour du calendrier
   (devoirs donnés, à retrouver à la séance suivante). --- */
.admin-attendance-day-note {
  padding: 0 0.25rem 0.75rem;
}

.admin-attendance-day-note-label {
  display: block;
  font-size: 0.78rem;
  color: var(--text-muted, #b8b3c9);
  margin-bottom: 0.3rem;
}

.admin-attendance-day-note-status {
  color: var(--cyan);
  margin-left: 0.5rem;
}

.admin-attendance-day-note-input {
  width: 100%;
  min-height: 50px;
  resize: vertical;
  background: var(--glass-bg-strong, rgba(255, 255, 255, 0.06));
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  color: #fff;
  padding: 0.5rem 0.6rem;
  font-family: inherit;
  font-size: 0.85rem;
}

.admin-attendance-day-note-input::placeholder {
  color: var(--pill-pending-ink);
}

/* --- Regroupement des lignes de présence par "classe" (session.label), voir
   renderAttendanceRows/buildAttendanceGroupElement : une entrée dépliable
   plutôt qu'une ligne par élève x occurrence. --- */
.attendance-group-item {
  padding: 0;
  overflow: hidden;
}

.attendance-group-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 1rem 1.25rem;
  cursor: pointer;
  transition: background 0.15s ease;
}

.attendance-group-header:hover,
.attendance-group-header:focus-visible {
  background: rgba(255, 255, 255, 0.06);
  outline: none;
}

.attendance-group-chevron {
  display: inline-block;
  color: var(--cyan);
  transition: transform 0.15s ease;
}

.attendance-group-chevron--open {
  transform: rotate(90deg);
}

.attendance-group-members {
  list-style: none;
  margin: 0;
  padding: 0 0.75rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.attendance-group-members[hidden] {
  display: none;
}

.attendance-group-members .student-list-item {
  background: rgba(255, 255, 255, 0.05);
}

/* Un 3e niveau d'imbrication (classe -> élève -> dates, voir
   buildAttendanceStudentElement) : léger retrait + fond un cran plus discret
   pour que les dates d'un élève restent visuellement distinguables de la
   liste des élèves de la classe. */
.attendance-group-members .attendance-group-members {
  margin-left: 0.75rem;
  padding-left: 0.75rem;
  border-left: 2px solid rgba(255, 255, 255, 0.12);
}

.attendance-group-members .attendance-group-members .student-list-item {
  background: rgba(255, 255, 255, 0.03);
}

/* --- Onglet élève : mini-calendrier + liste --- */

.attendance-calendar-month {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  color: var(--cyan);
  margin: 0.8rem 0 0;
  text-transform: capitalize;
}

.attendance-calendar {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.3rem;
  max-width: 420px;
  margin: 0.8rem 0 1.2rem;
}

.attendance-calendar-dow {
  font-size: 0.68rem;
  text-align: center;
  color: var(--glass-ink-soft);
  font-weight: 700;
  letter-spacing: 0.03em;
}

.attendance-calendar-cell {
  aspect-ratio: 1;
  border-radius: 8px;
  background: var(--glass-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  position: relative;
  color: var(--glass-ink);
}

.attendance-calendar-cell--empty {
  background: transparent;
}

.attendance-calendar-cell--session::after {
  content: "";
  position: absolute;
  bottom: 4px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--cyan);
}

.attendance-calendar-cell--today {
  background: var(--cyan);
  color: #133b3a;
  font-weight: 700;
}

.attendance-calendar-cell--today::after {
  background: #133b3a;
}

.attendance-answer-actions {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.5rem;
}

/* --- Récap dans la fiche profil admin (voir admin-user-profile.js) --- */

/* Cartes "verre" pleines, comme .exam-take-question/.exercise-editor-card —
   ces deux sections n'étaient que séparées par un simple filet, demandé
   explicitement en boîte complète comme le reste du site (sans filigrane :
   ce dernier est spécifique aux fiches/examens, pas à cette modale). */
.user-profile-attendance,
.user-profile-notes,
.user-profile-credit {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  margin: 0 0 1rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Essai gratuit de 5 minutes de flashcards (validé 22/08/2026) — même
   traitement visuel que .user-profile-credit ci-dessus. */
.user-profile-flashcards {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  margin: 0 0 1rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.user-profile-flashcards .student-list-meta {
  margin: 0.4rem 0 0.6rem;
  text-transform: none;
  letter-spacing: normal;
}

.user-profile-flashcards-duration {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--glass-border);
}

.user-profile-flashcards-duration label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.9em;
}

.user-profile-flashcards-duration-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}

.user-profile-flashcards-duration-row input[type="number"] {
  width: 5rem;
}

.user-profile-flashcards-duration-until {
  margin: 0.4rem 0 0;
}

.user-profile-notes-input {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  /* --glass-bg-strong (pas --glass-bg) : la carte parente est déjà en verre
     depuis .user-profile-notes ci-dessus, sinon le champ s'y fond trop. */
  background: var(--glass-bg-strong);
  color: var(--glass-ink);
  margin-top: 0.4rem;
  resize: vertical;
}

.user-profile-notes-input::placeholder {
  color: var(--glass-ink-soft);
}

.user-profile-notes-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.5rem;
}

.user-profile-attendance h3,
.user-profile-credit h3 {
  margin: 0 0 0.4rem;
  font-size: 1rem;
}

.user-profile-credit-input-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.4rem;
}

.user-profile-credit-input-row label {
  font-size: 0.85rem;
  color: var(--glass-ink-soft);
}

.user-profile-credit-input {
  width: 4.5rem;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  background: var(--glass-bg-strong);
  color: var(--glass-ink);
}

.user-profile-credit-input::placeholder {
  color: var(--glass-ink-soft);
}

.user-profile-credit-display {
  margin-top: 0.8rem;
}

.user-profile-credit-payments-label {
  margin: 1.1rem 0 0.3rem;
  font-size: 0.85rem;
  font-weight: 600;
}

.credit-bar-track {
  width: 100%;
  height: 8px;
  border-radius: 999px;
  background: var(--glass-bg-strong);
  overflow: hidden;
  margin-bottom: 0.4rem;
}

.credit-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--cyan);
  transition: width 0.2s ease;
}

.credit-bar-fill--warn {
  background: var(--pill-warn-ink);
}

.credit-bar-fill--red {
  background: var(--pill-danger-ink);
}

.credit-label {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--glass-ink);
}

.credit-label--warn {
  color: var(--pill-warn-ink);
}

.credit-label--red {
  color: var(--pill-danger-ink);
}

.credit-total-label {
  margin: 0.3rem 0 0;
  font-size: 0.75rem;
  color: var(--glass-ink-muted, var(--glass-ink));
  opacity: 0.75;
}

.attendance-history-dots {
  display: flex;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

.attendance-history-dot {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 700;
  cursor: default;
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.attendance-history-dot--ok {
  background: var(--pill-success-bg);
  color: var(--pill-success-ink);
}

.attendance-history-dot--no,
.attendance-history-dot--pending {
  background: var(--pill-danger-bg);
  color: var(--pill-danger-ink);
}

.admin-toolbar-block {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--paper-line);
}

.admin-toolbar-block label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 0.3rem;
}

.admin-toolbar-block textarea,
.admin-toolbar-block input {
  display: block;
  width: 100%;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  color: var(--ink);
  margin-bottom: 1rem;
}

.exam-result-comment {
  margin: 0.75rem auto 0;
  max-width: 40ch;
  padding: 0.75rem 1rem;
  background: var(--paper);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  font-size: 0.9rem;
  color: var(--ink);
  text-align: left;
}

.chat-input-row {
  display: flex;
  gap: 0.5rem;
  padding: 0.75rem;
  border-top: 1px solid var(--glass-border);
  flex-shrink: 0;
}

.chat-attach-btn {
  flex-shrink: 0;
  background: none;
  border: none;
  font-size: 1.2rem;
  cursor: pointer;
  padding: 0 0.2rem;
  line-height: 1;
}

.chat-input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.5rem 0.7rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  color: var(--glass-ink);
}

.chat-input::placeholder {
  color: var(--glass-ink-soft);
}

.chat-send-btn {
  background: var(--cyan);
  color: #0b1a1a;
  border: none;
  border-radius: 999px;
  padding: 0.5rem 1rem;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.2s ease;
}

.chat-send-btn:hover {
  background: #6ff2f0;
}

@media (max-width: 480px) {
  .chat-panel {
    right: 0.75rem;
    bottom: 5rem;
  }
  .chat-bubble {
    right: 1rem;
    bottom: 1rem;
  }
}

/* --- Page "Qui suis-je ?" : texte à gauche, photo à droite, dans un cadre
   qui s'arrête juste sous le contenu (pas de hauteur imposée). --- */

.about-main {
  max-width: 900px;
  margin: 0 auto;
  padding: 0 1.5rem 4rem;
}

.about-card {
  display: flex;
  align-items: center;
  gap: 2.5rem;
  padding: 2rem 2.5rem;
}

/* Même "boîte vitre" retenue pour Prestations (voir .prestation-text) :
   uniquement le texte, ni la photo ni le titre. */
.about-text {
  flex: 1 1 55%;
  min-width: 0;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 1.5rem 1.75rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.about-text p {
  margin: 0 0 1rem;
  color: #ffffff;
  line-height: 1.7;
  font-size: 0.95rem;
}

.about-text p:last-child {
  margin-bottom: 0;
}

.about-highlight {
  color: #ffffff;
  font-weight: 600;
  text-decoration: underline;
}

.about-photo-wrap {
  flex: 0 0 auto;
  width: 40%;
  max-width: 300px;
}

.about-photo {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.18);
}

@media (max-width: 720px) {
  .about-card {
    flex-direction: column;
    padding: 1.75rem;
  }
  .about-photo-wrap {
    width: 55%;
    order: -1;
  }
}

/* --- Page "Prestations" : 3 blocs titre + image + texte --- */

.prestations-main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 1.5rem 4rem;
}

.prestation-block {
  margin-bottom: 4rem;
}

.prestation-block:last-child {
  margin-bottom: 0;
}

/* 3 offres côte à côte plutôt qu'empilées (demandé le 25/08/2026) — les
   .prestation-block deviennent des colonnes de grille, la marge verticale
   entre blocs (pensée pour un empilement) ne sert plus ici. */
.prestation-columns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  align-items: start;
  margin-bottom: 4rem;
}

.prestation-columns .prestation-block {
  margin-bottom: 0;
}

.prestation-cta {
  display: block;
  width: fit-content;
  margin: 1.25rem auto 0;
  text-decoration: none;
  text-align: center;
}

@media (max-width: 860px) {
  .prestation-columns {
    grid-template-columns: 1fr;
  }
}

.prestation-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.3rem, 3.5vw, 1.7rem);
  color: #40EAE8;
  text-align: center;
  margin: 0 0 1.75rem;
}

.prestation-row {
  display: flex;
  align-items: flex-start;
  gap: 2.5rem;
}

.prestation-image-wrap {
  flex: 0 0 auto;
  width: 34%;
  max-width: 320px;
}

/* Bloc "30 jours" : l'image est seule dans .prestation-row (pas de
   .prestation-text à côté, ce texte-là vit dans .prestation-extra en
   dessous) — sans ça, un unique item flex reste collé à gauche avec tout le
   reste de la rangée vide à droite. */
.prestation-row > .prestation-image-wrap:only-child {
  width: 50%;
  max-width: 340px;
  margin: 0 auto;
}

.prestation-image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 16px;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.18);
}

.prestation-text {
  flex: 1 1 auto;
  min-width: 0;
}

.prestation-text p {
  margin: 0 0 1rem;
  color: #ffffff;
  line-height: 1.7;
  font-size: 0.95rem;
}

.prestation-text p:last-child {
  margin-bottom: 0;
}

.prestation-extra {
  max-width: 700px;
  margin: 2rem auto 0;
}

.prestation-subheading {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: #40EAE8;
  margin: 1.5rem 0 0.5rem;
}

.prestation-extra p {
  margin: 0 0 0.9rem;
  color: #ffffff;
  line-height: 1.7;
  font-size: 0.95rem;
}

/* "Boîte vitre" retenue après test (voir historique) : uniquement autour du
   texte, ni l'image ni le titre. .prestation-extra (bloc "30 jours", pas de
   .prestation-text à côté de son image) suit la même règle en une seule
   boîte réunissant tous ses paragraphes/sous-titres. */
.prestation-text,
.prestation-extra {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 1.5rem 1.75rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Sans ça, la marge naturelle du premier sous-titre s'ajoute au padding de
   la boîte -> trop d'espace en haut. */
.prestation-extra > .prestation-subheading:first-child {
  margin-top: 0;
}

@media (max-width: 720px) {
  .prestation-row {
    flex-direction: column;
  }
  .prestation-image-wrap {
    width: 60%;
    max-width: 260px;
    margin: 0 auto;
  }
}

/* --- Page "Tarifs & FAQ" : titre + photo à gauche, accordéon à droite --- */

.tarifs-main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 1rem 1.5rem 4rem;
}

.tarifs-layout {
  display: flex;
  align-items: flex-start;
  gap: 3rem;
}

.tarifs-intro {
  flex: 0 0 34%;
  max-width: 380px;
}

.tarifs-intro-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.5rem, 3.5vw, 2rem);
  line-height: 1.3;
  color: #40EAE8;
  margin: 0 0 2rem;
}

.tarifs-photo {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  /* Forme "vitrail" : juste le haut en arc de cercle (rayon vertical
     faible = arc peu profond), le reste droit/anguleux. Le rayon
     horizontal à 50% garantit que l'arc part bien du bord de l'image. */
  border-radius: 50% 50% 0 0 / 30% 30% 0 0;
  object-fit: cover;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.18);
}

/* Boîtes "vitre" empilées (une par question), chacune s'étend/se rétracte
   dynamiquement à l'ouverture — voir .faq-answer plus bas pour la mécanique
   d'animation (grid-template-rows 0fr/1fr, piloté par .faq-item--open que
   tarifs-faq.js bascule au clic). Remplace l'ancienne liste à simples filets
   (--paper-line, illisible sur le fond violet de toute façon). */
.faq-list {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.faq-item {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.faq-question {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.25rem;
  width: 100%;
  background: none;
  border: none;
  text-align: left;
  padding: 1.1rem 1.5rem;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.92rem;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: #40EAE8;
  cursor: pointer;
}

.faq-question:hover,
.faq-question:focus-visible {
  color: #40EAE8;
}

.faq-icon {
  flex-shrink: 0;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--gold);
}

/* max-height plutôt que grid-template-rows: 0fr (essayé d'abord) — ce
   dernier ne retombait pas à une hauteur réellement nulle ici (la taille
   minimale automatique d'un item de grille bloquait le repli complet),
   laissant dépasser la première ligne de texte même replié. */
.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.faq-item--open .faq-answer {
  /* Assez haut pour la plus longue réponse (voir tarifs.html, question 1,
     beaucoup plus longue depuis son réécrit) sans dépendre d'une vraie mesure
     JS de la hauteur du contenu. */
  max-height: 3000px;
}

.faq-answer-inner {
  padding: 0 1.5rem 1.25rem;
}

.faq-answer p {
  margin: 0 0 0.85rem;
  color: #ffffff;
  line-height: 1.7;
  font-size: 0.92rem;
}

/* Liens vers concepts.html dans la FAQ "Hệ sinh thái học tập" — cyan +
   souligné pour rester bien visibles sur le fond violet, contrairement au
   blanc uni du reste du texte (voir .faq-answer p ci-dessus). */
.faq-link {
  color: var(--cyan);
  text-decoration: underline;
}

.faq-link:hover {
  color: #ffffff;
}

.faq-answer p:last-child {
  margin-bottom: 0;
}

/* --- Détail d'une inscription (admin) --- */

.registration-detail-field {
  margin-bottom: 1rem;
}

.registration-detail-field label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #ffffff;
  margin-bottom: 0.2rem;
}

.registration-detail-field p {
  margin: 0;
  color: #ffffff;
  white-space: pre-wrap;
}

/* --- Formulaire d'inscription (public, sans compte) --- */

.registration-main {
  max-width: 900px;
  margin: 0 auto;
  padding: 0 1.5rem 4rem;
}

.registration-note {
  margin: 0.75rem 0 0;
  color: #ffffff;
  font-size: 0.9rem;
}

.registration-note a {
  color: #40EAE8;
  font-weight: 600;
}

.registration-layout {
  display: flex;
  align-items: flex-start;
  gap: 2.5rem;
}

.registration-photo {
  flex: 0 0 auto;
  width: 240px;
  height: 240px;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 12px 32px rgba(44, 31, 69, 0.18);
  position: sticky;
  top: 2rem;
}

/* "Boîte vitre" comme .about-text/.prestation-text/.faq-item, demandée
   explicitement — la photo reste hors boîte (voir .registration-photo),
   seul le formulaire est encadré. */
.registration-layout .auth-form {
  flex: 1 1 auto;
  min-width: 0;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 1.5rem 1.75rem;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* Répété ici en plus de la règle .auth-form label ci-dessus (même valeur,
   déjà correcte pour les deux) pour rester explicite au cas où le style de
   base de .auth-form label change un jour indépendamment. */
.registration-layout .auth-form label {
  color: #40EAE8;
}

/* Sans ça, la marge naturelle du premier label s'ajoute au padding de la
   boîte -> trop d'espace en haut. */
.registration-layout .auth-form > .form-row:first-child .form-field label {
  margin-top: 0;
}

/* Questions groupées 2 par 2 (1+2, 3+4, 5+6) pour gagner en hauteur, demandé
   explicitement — chaque paire est un .form-row contenant deux .form-field
   (label + champ), le reste du formulaire (radios, dropdown Q8, textarea)
   garde une seule colonne. */
.form-row {
  display: flex;
  gap: 1.5rem;
}

.form-row .form-field {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

@media (max-width: 780px) {
  .registration-layout {
    flex-direction: column;
    align-items: center;
  }
  .registration-photo {
    position: static;
    width: 180px;
    height: 180px;
  }
  .form-row {
    flex-direction: column;
    gap: 0;
  }
}

.registration-main .auth-form textarea {
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  background: #fff;
  color: var(--ink);
  resize: vertical;
}

.registration-main .auth-form select {
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  background: #fff;
  color: var(--ink);
}

/* Q8 en menu déroulant à cocher (<details>/<summary>, pas de JS pour
   l'ouverture/fermeture) plutôt qu'une liste de cases toujours dépliée —
   demandé explicitement pour gagner en hauteur. Fond translucide (pas blanc
   comme les autres champs) : .checkbox-option est en texte blanc partout
   ailleurs sur cette page, un fond blanc le rendrait illisible. */
.checkbox-dropdown {
  margin-top: 0.4rem;
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  background: var(--glass-bg-strong);
  overflow: hidden;
}

.checkbox-dropdown-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.65rem 0.85rem;
  font-family: var(--font-body);
  font-size: 0.95rem;
  color: #ffffff;
}

.checkbox-dropdown-summary::-webkit-details-marker {
  display: none;
}

.checkbox-dropdown-summary::after {
  content: "▾";
  flex-shrink: 0;
  transition: transform 0.15s ease;
}

.checkbox-dropdown[open] .checkbox-dropdown-summary::after {
  transform: rotate(180deg);
}

/* Plus spécifique que .checkbox-group (margin-top: 0.4rem) pour l'annuler
   proprement plutôt que via !important. */
.checkbox-dropdown .checkbox-dropdown-panel {
  margin-top: 0;
  padding: 0.6rem 0.85rem 0.75rem;
  border-top: 1px solid var(--glass-border);
  max-height: 220px;
  overflow-y: auto;
}

.radio-group,
.checkbox-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.4rem;
}

.radio-option,
.checkbox-option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.95rem;
  color: #ffffff;
  cursor: pointer;
}

.radio-option input,
.checkbox-option input {
  accent-color: var(--accent-dark);
  cursor: pointer;
}

.checkbox-option:has(input:disabled) {
  color: #ffffff;
  opacity: 0.6;
  cursor: not-allowed;
}

@media (max-width: 780px) {
  .tarifs-layout {
    flex-direction: column;
    gap: 2rem;
  }
  .tarifs-intro {
    max-width: none;
    width: 100%;
  }
  .tarifs-photo {
    max-width: 220px;
    margin: 0 auto;
  }
}

/* --- Filigrane discret ("idempourmoi.fr") sur le contenu d'une fiche ou
   d'un bloc d'exercices : voir public/js/content-watermark.js
   (applyContentWatermark). Scopé au conteneur qui porte .watermark-host
   (ajoutée dynamiquement par le JS), jamais toute la page. overflow:hidden
   en garde-fou : même si le canvas était mal dimensionné, il ne peut plus
   déborder du cadre et créer un vide comme le bug corrigé le 2026-08-18. --- */

.watermark-host {
  position: relative;
  overflow: hidden;
}

.content-watermark-canvas {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
}

/* --- Blocage sélection/copier-coller : voir public/js/content-protect.js.
   Portée à <body class="protect-content"> uniquement (cours.html/mes-cours.html),
   jamais l'admin ni les pages publiques. --- */

body.protect-content {
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  -webkit-touch-callout: none; /* menu "Copier" au appui long, iOS Safari */
}

/* Un élève doit pouvoir sélectionner/corriger SA PROPRE réponse en cours de
   rédaction (ex: exercice "réponse libre", champ de chat) — l'exemption
   correspondante côté JS (voir isFormField) ne suffit pas seule, il faut
   aussi ré-autoriser la sélection native ici. */
body.protect-content input,
body.protect-content textarea,
body.protect-content [contenteditable="true"] {
  -webkit-user-select: text;
  -moz-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* Le widget de chat (public/js/chat-widget.js) s'ajoute à <body>, donc sur
   cours.html/mes-cours.html il héritait de la protection ci-dessus alors
   qu'elle n'a jamais été pensée pour lui (elle vise le contenu de cours/
   exercices, pas des messages privés déjà échangés) — remonté explicitement
   ("j'peux même pas copier le texte"). Ré-autorisé pour tout texte de bulle
   de message, jamais pour le reste du widget (contacts, en-têtes...). */
body.protect-content .chat-message-text,
body.protect-content .chat-message-sender,
body.protect-content .chat-message-file-link,
body.protect-content .chat-message-attachment-expired {
  -webkit-user-select: text;
  -moz-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* --- Onglet "Flashcards" (plan validé le 21/08/2026) : posé directement sur
   .admin-panel (fond violet, côté admin ET élève), donc tokens "verre" comme
   le reste du chrome applicatif. Balancement + retournement 3D repris quasi
   tels quels de la maquette de plan (voir artefact "Onglet Flashcards"),
   juste réécrits avec les tokens réels du site à la place des tokens de
   maquette. --- */

.flashcard-levels-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.flashcard-level-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.75rem;
}

.flashcard-level-pill {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  padding: 0.5rem 1.2rem 0.5rem 0.7rem;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  color: var(--glass-ink);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}

.flashcard-level-pill:hover:not(:disabled) {
  background: var(--glass-bg-strong);
  border-color: var(--cyan);
  transform: translateY(-2px);
}

/* Mascotte par niveau (voir FLASHCARD_LEVEL_MASCOTS) — un petit signe de vie
   au survol, demandé "mimi" par Lily le 22/08/2026. */
.flashcard-level-mascot {
  font-size: 1.1rem;
  display: inline-block;
  transition: transform 0.2s ease;
}

.flashcard-level-pill:hover:not(:disabled) .flashcard-level-mascot {
  transform: rotate(-12deg) scale(1.15);
}

.flashcard-level-pill:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.flashcard-level-pill:disabled .flashcard-level-mascot {
  filter: grayscale(1);
}

.flashcard-cards-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* Explicite (déjà la valeur par défaut de Grid) : les 3 cartes doivent
     rester alignées même quand l'une a plus de contenu que les autres — la
     phrase d'exemple (optionnelle, un mot sur trois peut ne pas en avoir)
     rendait la rangée en dents de scie sans ça. Voir .flashcard-flip
     ci-dessous pour le complément nécessaire côté carte retournée. */
  align-items: stretch;
  gap: 1rem;
  margin-top: 1rem;
}

@media (max-width: 720px) {
  .flashcard-cards-row {
    grid-template-columns: 1fr;
  }
}

/* --- Palette "mimi" par niveau (Lily, 22/08/2026) : une couleur pastel +
   une mascotte par palier, pilotées par data-level (posé en JS, voir
   student-flashcards.js). Custom properties scopées à .flashcard-card plutôt
   que globales : n'affecte rien d'autre sur le site. --- */
.flashcard-card {
  --fc-bg: var(--glass-bg);
  --fc-ink: var(--glass-ink);
  --fc-border: var(--glass-border);
  --fc-mascot: "";
}
.flashcard-card[data-level="a1"] { --fc-bg: #bdf3e6; --fc-ink: #0d5c4c; --fc-border: #6fd9bd; --fc-mascot: "🐣"; }
.flashcard-card[data-level="a2"] { --fc-bg: #bfe3ff; --fc-ink: #12578a; --fc-border: #74bdf2; --fc-mascot: "🐥"; }
.flashcard-card[data-level="b1"] { --fc-bg: #e6d9ff; --fc-ink: #5a3a9e; --fc-border: #b79cf0; --fc-mascot: "🐰"; }
.flashcard-card[data-level="b2"] { --fc-bg: #ffdfc0; --fc-ink: #8a4a12; --fc-border: #f2b877; --fc-mascot: "🦊"; }
.flashcard-card[data-level="c1"] { --fc-bg: #ffd3e6; --fc-ink: #9c2f63; --fc-border: #f593bd; --fc-mascot: "🐼"; }

.flashcard-card {
  /* Fond pastel plein + bordure épaisse + ombre teintée (jamais de noir pur)
     : look "autocollant/jouet" plutôt que le glassmorphism générique utilisé
     ailleurs sur le site — demandé explicitement pour les flashcards. */
  background: var(--fc-bg);
  border: 3px solid var(--fc-border);
  border-radius: 22px;
  /* Padding du haut agrandi pour laisser la place à la mascotte/étincelle
     décoratives (::before/::after ci-dessus) sans chevaucher le mot. */
  padding: 2.1rem 1.1rem 1.1rem;
  box-shadow: 0 10px 22px -10px rgba(58, 26, 92, 0.5), inset 0 2px 0 rgba(255, 255, 255, 0.5);
  color: var(--fc-ink);
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  min-height: 150px;
  position: relative;
}

/* Mascotte + étincelle décorative, coin haut de la carte — pas de DOM en
   plus, juste du contenu généré CSS. */
.flashcard-card::before {
  content: var(--fc-mascot);
  position: absolute;
  top: 0.7rem;
  left: 0.9rem;
  font-size: 1.4rem;
  filter: drop-shadow(0 2px 0 rgba(255, 255, 255, 0.5));
}
.flashcard-card::after {
  content: "✨";
  position: absolute;
  top: 0.85rem;
  right: 1rem;
  font-size: 0.9rem;
  opacity: 0.65;
}

/* Léger balancement continu tant que l'essai n'est pas verrouillé — demandé
   explicitement ("plus vivant"), désynchronisé par carte. S'arrête une fois
   verrouillé : les cartes passent alors dans .flashcard-flip, qui a sa
   propre transformation (rotateY) sur la même propriété transform — cumuler
   les deux causerait des sauts visuels au clic. */
@keyframes flashcard-sway {
  0%, 100% { transform: rotate(-1.1deg); }
  50% { transform: rotate(1.1deg); }
}
.flashcard-cards-row > .flashcard-card {
  animation: flashcard-sway 3.8s ease-in-out infinite;
  transform-origin: 50% 100%;
}
.flashcard-cards-row > .flashcard-card:nth-child(2) {
  animation-duration: 4.3s;
  animation-delay: -1.4s;
}
.flashcard-cards-row > .flashcard-card:nth-child(3) {
  animation-duration: 3.4s;
  animation-delay: -2.6s;
}
@media (prefers-reduced-motion: reduce) {
  .flashcard-cards-row > .flashcard-card {
    animation: none;
  }
}

.flashcard-word {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.2rem;
  text-align: center;
  /* Pastille blanche façon étiquette — se pose sur le fond pastel de
     .flashcard-card, dont elle hérite l'encre (var(--fc-ink)) pour rester
     assortie au niveau. Neutralisé pour .flashcard-history-detail-card
     ci-dessous (liste compacte, pas de carte pastel autour). */
  color: var(--fc-ink, var(--glass-ink));
  background: #fffdf9;
  border-radius: 14px;
  padding: 0.7rem 0.5rem;
  box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.03);
}

.flashcard-input {
  display: block;
  width: 100%;
  min-height: 2.6rem;
  background: rgba(255, 255, 255, 0.55);
  border: 2px dashed var(--fc-border, var(--glass-border));
  border-radius: 14px;
  padding: 0.55rem 0.7rem;
  font-family: var(--font-body);
  font-size: 0.88rem;
  color: var(--fc-ink, var(--glass-ink));
  resize: vertical;
}

.flashcard-input::placeholder {
  color: var(--fc-ink, var(--glass-ink-soft));
  opacity: 0.55;
}

.flashcard-input--readonly {
  white-space: pre-wrap;
}

.flashcard-input--placeholder {
  color: var(--fc-ink, var(--glass-ink-soft));
  opacity: 0.6;
  font-style: italic;
}

.flashcard-actions {
  margin-top: 1.25rem;
}

/* Retournement en 3D, CSS pur — voir l'artefact de plan pour la démo
   interactive équivalente.
   Hauteur FIXE (pas min-height, pas de %, pas d'étirement de grille) —
   constaté en vrai que min-height + Grid stretch ne suffisait pas à aligner
   les 3 cartes d'un tirage (.flashcard-face en dessous est en
   position:absolute/inset:0 : son contenu ne participe jamais au calcul de
   hauteur "auto" de ses ancêtres, avec ou sans stretch). Une valeur fixe,
   assez généreuse pour le contenu le plus long (mot + badges + réponse +
   définition + exemple + bouton), garantit des cartes strictement
   identiques peu importe si l'une a une phrase d'exemple et l'autre non —
   voir aussi .flashcard-face (overflow-y: auto, filet de sécurité si un
   exemple est un jour plus long que prévu) et .flashcard-back-content
   (déjà height:100% + margin-top:auto sur le bouton, qui se recale
   automatiquement en bas de cette hauteur fixe). */
.flashcard-flip {
  position: relative;
  height: 440px;
  perspective: 1200px;
}

.flashcard-flip-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.6s cubic-bezier(0.4, 0.2, 0.2, 1);
}

.flashcard-flip.is-flipped .flashcard-flip-inner {
  transform: rotateY(180deg);
}

.flashcard-face {
  position: absolute;
  inset: 0;
  /* Filet de sécurité : si un jour une phrase d'exemple/réponse est plus
     longue que prévu par la hauteur fixe de .flashcard-flip, ça défile au
     lieu de déborder hors de la carte ou d'être coupé sans prévenir. */
  overflow-y: auto;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  margin: 0;
}

.flashcard-face--back {
  transform: rotateY(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .flashcard-flip-inner {
    transition: none;
  }
}

.flashcard-flip-btn {
  margin-top: auto;
  align-self: center;
  /* Surcharge .btn-secondary.btn-small (fond neutre) pour une pilule assortie
     à la couleur du niveau, avec un petit rebond au survol — cohérent avec le
     reste du traitement "autocollant" des flashcards. */
  background: var(--fc-ink, var(--accent-dark));
  border-color: var(--fc-ink, var(--accent-dark));
  color: #fff;
  border-radius: 999px;
  transition: transform 0.15s ease;
}

.flashcard-flip-btn:hover {
  transform: scale(1.06) rotate(-1deg);
  background: var(--fc-ink, var(--accent-dark));
  opacity: 0.9;
}

.flashcard-back-content {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  height: 100%;
}

/* Pilule "autocollant" avec un petit pop-in rebondi à l'apparition — plus
   festif que le tag monospace discret d'avant, demandé "mimi". */
@keyframes flashcard-badge-pop {
  0% { transform: scale(0.4); opacity: 0; }
  60% { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1); }
}
.flashcard-badge {
  align-self: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.78rem;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  background: #fffdf9;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.08);
  animation: flashcard-badge-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@media (prefers-reduced-motion: reduce) {
  .flashcard-badge {
    animation: none;
  }
}

/* Réponse identique à la définition du prof — signal le plus fort, distingué
   du simple "sur la bonne voie" (cyan plutôt que vert, cohérent avec le
   reste des accents "premium" du site — tab actif, titres de cours...). */
.flashcard-badge--exact {
  color: var(--pill-upcoming-ink);
}

.flashcard-badge--hit {
  color: var(--pill-success-ink);
}

.flashcard-badge--miss {
  color: var(--pill-danger-ink);
}

.flashcard-reveal-label {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--fc-ink, var(--cyan));
  opacity: 0.75;
}

.flashcard-reveal-text {
  margin: 0 0 0.2rem;
  font-size: 0.88rem;
  color: var(--glass-ink);
}

/* Dans le dos de carte (pastel), la réponse redevient une petite étiquette
   blanche assortie au mot — dans la liste d'historique compacte (voir
   .flashcard-history-detail-card plus bas), on garde le texte simple. */
.flashcard-back-content .flashcard-reveal-text {
  background: #fffdf9;
  color: var(--fc-ink, var(--glass-ink));
  border-radius: 12px;
  padding: 0.5rem 0.6rem;
}

.flashcard-history-list {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
}

.flashcard-history-item {
  margin-bottom: 0.5rem;
}

/* Ligne cliquable (voir student-flashcards.js buildFlashcardHistoryRow) —
   un <div role="button"> plutôt qu'un <button>, même patron que les items
   cliquables de .student-list ailleurs dans ce fichier. */
.flashcard-history-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  width: 100%;
  box-sizing: border-box;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  padding: 0.75rem 1rem;
  cursor: pointer;
}

.flashcard-history-row:hover,
.flashcard-history-row:focus-visible {
  background: var(--glass-bg-strong);
  border-color: var(--cyan);
  outline: none;
}

.flashcard-history-chevron {
  color: var(--glass-ink-soft);
  font-size: 0.8rem;
  flex-shrink: 0;
}

.flashcard-history-details {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  padding: 0.9rem 1rem;
  margin-top: 0.5rem;
}

.flashcard-history-details[hidden] {
  display: none;
}

.flashcard-history-detail-card {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px dashed var(--glass-border);
}

.flashcard-history-detail-card:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

/* .flashcard-word est pensée pour la grande carte (centrée, padding vertical)
   — trop large dans une ligne de détail compacte. */
.flashcard-history-detail-card .flashcard-word {
  text-align: left;
  padding: 0;
  font-size: 1rem;
  color: var(--glass-ink);
  background: none;
  border-radius: 0;
  box-shadow: none;
}

.flashcard-history-date {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  color: var(--glass-ink-soft);
  flex-shrink: 0;
}

.flashcard-history-words {
  font-size: 0.85rem;
  color: var(--glass-ink);
  flex: 1;
  min-width: 200px;
}

.flashcard-history-score {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.78rem;
  color: var(--cyan);
  flex-shrink: 0;
}

/* --- "Défi Score" (gamification, validé 22/08/2026) : tirage 1 facile/1
   moyen/1 difficile, score par carte, classement hebdo/global. --- */

.flashcard-card-badges-row {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

/* Niveau CEFR du mot, toujours affiché (demandé explicitement, "toujours
   affiché sur la carte" dans le plan) — même encre que la carte pastel qui
   l'entoure (voir --fc-ink posé par .flashcard-card[data-level]). */
.flashcard-level-badge {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.72rem;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.65);
  color: var(--fc-ink, var(--glass-ink));
  letter-spacing: 0.03em;
}

/* Palier "Défi Score" (facile/moyen/difficile) — absent en mode classique.
   Couleurs propres au palier, distinctes des pastels par niveau : le palier
   organise le tirage, le niveau reste une propriété du mot. */
.flashcard-slot-tag {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.7rem;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
}
.flashcard-slot-tag--facile { background: #d4f7de; color: #145c34; }
.flashcard-slot-tag--moyen { background: #ffedc7; color: #7a4a05; }
.flashcard-slot-tag--difficile { background: #ffd9e2; color: #7a0f31; }

/* --- Choix du mode (validé 22/08/2026) : 2 gros boutons plutôt qu'un choix
   de niveau par défaut — le classement reste visible juste au-dessus. --- */
.flashcard-mode-choice-row {
  display: flex;
  gap: 1rem;
  margin-top: 1.25rem;
  flex-wrap: wrap;
}

.flashcard-mode-choice-btn {
  flex: 1;
  min-width: 180px;
  font-size: 1rem;
  padding: 1rem;
}

/* .btn-primary/.btn-secondary n'ont pas de style :disabled par défaut (fond
   coloré en dur) — sans ça, un bouton désactivé (essai gratuit épuisé)
   restait visuellement identique à actif. Même traitement que
   .flashcard-level-pill:disabled plus haut. */
.flashcard-mode-choice-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Essai gratuit de 5 minutes (validé 22/08/2026) : temps restant/statut,
   au-dessus du classement sur l'écran de choix du mode. */
.flashcard-usage-message {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--glass-ink-soft);
  margin: 0 0 1rem;
}

.flashcard-usage-message--blocked {
  color: #ff7a9c;
}

/* Lien "Se connecter" dans la bannière visiteur non connecté (ajusté
   22/08/2026) — même couleur que le texte plutôt que le bleu de lien par
   défaut, juste souligné pour rester identifiable comme un lien. */
.flashcard-usage-message--blocked a {
  color: inherit;
  text-decoration: underline;
}

/* --- Compte à rebours de 30s par manche (les 2 modes) --- */
.flashcard-timer-bar {
  display: flex;
  justify-content: center;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: 0.5rem 1rem;
  margin-bottom: 1rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--glass-ink);
  transition: color 0.2s ease, border-color 0.2s ease;
}
.flashcard-timer-bar[hidden] { display: none; }

/* 10 dernières secondes : bascule vers une couleur d'alerte, même palette
   que les badges "mauvaise réponse" ailleurs dans les flashcards. */
.flashcard-timer-bar--warning {
  color: #ff7a9c;
  border-color: rgba(255, 122, 156, 0.5);
}

/* --- Classement --- */

.flashcard-leaderboard {
  margin-top: 1.25rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 1rem 1.2rem;
  backdrop-filter: blur(6px);
}

.flashcard-leaderboard-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 0.9rem;
}

.flashcard-leaderboard-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--glass-ink);
}

.flashcard-leaderboard-toggle {
  display: inline-flex;
  gap: 0.3rem;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 999px;
  padding: 0.2rem;
}

.flashcard-leaderboard-toggle-btn {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.76rem;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  border: none;
  background: none;
  color: var(--glass-ink-soft);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.flashcard-leaderboard-toggle-btn--active {
  background: var(--cyan);
  color: #0f3a39;
}

.flashcard-leaderboard-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.flashcard-leaderboard-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.7rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
}

.flashcard-leaderboard-row--top1 {
  background: linear-gradient(90deg, rgba(255, 193, 94, 0.22), rgba(255, 193, 94, 0.05));
  border: 1px solid rgba(255, 193, 94, 0.5);
}

.flashcard-leaderboard-rank {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.85rem;
  width: 20px;
  text-align: center;
  color: var(--glass-ink-soft);
  flex-shrink: 0;
}

.flashcard-leaderboard-row--top1 .flashcard-leaderboard-rank {
  color: #ffc15e;
}

.flashcard-leaderboard-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--glass-bg-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.7rem;
  color: var(--glass-ink);
  flex-shrink: 0;
}

.flashcard-leaderboard-name {
  flex-grow: 1;
  font-size: 0.88rem;
  color: var(--glass-ink);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.flashcard-leaderboard-pts {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--cyan);
  flex-shrink: 0;
}

.flashcard-leaderboard-row--top1 .flashcard-leaderboard-pts {
  color: #ffc15e;
}

.flashcard-leaderboard-trophy {
  flex-shrink: 0;
}

/* Phrase d'exemple (idée d'un élève de Lily, 22/08/2026) — même style que
   .flashcard-reveal-text, juste en italique pour se distinguer d'une
   définition brute. */
.flashcard-example-text {
  font-style: italic;
}

/* --- Vitrine de cours ("Les petits +", 22/08/2026) : aperçu réel d'un vrai
   cours (mêmes classes .student-list/.student-list-item que "Mes cours",
   voir concepts-page.js) légèrement flouté et neutralisé au clic, avec une
   bannière de conversion fixe par-dessus. --- */
.vitrine-preview {
  position: relative;
}

/* Flashcards : même patron que .vitrine-preview-content, appliqué au panneau
   entier (une seule règle, peu importe la vue interne affichée) quand
   l'essai gratuit du jour est épuisé — voir setFlashcardsTrialOverlay dans
   student-flashcards.js. */
#panel-flashcards.flashcard-panel-blocked > div:not(#flashcards-trial-overlay) {
  filter: blur(2.2px);
  -webkit-filter: blur(2.2px);
  user-select: none;
  pointer-events: none;
}

/* .vitrine-preview-overlay force "display: flex", ce qui écrase l'attribut
   [hidden] (règle d'auteur > feuille de style par défaut du navigateur à
   spécificité égale) — sans ça le pop-up reste visible même quand on lui met
   `hidden`. La vitrine ne rencontre jamais ce cas (son overlay est toujours
   affiché dès que .panel-vitrine est visible), mais celui des flashcards est
   basculé dynamiquement — bug réel signalé par Gauthier le 23/08/2026. */
#flashcards-trial-overlay[hidden] {
  display: none;
}

/* Contenu flouté en flux normal de la page (plus de fenêtre à hauteur
   plafonnée) : un cours à beaucoup de fiches (ex. "30 jours", 30 lignes) se
   parcourt en scrollant la page elle-même — demandé explicitement le
   23/08/2026 ("qu'on puisse scroll"). La bannière ci-dessous compense en
   restant fixée au centre de l'écran quel que soit le défilement, voir
   .vitrine-preview-overlay. padding-bottom : laisse de la place pour lire le
   bas d'un contenu court sans qu'il ne se retrouve caché sous la bannière. */
.vitrine-preview-content {
  filter: blur(2.2px);
  -webkit-filter: blur(2.2px);
  user-select: none;
  pointer-events: none;
  min-height: 16rem;
  padding-bottom: 6rem;
}

.vitrine-preview-course-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.3rem;
  color: var(--cyan);
  margin: 0 0 1.2rem;
}

/* Bannière centrée, PAS floutée — seul élément vraiment lisible et cliquable
   de la vue. position:fixed (pas absolute) : reste au centre de l'ÉCRAN, pas
   juste du bloc flouté, donc visible en permanence même en scrollant un
   contenu plus long que la fenêtre (voir .vitrine-preview-content). */
.vitrine-preview-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem 1rem;
  pointer-events: none;
}

.vitrine-preview-banner {
  background: rgba(28, 17, 48, 0.9);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  padding: 1.5rem 1.7rem;
  max-width: 380px;
  text-align: center;
  color: #fff;
  box-shadow: 0 24px 55px -20px rgba(0, 0, 0, 0.65);
  pointer-events: auto;
}

.vitrine-preview-banner p {
  margin: 0 0 0.35rem;
  font-size: 0.92rem;
  color: rgba(255, 255, 255, 0.92);
}

.vitrine-preview-banner p.vi {
  margin: 0 0 1.1rem;
  color: rgba(255, 255, 255, 0.68);
}

.vitrine-preview-links {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.vitrine-preview-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  background: var(--gold);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.92rem;
  padding: 0.55rem 1rem;
  border-radius: 999px;
  text-decoration: none;
  transition: transform 0.15s ease;
}

.vitrine-preview-link:hover,
.vitrine-preview-link:focus-visible {
  transform: scale(1.04);
}

/* --- Admin "Les petits +" : réordonnancement par flèches (▲▼), plus fiable
   qu'un glisser-déposer tactile pour un si petit nombre de lignes — voir
   admin-concepts.js. Rangées posées sur .simple-list (déjà utilisée
   ailleurs dans l'admin), juste un .admin-reorder-main pour regrouper
   icône/titre/méta à gauche de .item-actions. --- */
.admin-reorder-main {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}

.admin-reorder-icon {
  flex-shrink: 0;
}

.admin-reorder-label {
  font-weight: 600;
  white-space: nowrap;
}

.admin-reorder-meta {
  color: var(--glass-ink-soft);
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.admin-reorder-tag {
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--glass-ink-soft);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  flex-shrink: 0;
}

.admin-reorder-move {
  font-size: 0.9rem;
}

.admin-reorder-move:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

/* ===== Onglet "Dictionnaire" (admin, 03/09/2026) : formulaire d'un verbe —
   mêmes tokens "verre dépoli" que le reste des panneaux admin (voir
   .admin-panel plus haut), pas les tokens --ink/--paper réservés au contenu
   "papier" d'une fiche/d'un examen. Voir public/js/admin-dictionary.js. ===== */

/* var(--ink) (le texte saisi dans .sheet-title-input/.exam-description-input
   partout ailleurs sur le site) a été signalé peu lisible par Gauthier sur ce
   formulaire précis (beaucoup de champs denses, texte sur fond blanc) — voir
   capture du 03/09/2026. Corrigé ici, scopé à ce panneau uniquement (pas
   touché globalement : .sheet-title-input est réutilisé par l'éditeur de
   cours/examens/flashcards, déjà validés tels quels ailleurs). */
#panel-dictionary input.sheet-title-input,
#panel-dictionary textarea.exam-description-input {
  color: #150e24;
  font-weight: 500;
}

/* Même souci que ci-dessus mais sur les LABELS de champ ("CONSTRUCTION
   (FRANÇAIS)", "SENS PRÉCIS DE CET EMPLOI", etc.) : .field-label est stylé en
   var(--ink-soft), pensé pour reposer sur une carte blanche "papier" (voir sa
   définition) — ici ces labels sont directement sur le dégradé violet du
   panneau (même surface que .student-list-item/.admin-panel), donc du texte
   violet-gris moyen sur fond violet = contraste trop faible, signalé par
   Gauthier le 03/09/2026. Reprend les tokens "verre dépoli" déjà utilisés par
   le reste du panneau plutôt qu'inventer une nouvelle couleur. */
#panel-dictionary .field-label {
  color: var(--glass-ink-soft);
}

.dict-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

@media (max-width: 640px) {
  .dict-form-row {
    grid-template-columns: 1fr;
  }
}

.dict-tense-tabs {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  margin-top: 0.75rem;
}

/* Temps/modes ajoutables à volonté depuis le 03/09/2026 (Imparfait,
   Subjonctif présent, Impératif...) — le bouton "+" reste visuellement
   distinct (bordure en tirets) des onglets réels, et chaque onglet actif
   affiche un petit "✕" pour se supprimer sans devoir ouvrir une autre vue. */
.dict-tense-tab--add {
  border-style: dashed;
  color: var(--cyan);
}

.dict-tense-tab-remove {
  margin-left: 0.4rem;
  opacity: 0.8;
}

.dict-tense-tab-remove:hover {
  opacity: 1;
}

.dict-tense-tab {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.82rem;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  color: var(--glass-ink-soft);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.dict-tense-tab--active {
  background: var(--cyan);
  border-color: var(--cyan);
  color: #133b3a;
}

.dict-conjugation-grid {
  display: grid;
  gap: 0.5rem;
  margin-top: 0.75rem;
  max-width: 32rem;
}

.dict-conjugation-row {
  display: grid;
  grid-template-columns: 6rem 1fr;
  align-items: center;
  gap: 0.75rem;
}

.dict-conjugation-pronoun {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.88rem;
  color: var(--glass-ink-soft);
}

.dict-construction-card {
  position: relative;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1rem 1.1rem;
  margin-top: 0.85rem;
}

.dict-construction-remove {
  position: absolute;
  top: 0.7rem;
  right: 0.9rem;
  font-size: 0.78rem;
  color: var(--glass-ink-soft);
}

.dict-example-row {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.4rem;
}

@media (max-width: 640px) {
  .dict-example-row {
    grid-template-columns: 1fr;
  }
}

/* ===== "Dictionnaire des verbes" (élève, 03/09/2026) : concepts.html,
   panel-dictionary — mêmes tokens "verre dépoli" que le reste de la page
   (voir .student-list-item), pas les tokens --ink/--paper. Voir
   public/js/student-dictionary.js. ===== */

.verb-search-bar {
  margin-top: 0.75rem;
}

.verb-search-bar input {
  width: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.7rem 1rem;
  border-radius: 999px;
  border: 1.5px solid var(--cyan);
  background: var(--glass-bg);
  color: var(--glass-ink);
}

.verb-search-bar input::placeholder {
  color: var(--glass-ink-soft);
}

.verb-result-fr {
  color: var(--gold);
}

.verb-result-vi {
  color: var(--cyan);
  font-weight: 600;
  margin-left: 0.4rem;
}

.verb-sheet {
  margin-top: 0.75rem;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 16px;
  overflow: hidden;
}

.verb-sheet-head {
  padding: 1.4rem 1.5rem 1.2rem;
  background: var(--glass-bg-strong);
  border-bottom: 1px solid var(--glass-border);
}

.verb-tag {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  color: var(--glass-ink-soft);
  margin-bottom: 0.6rem;
}

.verb-sheet-title {
  font-family: var(--font-display);
  font-size: 1.9rem;
  color: var(--gold);
  margin: 0 0 1rem;
}

.verb-def-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.2rem;
}

@media (max-width: 640px) {
  .verb-def-cols {
    grid-template-columns: 1fr;
  }
}

.verb-def-cols .verb-lang-label {
  display: block;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  color: var(--glass-ink-soft);
  margin-bottom: 0.2rem;
}

.verb-def-cols p {
  margin: 0;
  color: var(--glass-ink);
  font-size: 0.96rem;
}

.verb-def-vi p {
  color: var(--cyan);
}

.verb-sheet-body {
  padding: 1.4rem 1.5rem 1.6rem;
}

.verb-block-title {
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: var(--glass-ink);
  margin: 1.4rem 0 0.6rem;
}

.verb-block-title:first-child {
  margin-top: 0;
}

.verb-tense-tabs {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
}

.verb-tense-tab {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.85rem;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  color: var(--glass-ink-soft);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.verb-tense-tab--active {
  background: var(--cyan);
  border-color: var(--cyan);
  color: #133b3a;
}

.verb-conjugation-table {
  width: 100%;
  max-width: 34rem;
  border-collapse: collapse;
}

.verb-conjugation-table td {
  padding: 0.5rem 0.3rem;
  font-size: 0.95rem;
  border-bottom: 1px solid var(--glass-border);
}

.verb-conjugation-table tr:last-child td {
  border-bottom: none;
}

.verb-conjugation-pronoun {
  color: var(--glass-ink-soft);
  width: 22%;
}

.verb-conjugation-form {
  color: var(--glass-ink);
  font-weight: 600;
  width: 30%;
}

/* Colonne "Utilisation" (03/09/2026) : reconstruit la phrase telle qu'elle
   se dit vraiment ("Tu parles …" au présent, mais "Parle !" à l'impératif,
   sans pronom répété et avec "!" plutôt que "…") — but explicite : rendre
   visible d'un coup d'œil qu'un mode donné n'emploie pas de pronom, pas
   seulement déductible d'un tiret dans la colonne pronom. */
.verb-conjugation-usage-head {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  color: var(--glass-ink-soft);
  text-align: left;
  padding: 0 0.3rem 0.4rem;
}

.verb-conjugation-usage {
  color: var(--cyan);
  font-style: italic;
}

.verb-constructions {
  display: grid;
  gap: 0.75rem;
}

.verb-construction-card {
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 1rem 1.1rem;
}

.verb-construction-head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.4rem;
}

.verb-construction-pattern {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.02rem;
  color: var(--cyan);
}

.verb-construction-arrow {
  color: var(--glass-ink-soft);
}

.verb-construction-vi {
  font-weight: 600;
  color: var(--glass-ink);
}

.verb-construction-meaning {
  margin: 0 0 0.6rem;
  color: var(--glass-ink-soft);
  font-size: 0.9rem;
}

.verb-example {
  border-left: 2px solid var(--cyan);
  padding-left: 0.85rem;
  margin-top: 0.6rem;
}

.verb-example p {
  margin: 0;
}

.verb-example-fr {
  color: var(--glass-ink);
  font-style: italic;
}

.verb-example-vi {
  color: var(--glass-ink-soft);
  font-size: 0.88rem;
  margin-top: 0.15rem !important;
}
