/* Echec & Maths — socle visuel.
   Reprend l'identité de l'app Glide : bleu nuit étoilé, cartes sombres, accent bleu. */

:root {
  --bg:            #081522;
  --bg-deep:       #050d16;
  --bg-blue:       #0d2b45;
  --surface:       #111f2e;
  --surface-2:     #17283a;
  --line:          #223449;

  --accent:        #1f7ae0;
  --accent-soft:   #2b8fe8;
  --accent-dim:    rgba(31, 122, 224, .16);

  --text:          #f2f6fb;
  --text-dim:      #9db0c6;
  --text-faint:    #6b7f96;

  --ok:            #34c77b;
  --warn:          #e8b23a;
  --danger:        #e2574c;

  --radius:        14px;
  --radius-lg:     20px;
  --gutter:        16px;
  --topbar-h:      56px;
  --tabbar-h:      64px;

  /* Deux tailles de bouton, et rien d'autre : la pleine largeur d'une action
     principale, et la version courte des barres d'onglets, des filtres et des
     actions groupées. Tout ce qui s'en écartait donnait des voisins bancals. */
  --btn-h:         48px;
  --btn-h-sm:      42px;

  --shadow:        0 10px 30px rgba(0, 0, 0, .45);
  --font:          system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }

/* Plusieurs composants sont en display:flex/grid : sans cette règle,
   l'attribut [hidden] n'aurait aucun effet sur eux. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  min-height: 100dvh;
  /* Rien ne doit jamais déborder sur les côtés : une seule ligne trop longue —
     une adresse e-mail, un nom de fichier — et toute la page se met à glisser
     horizontalement sur téléphone.
     `clip` et non `hidden` : `hidden` fait du corps un conteneur de défilement,
     et comme son contenu y tient toujours, la molette s'y arrêtait sans jamais
     atteindre la page. `clip` coupe pareil sans créer ce conteneur. */
  max-width: 100%;
  overflow-x: clip;
  background: var(--bg-deep);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Sur la page seulement, jamais sur le corps : posé sur les deux, il empêchait
   la molette de remonter du corps vers la page. */
html { overscroll-behavior-y: none; }

/* Le fond dégradé vit sur une couche fixe à part, et non sur le corps en
   `background-attachment: fixed` : cette propriété force le navigateur à
   repeindre tout l'écran à chaque image. Une couche fixe, elle, est peinte une
   fois puis simplement affichée. */
body { background: transparent; }
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(130% 80% at 50% 0%, rgba(24, 74, 122, .55), transparent 70%),
    linear-gradient(180deg, rgb(10, 27, 44) 0%, rgb(8, 21, 34) 45%, rgb(10, 33, 53) 100%);
}

/* Ciel étoilé, purement décoratif.
   Deux couches qui dérivent à des vitesses différentes : comme les motifs n'ont
   pas la même taille, le même décalage en pixels produit une parallaxe naturelle.
   Tout est animé en `background-position` et en `opacity`, jamais en layout :
   aucun recalcul de mise en page, donc aucun impact sur le défilement. */
.stars {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

/* Les trois couches sont plus grandes que l'écran du décalage qu'elles
   parcourent, pour que le déplacement ne découvre jamais de bord. */
.stars > i {
  position: absolute;
  inset: 0 -420px -300px 0;
  will-change: transform, opacity;
  opacity: .7;
  background-image:
    radial-gradient(1px 1px at 12% 22%, #fff, transparent),
    radial-gradient(1px 1px at 68% 14%, #cfe4ff, transparent),
    radial-gradient(1px 1px at 34% 58%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 82% 44%, #fff, transparent),
    radial-gradient(1px 1px at 22% 78%, #bcd8ff, transparent),
    radial-gradient(1px 1px at 55% 88%, #fff, transparent),
    radial-gradient(1px 1px at 91% 72%, #fff, transparent),
    radial-gradient(1px 1px at 5% 48%, #cfe4ff, transparent),
    radial-gradient(1px 1px at 44% 33%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 8% 8%, #cfe4ff, transparent),
    radial-gradient(1px 1px at 73% 63%, #fff, transparent),
    radial-gradient(1px 1px at 38% 5%, #bcd8ff, transparent),
    radial-gradient(1px 1px at 96% 26%, #fff, transparent),
    radial-gradient(1px 1px at 61% 47%, #cfe4ff, transparent),
    radial-gradient(1.5px 1.5px at 15% 92%, #fff, transparent),
    radial-gradient(1px 1px at 84% 84%, #fff, transparent);
  background-size: 420px 420px, 380px 380px, 500px 500px, 460px 460px,
                   400px 400px, 520px 520px, 440px 440px, 480px 480px,
                   360px 360px, 540px 540px, 410px 410px, 470px 470px,
                   390px 390px, 510px 510px, 430px 430px, 450px 450px;
  animation: derive-etoiles 240s linear infinite,
             scintillement 11s ease-in-out infinite;
}

/* Seconde couche, plus fine et plus lente : donne de la profondeur au ciel. */
.stars::after {
  content: '';
  position: absolute;
  inset: 0 -420px -300px 0;
  will-change: transform, opacity;
  opacity: .7;
  background-image:
    radial-gradient(1px 1px at 41% 9%, #fff, transparent),
    radial-gradient(1px 1px at 77% 31%, #bcd8ff, transparent),
    radial-gradient(1px 1px at 17% 64%, #fff, transparent),
    radial-gradient(1px 1px at 63% 71%, #cfe4ff, transparent),
    radial-gradient(1px 1px at 88% 91%, #fff, transparent),
    radial-gradient(1px 1px at 29% 37%, #fff, transparent),
    radial-gradient(1px 1px at 52% 19%, #cfe4ff, transparent),
    radial-gradient(1px 1px at 9% 45%, #fff, transparent),
    radial-gradient(1px 1px at 94% 57%, #bcd8ff, transparent),
    radial-gradient(1px 1px at 35% 82%, #fff, transparent),
    radial-gradient(1px 1px at 70% 96%, #fff, transparent),
    radial-gradient(1px 1px at 24% 14%, #cfe4ff, transparent);
  background-size: 660px 660px, 720px 720px, 610px 610px,
                   690px 690px, 640px 640px, 700px 700px,
                   580px 580px, 750px 750px, 630px 630px,
                   670px 670px, 710px 710px, 600px 600px;
  animation: derive-etoiles 380s linear infinite reverse,
             scintillement 17s ease-in-out infinite 3s;
}

/* Troisième couche, minuscule et très lente : c'est elle qui donne au ciel sa
   densité. Les deux premières portent le mouvement, celle-ci le remplissage. */
.stars::before {
  content: '';
  position: absolute;
  inset: 0 -420px -300px 0;
  will-change: transform, opacity;
  opacity: .5;
  background-image:
    radial-gradient(.8px .8px at 7% 31%, #fff, transparent),
    radial-gradient(.8px .8px at 48% 12%, #cfe4ff, transparent),
    radial-gradient(.8px .8px at 85% 20%, #fff, transparent),
    radial-gradient(.8px .8px at 26% 52%, #fff, transparent),
    radial-gradient(.8px .8px at 66% 40%, #bcd8ff, transparent),
    radial-gradient(.8px .8px at 13% 74%, #fff, transparent),
    radial-gradient(.8px .8px at 58% 66%, #cfe4ff, transparent),
    radial-gradient(.8px .8px at 92% 79%, #fff, transparent),
    radial-gradient(.8px .8px at 40% 94%, #fff, transparent),
    radial-gradient(.8px .8px at 78% 6%, #bcd8ff, transparent);
  background-size: 300px 300px, 330px 330px, 280px 280px, 350px 350px,
                   310px 310px, 290px 290px, 340px 340px, 320px 320px,
                   360px 360px, 270px 270px;
  animation: derive-etoiles 170s linear infinite,
             scintillement 8s ease-in-out infinite 1.5s;
}

@keyframes derive-etoiles {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-420px, -300px, 0); }
}

/* Pendant un cours en visio, le ciel est caché de toute façon : autant ne pas
   le faire tourner derrière la vidéo, le processeur sert à l'image. */
body:has(.salle) .stars { display: none; }

@keyframes scintillement {
  0%, 100% { opacity: .42; }
  50%      { opacity: .62; }
}

/* ------------------------------------------------------------ démarrage */

.boot {
  position: fixed; inset: 0; z-index: 50;
  display: grid; place-content: center; justify-items: center; gap: 22px;
  background: var(--bg-deep);
}
.boot-logo {
  width: 74px; height: 74px;
  display: block;
  border-radius: 18px;
  object-fit: cover;
  box-shadow: var(--shadow);
}
.boot-msg {
  max-width: min(88vw, 400px);
  padding: 16px 18px;
  border-radius: 14px;
  background: rgba(232, 178, 58, .12);
  border: 1px solid rgba(232, 178, 58, .4);
  font-size: 14.5px; line-height: 1.55;
  text-align: left;
}
.boot-msg code {
  padding: 1px 6px; border-radius: 5px;
  background: rgba(255, 255, 255, .1);
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px;
}

.spinner {
  width: 26px; height: 26px;
  border: 3px solid rgba(255, 255, 255, .18);
  border-top-color: var(--accent-soft);
  border-radius: 50%;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------- barres */

/* Pas de `backdrop-filter` sur les deux barres : à 92 et 96 % d'opacité le flou
   ne se voyait pas, mais il était recalculé à chaque image sous un ciel animé. */
.topbar {
  position: sticky; top: 0; z-index: 20;
  height: var(--topbar-h);
  display: flex; align-items: center; gap: 4px;
  padding: 0 6px;
  padding-top: env(safe-area-inset-top);
  background: rgba(10, 27, 44, .92);
  border-bottom: 1px solid var(--line);
}
.topbar h1 {
  flex: 1;
  margin: 0;
  font-size: 17px; font-weight: 600; text-align: center;
}
.topbar .icon-btn:last-child { order: -1; }

.icon-btn {
  width: 40px; height: 40px;
  display: grid; place-content: center;
  border: 0; border-radius: 10px;
  background: transparent; color: var(--text);
  cursor: pointer;
}
.icon-btn:hover { background: rgba(255, 255, 255, .07); }
.icon-btn svg {
  width: 22px; height: 22px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  background: rgba(8, 21, 34, .96);
  border-top: 1px solid var(--line);
}
.tabbar a {
  display: grid; place-content: center; justify-items: center; gap: 3px;
  text-decoration: none; color: var(--text-faint);
  font-size: 10.5px; letter-spacing: .01em;
  position: relative;
}
.tabbar a.on { color: var(--accent-soft); }
/* Profil, autres pages et déconnexion : le rail de l'écran PC seulement. */
.rail-seul { display: none !important; }

/* -------------------------------------------------------------- contenu */

.screen {
  position: relative; z-index: 1;
  max-width: 100%; overflow-x: clip;
  padding: var(--gutter);
  padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 24px);
  max-width: 720px;
  margin: 0 auto;
  min-height: 60vh;
}
.screen:focus { outline: none; }
.screen.no-tabs { padding-bottom: 32px; }

h2.title { margin: 4px 0 18px; font-size: 26px; font-weight: 700; letter-spacing: -.01em; }
h3.subtitle { margin: 26px 0 10px; font-size: 17px; font-weight: 600; }
p.lead { color: var(--text-dim); margin: 0 0 18px; }

/* --------------------------------------------------------------- cartes */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
}
.card + .card { margin-top: 12px; }

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.tile {
  display: block; text-decoration: none; color: inherit;
  border-radius: var(--radius); overflow: hidden;
  background: var(--surface); border: 1px solid var(--line);
}
.tile .tile-fond { display: block; width: 100%; }
.tile img, .tile .tile-img {
  display: block; width: 100%; aspect-ratio: 1 / 1; object-fit: cover;
}
.tile .tile-label { padding: 10px 12px; font-weight: 600; font-size: 14px; }

.row {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none; color: inherit;
  width: 100%; text-align: left;
  cursor: pointer;
}
.row + .row { margin-top: 10px; }
.row .row-main { flex: 1; min-width: 0; }
.row .row-title { font-weight: 600; overflow-wrap: anywhere; }
.row .row-sub { color: var(--text-dim); font-size: 13.5px; overflow-wrap: anywhere; }

/* Un nom de personne, partout où il apparaît dans une liste. Le bleu le
   distingue du reste de la ligne : c'est par lui qu'on reconnaît un cours. */
.nom { color: var(--accent-soft); font-weight: 600; }
.row .chev { color: var(--text-faint); flex: none; }

/* -------------------------------------------------------------- boutons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: var(--btn-h); padding: 0 18px;
  border: 0; border-radius: 12px;
  background: var(--accent); color: #fff;
  font: inherit; font-weight: 600;
  cursor: pointer;
}
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:not(:disabled):hover { background: var(--accent-soft); }
.btn + .btn { margin-top: 10px; }

/* Un bouton est un conteneur flex : sans cette règle, l'icône qu'il porte est
   un élément flexible comme un autre et se laisse écraser dès que le libellé
   est long. C'est ce qui rétrécissait la maison à cheminée de « Présentiel 2 »,
   le plus long des trois onglets, face aux deux autres. */
.btn svg { flex: none; }

/* Deux hauteurs, pas quatre. Elles traînaient jusqu'ici en styles en ligne —
   48, 42, 40, 36 — et deux boutons voisins n'avaient pas la même taille. */
.btn-compact { width: auto; min-height: var(--btn-h-sm); padding: 0 14px; font-size: 14px; }
.btn-ghost { background: transparent; border: 1px solid var(--line); color: var(--text); }
.btn-ghost:not(:disabled):hover { background: rgba(255, 255, 255, .06); }
.btn-google { background: #fff; color: #1f2733; }
.btn-google:not(:disabled):hover { background: #eef2f7; }
.btn-google svg { width: 18px; height: 18px; }

/* ------------------------------------------------------------ formulaire */

.field { margin-bottom: 14px; }
.field label { display: block; margin-bottom: 6px; font-size: 13.5px; color: var(--text-dim); }
.field input, .field select, .field textarea {
  width: 100%; min-height: 48px; padding: 12px 14px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: 12px;
  font: inherit;
}
.field textarea { min-height: 96px; resize: vertical; }

/* Le champ de fichier natif est minuscule et ne ressemble à rien d'autre dans
   l'application. On lui rend la hauteur et la bordure d'un champ ordinaire, et
   son bouton interne prend l'allure d'un bouton court. */
.fichier {
  width: 100%; min-height: var(--btn-h); padding: 0 12px;
  display: flex; align-items: center; gap: 12px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--line); border-radius: 12px;
  font: inherit; font-size: 14px; cursor: pointer;
}
.fichier::file-selector-button {
  min-height: var(--btn-h-sm); padding: 0 14px;
  border: 0; border-radius: 10px;
  background: var(--accent); color: #fff;
  font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
}
.fichier::file-selector-button:hover { background: var(--accent-soft); }
.fichier:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent;
}
.field .err { margin-top: 6px; font-size: 13px; color: var(--danger); }
.field.invalid input, .field.invalid select { border-color: var(--danger); }

/* -------------------------------------------------------------- divers */

.note {
  display: flex; gap: 10px;
  padding: 12px 14px; border-radius: 12px;
  background: var(--accent-dim); border: 1px solid rgba(31, 122, 224, .35);
  font-size: 14px;
}
.note.warn { background: rgba(232, 178, 58, .12); border-color: rgba(232, 178, 58, .4); }
.note.ok   { background: rgba(63, 191, 111, .13); border-color: rgba(63, 191, 111, .45); }

.avatar {
  width: 44px; height: 44px; flex: none;
  border-radius: 50%; background: var(--surface-2) center/cover no-repeat;
  display: grid; place-content: center; font-weight: 600; color: var(--text-dim);
}
/* Les pastilles sans photo portent la silhouette : une page d'initiales
   colorées se lit comme un tableau de lettres, pas comme une liste de gens. */
.avatar svg {
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}

.empty { text-align: center; padding: 48px 16px; color: var(--text-dim); }
.empty .empty-emoji { font-size: 40px; display: block; margin-bottom: 10px; }

/* --------------------------------------------------------------- menu */

.drawer { position: fixed; inset: 0; z-index: 40; }
.drawer-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .55); }
.drawer-panel {
  position: absolute; inset: 0 auto 0 0; width: min(84vw, 320px);
  padding: calc(env(safe-area-inset-top) + 18px) 16px 24px;
  background: var(--bg); border-right: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 18px;
  overflow-y: auto;
  animation: slide-in .18s ease-out;
}
@keyframes slide-in { from { translate: -100% 0; } }
.drawer-head {
  display: flex; align-items: center; gap: 12px;
  /* C'est devenu le chemin vers le profil : l'entrée de menu a disparu, et on
     y va en cliquant sa photo ou son nom. */
  text-decoration: none; color: inherit;
  padding: 8px; margin: -8px; border-radius: 12px;
}
.drawer-head:hover { background: rgba(255, 255, 255, .06); }
.drawer-name { font-weight: 600; }
.drawer-mail { color: var(--text-faint); font-size: 13px; word-break: break-all; }
.drawer-links { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.drawer-links a {
  padding: 12px 12px; border-radius: 10px;
  text-decoration: none; color: var(--text); font-size: 15px;
  display: flex; align-items: center; gap: 12px;
}
.drawer-links a svg {
  flex: none; fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; opacity: .75;
}
.drawer-links a.on svg { opacity: 1; }
.drawer-links a:hover { background: rgba(255, 255, 255, .06); }
.drawer-links a.on { background: var(--accent-dim); color: var(--accent-soft); }

/* -------------------------------------------------------------- toasts */

.toasts {
  /* Au-dessus des feuilles (`.voile`, z-index 60) : à égalité, la feuille
     l'emportait car ajoutée au `body` plus tard, et les messages d'erreur
     d'un formulaire en feuille n'apparaissaient jamais. */
  position: fixed; z-index: 80;
  left: 50%; translate: -50% 0;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 16px);
  display: flex; flex-direction: column; gap: 8px;
  width: min(92vw, 420px);
}
.toast {
  padding: 13px 16px; border-radius: 12px;
  background: var(--surface-2); border: 1px solid var(--line);
  box-shadow: var(--shadow); font-size: 14.5px;
  animation: rise .18s ease-out;
}
.toast.err { border-color: rgba(226, 87, 76, .5); }
.toast.ok { border-color: rgba(52, 199, 123, .5); }
@keyframes rise { from { translate: 0 10px; opacity: 0; } }

/* Bandeau hors ligne */
.offline-bar {
  position: fixed; z-index: 30;
  left: 0; right: 0; top: calc(var(--topbar-h) + env(safe-area-inset-top));
  padding: 7px 16px; text-align: center;
  background: var(--warn); color: #241a00;
  font-size: 13px; font-weight: 600;
}

@media (min-width: 720px) {
  .screen { padding-inline: 24px; }
}

/* Mouvement réduit : on coupe les animations au lieu de les accélérer.
   Sans `iteration-count: 1`, une animation infinie ramenée à 0,01 ms
   se mettrait à clignoter frénétiquement — exactement l'inverse du but. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ------------------------------------------------------------ calendrier */

.calendrier {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 12px 12px 4px;
}

.cal-barre {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px;
}
.cal-titre { font-weight: 650; font-size: 15.5px; }
.cal-titre::first-letter { text-transform: uppercase; }
.cal-fleche {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 10px;
  background: transparent; border: 1px solid var(--line); color: var(--text);
  cursor: pointer;
}
.cal-fleche:hover { background: var(--accent-dim); }
/* La même icône sert aux deux sens : la première est retournée. */
.cal-fleche:first-child svg { transform: rotate(180deg); }

.cal-grille {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px;
}
.cal-nom {
  text-align: center; font-size: 11.5px; color: var(--text-dim);
  padding-bottom: 4px; text-transform: uppercase; letter-spacing: .04em;
}

.cal-jour {
  position: relative; aspect-ratio: 1 / 1;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid transparent; border-radius: 10px;
  color: var(--text); font-size: 14.5px; cursor: pointer;
  padding: 0;
}
.cal-jour:hover { background: var(--accent-dim); }
/* Sur ordinateur la grille est large : des cases carrées deviendraient très hautes. */
@media (min-width: 720px) {
  .cal-jour { aspect-ratio: auto; height: 42px; }
}
.cal-jour.hors { color: var(--text-dim); opacity: .45; }
/* Un jour qui porte quelque chose se voit sans avoir à le lire. */
.cal-jour.plein { background: var(--accent-dim); font-weight: 650; }
.cal-jour.aujourdhui { border-color: var(--text-dim); }
.cal-jour.choisi { background: var(--accent); color: #fff; border-color: var(--accent); }

.cal-pastille {
  position: absolute; top: 3px; right: 3px;
  min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 8px; background: var(--accent); color: #fff;
  font-size: 10px; line-height: 15px; font-weight: 700;
}
.cal-jour.choisi .cal-pastille { background: #fff; color: var(--accent); }

.cal-detail { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 12px; }
.cal-detail-titre {
  font-size: 13.5px; color: var(--text-dim); margin-bottom: 8px;
}
.cal-detail-titre::first-letter { text-transform: uppercase; }
.cal-invite { color: var(--text-dim); font-size: 14px; padding: 6px 0 14px; }

.cal-creneau {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: var(--surface-2, transparent); border: 1px solid var(--line);
  border-radius: 12px; padding: 12px 14px; margin-bottom: 8px;
  color: var(--text); font-size: 15px; text-align: left; cursor: pointer;
}
.cal-creneau:hover { border-color: var(--accent); background: var(--accent-dim); }
.cal-creneau.pris { opacity: .55; cursor: default; }
.cal-creneau.pris:hover { border-color: var(--line); background: transparent; }
.cal-creneau .sous { color: var(--text-dim); font-size: 13px; }

/* -------------------------------------------------------- feuille modale */

.voile {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(3, 9, 16, .62);
  display: flex; align-items: flex-end; justify-content: center;
}
@media (min-width: 620px) { .voile { align-items: center; } }

.feuille {
  width: 100%; max-width: 560px; max-height: 88vh;
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 18px 18px 0 0;
  animation: monte .18s ease-out;
}
@media (min-width: 620px) { .feuille { border-radius: 18px; } }
@keyframes monte { from { transform: translateY(16px); opacity: .6 } }

.feuille-tete {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 16px 16px 10px; border-bottom: 1px solid var(--line);
}
.feuille-tete h2 { margin: 0; font-size: 17px; }
.feuille-corps { padding: 16px; overflow-y: auto; }

.detail-liste { display: grid; grid-template-columns: auto 1fr; gap: 9px 16px; margin: 0 0 6px; }
.detail-liste dt { color: var(--text-dim); font-size: 13.5px; white-space: nowrap; }
.detail-liste dd { margin: 0; font-size: 14.5px; }

/* ------------------------------------------------------------- onglets */

/*
 * Les boutons d'un sélecteur partagent la largeur à parts égales.
 * `flex: 1 1 0` plutôt que la largeur de `.btn` : sinon le bouton au libellé
 * le plus long refuse de rétrécir et s'accapare la place.
 */
.onglets { display: flex; gap: 8px; margin-bottom: 18px; }
.onglets .btn {
  flex: 1 1 0; min-width: 0; width: auto;
  min-height: var(--btn-h-sm); padding: 0 10px; font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.onglets .btn + .btn { margin-top: 0; }

.cal-titre-groupe { display: flex; align-items: center; gap: 8px; }
.cal-titre-groupe svg { color: var(--accent-soft); flex: none; }

/* Un jour dont au moins un créneau est réservé. */
.cal-jour.reserve { background: rgba(52, 199, 123, .18); }
.cal-jour.reserve .cal-pastille { background: var(--ok); }
.cal-jour.choisi.reserve { background: var(--ok); border-color: var(--ok); }
.cal-jour.choisi.reserve .cal-pastille { background: #fff; color: var(--ok); }

.cal-creneau.reserve {
  border-color: rgba(52, 199, 123, .55);
  background: rgba(52, 199, 123, .12);
}
.cal-creneau.reserve:hover { border-color: rgba(52, 199, 123, .55); }
.cal-creneau .marque {
  flex: none; font-size: 12px; padding: 3px 9px; border-radius: 8px;
  background: rgba(52, 199, 123, .2); color: var(--ok);
}
.cal-ajout { margin-top: 4px; }

/* ------------------------------------------------ réservation en une page */

.bloc-choix { margin-bottom: 20px; }

/* Une question déjà répondue se replie en une ligne, cliquable pour revenir. */
.row.choix-fait {
  width: 100%; text-align: left; cursor: pointer;
  border-color: var(--accent-dim); background: var(--accent-dim);
}
.row.choix-fait:hover { border-color: var(--accent); }
.row.choix-fait .row-sub:last-child { color: var(--accent-soft); flex: none; }

.pastilles { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.pastille {
  border: 1px solid var(--line); background: transparent; color: var(--text);
  border-radius: 999px; padding: 0 16px; min-height: var(--btn-h-sm);
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit; font-size: 14px; cursor: pointer;
}
.pastille:hover { border-color: var(--accent); background: var(--accent-dim); }
.pastille.on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* --------------------------------------------------------------- graphe */

.graphe { margin: 14px 0 4px; color: var(--text); }
.graphe-max { font-size: 11.5px; color: var(--text-dim); margin-bottom: 2px; }
.graphe svg { display: block; overflow: visible; }
.graphe-legende {
  display: flex; flex-wrap: wrap; gap: 14px; margin-top: 8px;
  font-size: 12.5px; color: var(--text-dim);
}
.graphe-legende span { display: inline-flex; align-items: center; gap: 6px; }
.graphe-legende i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

/* ----------------------------------------------------------- camembert */

/* Le disque et sa légende côte à côte quand la place le permet, l'un sous
   l'autre sur un téléphone étroit : une légende de six lignes serrée contre un
   disque de 180 px devient illisible sous 340 px. */
.camembert-corps {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  margin: 10px 0 2px;
}
.camembert-corps > svg { flex: none; margin: 0 auto; }
.camembert-legende { flex: 1 1 150px; min-width: 0; display: flex;
                     flex-direction: column; gap: 2px; }

/* Chaque entrée est un bouton : c'est par elle qu'on atteint les parts trop
   fines pour le pouce. */
.camembert-entree {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 5px 8px; border: 0; border-radius: 8px;
  background: transparent; color: var(--text-dim);
  font: inherit; font-size: 12.5px; text-align: left; cursor: pointer;
}
.camembert-entree:hover { background: var(--surface-2); }
.camembert-entree.on { background: var(--accent-dim); color: var(--text); }
.camembert-entree i {
  flex: none; width: 10px; height: 10px; border-radius: 3px; display: inline-block;
}
.camembert-nom {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.camembert-part { flex: none; font-variant-numeric: tabular-nums; font-weight: 600; }
.camembert path, .camembert circle { transition: opacity .15s ease; }

/* ------------------------------------------------------- fiche admin */

.admin-ligne {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 14.5px;
}
.admin-ligne span:first-child { color: var(--text-dim); }
.admin-actions { display: flex; gap: 8px; margin-top: 8px; }
.admin-actions .btn { width: auto; flex: 1; min-height: var(--btn-h-sm); }

/* --------------------------------------------------------- Math'ching */

/* La marque ne se montre qu'une fois l'élève entré dans son groupe. */
.matching-marque {
  display: inline-block; padding: 4px 11px; border-radius: 999px;
  background: var(--accent); color: #fff;
  font-weight: 700; font-size: 12.5px; letter-spacing: .3px;
}
.matching-tete { margin: 14px 0 4px; }

/* Les membres en grille : trois par ligne sur un téléphone. */
.membres {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 14px 8px;
}
.membre { text-align: center; display: flex; flex-direction: column;
          align-items: center; gap: 6px; }
.membre-nom  { font-size: 13px; font-weight: 600; line-height: 1.2; }
.membre-role { font-size: 11.5px; color: var(--text-dim); min-height: 14px; }

.matching-suite { margin-top: 30px; display: flex; flex-direction: column; gap: 10px; }
.matching-suite .btn[disabled] { opacity: .45; cursor: default; }

.puce-ok {
  flex: none; padding: 3px 9px; border-radius: 999px; font-size: 11.5px;
  font-weight: 600; background: rgba(63, 191, 111, .16); color: #7ee2a8;
}

/* Solde de Fichetons, en tête de la boutique : le nombre et rien d'autre. */
.bulle {
  flex: none; min-width: 44px; padding: 0 12px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 17px; background: var(--accent); color: #fff;
  font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums;
}

/* Les deux soldes se partagent la largeur à parts égales. */
.soldes { display: flex; gap: 10px; margin-bottom: 22px; }
.soldes .card {
  flex: 1 1 0; min-width: 0; text-align: center;
  /* Même hauteur pour les deux : sans le `nowrap`, « Pi-ons » passait à la
     ligne sur un solde à deux chiffres et la carte grandissait toute seule. */
  padding: 12px 10px; white-space: nowrap; overflow: hidden;
}
.soldes .card + .card { margin-top: 0; }

/* Prof visible et réservable, dans la liste d'administration. */
.card.prof-visible {
  background: var(--accent); border-color: var(--accent); color: #fff;
}
.card.prof-visible .row-sub { color: rgba(255, 255, 255, .8); }
.card.prof-visible .avatar { background: rgba(255, 255, 255, .22); color: #fff; }
.card.prof-visible svg { color: #fff; }

.graphe-lecture {
  margin-top: 8px; font-size: 13.5px; color: var(--text-dim);
  min-height: 20px;
}
.graphe-lecture strong { color: var(--text); font-size: 15px; }
.graphe svg rect:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 2px; }

/* L'offre que le calculateur vient de recommander : on la désigne sans la
   sélectionner, le choix restant à l'élève. */
.surligne {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  animation: surligne-pulse 1.4s ease-out 2;
}
@keyframes surligne-pulse {
  0%, 100% { outline-color: var(--accent); }
  50%      { outline-color: transparent; }
}

/* ------------------------------------------------------- notifications */

.topbar .cloche { position: relative; margin-left: auto; }

.cloche-compteur {
  position: absolute; top: 3px; right: 2px;
  min-width: 17px; height: 17px; padding: 0 4px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 9px; background: #e0574b; color: #fff;
  font-size: 10.5px; font-weight: 700; line-height: 1;
  border: 2px solid var(--bg, #0b1220);
}

/* Une notification non lue se repère sans avoir à comparer les lignes. */
.row.notif.non-lue {
  border-color: var(--accent);
  background: var(--accent-dim, rgba(45, 120, 220, .1));
}

/* ------------------------------------------------------ marque de l'en-tête */

/* La barre du haut porte le logo et le nom, à la place du titre de l'écran :
   celui-ci est déjà écrit en grand sous la barre, et le répéter volait la
   place de la marque. */
/* La marque est centrée dans la barre, pas collée au menu : elle occupe la
   place que prendrait un titre, et les deux boutons l'encadrent. Les marges
   automatiques la centrent sur la barre entière, ce qu'un `flex:1` ne fait
   pas dès que les boutons de gauche et de droite n'ont pas la même largeur. */
.topbar-marque {
  min-width: 0; margin: 0 auto;
  display: flex; align-items: center; gap: 9px;
  text-decoration: none; color: var(--text);
}
.topbar-marque img {
  width: 28px; height: 28px; flex: none;
  border-radius: 7px; object-fit: cover;
}
.topbar-marque span {
  font-size: 16px; font-weight: 700; letter-spacing: .01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ------------------------------------------- particules des logos matières */

/* Des poussières blanches qui montent par-dessus le visuel de la matière.

   Par-dessus, et non derrière : les visuels sont des images opaques, et une
   couche placée dessous est purement et simplement invisible. C'était l'erreur
   — le code était bon, l'animation tournait, et personne ne la voyait jamais.

   Tout est animé en `background-position`, comme le ciel du fond : aucun
   recalcul de mise en page, et rien à exécuter en JavaScript. Le dégradé
   vertical fait naître les particules en bas et les éteint en haut, sinon
   elles réapparaîtraient d'un coup à chaque tour de boucle. */
.tile-fond {
  position: relative;
  overflow: hidden;
  background: linear-gradient(160deg, #15507f, #0b2a45);
}
/* Des poussières blanches qui montent par-dessus le visuel, et s'effacent en
   chemin — certaines dès le bas, d'autres seulement tout en haut.

   Deux points ont demandé d'être corrigés :

   1. La couche ne déborde plus (`inset: 0`). Avec `inset: -35%`, le masque
      s'étalait sur une zone une fois et demie plus haute que la vignette, si
      bien qu'on n'en voyait que la tranche centrale — la plus plate. Les
      poussières paraissaient alors uniformément opaques, sans jamais
      s'éteindre. Le motif se répétant, rien ne manque au raccord.

   2. Les deux couches ont maintenant des masques très différents. Celles du
      dessus s'éteignent à mi-hauteur, celles du dessous montent jusqu'au
      sommet : c'est ce qui donne des poussières qui disparaissent au hasard,
      et non un rideau qui monte d'un bloc. */

/* Couche rapide : beaucoup de petites poussières, éteintes à mi-parcours. */
.tile-fond::after,
.particules::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image:
    radial-gradient(2.6px 2.6px at 22% 86%, #fff, transparent 60%),
    radial-gradient(1.4px 1.4px at 61% 74%, #fff, transparent 60%),
    radial-gradient(3.2px 3.2px at 85% 93%, #fff, transparent 60%),
    radial-gradient(1.9px 1.9px at 37% 63%, #fff, transparent 60%),
    radial-gradient(2.4px 2.4px at 9% 49%, #fff, transparent 60%),
    radial-gradient(1.5px 1.5px at 73% 35%, #fff, transparent 60%),
    radial-gradient(2.9px 2.9px at 47% 19%, #fff, transparent 60%),
    radial-gradient(1.3px 1.3px at 93% 55%, #fff, transparent 60%),
    radial-gradient(2.1px 2.1px at 29% 31%, #fff, transparent 60%),
    radial-gradient(1.7px 1.7px at 56% 47%, #fff, transparent 60%);
  background-size: 58px 78px, 84px 112px, 52px 70px, 96px 126px,
                   66px 88px, 78px 104px, 55px 74px, 88px 118px,
                   62px 84px, 72px 96px;
  -webkit-mask-image: linear-gradient(to top,
    transparent 0%, #fff 7%, #fff 22%, rgba(255,255,255,.45) 42%,
    rgba(255,255,255,.12) 58%, transparent 70%);
          mask-image: linear-gradient(to top,
    transparent 0%, #fff 7%, #fff 22%, rgba(255,255,255,.45) 42%,
    rgba(255,255,255,.12) 58%, transparent 70%);
  animation: monte-particules var(--souffle, 6s) linear infinite;
  animation-delay: var(--grain, 0s);
}

/* Couche lente : peu de poussières, plus grosses, qui vont jusqu'en haut.
   Ce sont elles qu'on voit encore au sommet du logo. */
.tile-fond::before,
.particules::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image:
    radial-gradient(3.6px 3.6px at 34% 88%, #fff, transparent 58%),
    radial-gradient(2.8px 2.8px at 76% 58%, #fff, transparent 58%),
    radial-gradient(4.2px 4.2px at 12% 40%, #fff, transparent 58%),
    radial-gradient(2.4px 2.4px at 58% 16%, #fff, transparent 58%),
    radial-gradient(3.1px 3.1px at 90% 72%, #fff, transparent 58%);
  background-size: 118px 168px, 146px 208px, 130px 186px, 160px 228px, 136px 196px;
  -webkit-mask-image: linear-gradient(to top,
    transparent 0%, #fff 6%, #fff 55%, rgba(255,255,255,.55) 80%,
    rgba(255,255,255,.25) 93%, transparent 100%);
          mask-image: linear-gradient(to top,
    transparent 0%, #fff 6%, #fff 55%, rgba(255,255,255,.55) 80%,
    rgba(255,255,255,.25) 93%, transparent 100%);
  animation: monte-grosses calc(var(--souffle, 6s) * 2.1) linear infinite;
  animation-delay: var(--grain, 0s);
}

/* Le même souffle autour d'un élément qui n'est pas une vignette. */
.particules { position: relative; }
.tile-fond { overflow: hidden; }

@keyframes monte-grosses {
  to { background-position: 0 -168px, 0 -208px, 0 -186px, 0 -228px, 0 -196px; }
}

@keyframes monte-particules {
  to {
    background-position: 0 -78px, 0 -112px, 0 -70px, 0 -126px,
                         0 -88px, 0 -104px, 0 -74px, 0 -118px,
                         0 -84px, 0 -96px;
  }
}

/* Quelqu'un qui a demandé moins d'animations n'en veut pas ici non plus. */
@media (prefers-reduced-motion: reduce) {
  .tile-fond::after, .particules::after,
  .tile-fond::before, .particules::before { animation: none; }
}

/* ---------------------------------------------------- documents longs */

/* Politique de confidentialité et autres textes juridiques : ce qui compte
   est qu'ils se lisent, pas qu'ils soient jolis. Les trois niveaux de titre
   doivent surtout se distinguer les uns des autres. */
.texte-long { font-size: 14.5px; line-height: 1.65; color: var(--text-dim); }
.texte-long h3 { margin: 26px 0 10px; font-size: 16.5px; color: var(--text); }
.texte-long h4 { margin: 18px 0 8px; font-size: 14.5px; color: var(--accent-soft); }
.texte-long strong { color: var(--text); }
.texte-long a { color: var(--accent-soft); overflow-wrap: anywhere; }


/* ------------------------------------------------- connexion et inscription */

/* Les écrans hors session : pas de barre, pas d'onglets, un contenu étroit et
   centré. Le logo remplace le titre de page qui n'existe pas encore ici. */
.connexion {
  max-width: 420px; margin: 0 auto;
  padding: calc(env(safe-area-inset-top) + 22px) 0 40px;
}
.connexion-logo {
  display: block; width: 72px; height: 72px;
  margin: 0 auto 16px; border-radius: 18px;
  object-fit: cover; box-shadow: var(--shadow);
}

/* Le « ou » entre deux façons de se connecter, barré de part et d'autre. */
.separateur {
  display: flex; align-items: center; gap: 12px;
  margin: 20px 0; color: var(--text-faint); font-size: 13px;
}
.separateur::before, .separateur::after {
  content: ''; flex: 1; height: 1px; background: var(--line);
}

/* Un lien vers un document, à l'intérieur d'une phrase. */
.lien-doc {
  padding: 0; border: 0; background: none;
  color: var(--accent-soft); font: inherit; font-weight: 600;
  text-decoration: underline; cursor: pointer;
}

/* Le rappel de vérification d'adresse, en tête d'écran. */
.bandeau-verif {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 16px; padding: 12px 14px;
  border-radius: 12px; font-size: 14px;
  background: rgba(232, 178, 58, .12);
  border: 1px solid rgba(232, 178, 58, .4);
}
.bandeau-verif .btn { width: auto; min-height: 34px; padding: 0 12px; font-size: 13px; }


/* ------------------------------------------------ étoiles montantes */

/* Reprise du décor de la barre d'outils du tableau blanc : de vraies étoiles,
   chacune avec sa taille, son opacité, son délai et sa durée, qui montent et
   s'éteignent. Un motif de fond ne donnait pas ce rythme irrégulier — toutes
   les poussières y partagent la même horloge.

   L'hôte est un conteneur positionné ; les étoiles y sont posées avant
   l'élément, et passent donc dessous sans recourir à un `z-index` négatif,
   qui les faisait disparaître derrière le fond de la ligne parente. */
.etoiles-hote { position: relative; display: block; }
.etoiles-hote > .btn,
.etoiles-hote > .pastille-ronde { position: relative; }
/* Dans une ligne, l'hôte prend exactement la taille de sa pastille et ne se
   laisse ni étirer ni comprimer. */
.row > .etoiles-hote { flex: none; width: 40px; height: 40px; }
.row > .etoiles-hote > .etoiles { inset: -10px -7px -3px; }

/* Un bouton pleine largeur : les étoiles naissent une douzaine de pixels sous
   lui, le traversent par-derrière — invisibles le temps du passage — et
   ressortent au-dessus avant de s'éteindre. Le champ déborde donc en haut ET
   en bas, et le masque garde de l'opacité jusqu'aux trois quarts pour que la
   sortie par le haut se voie autant que l'entrée par le bas. */
.etoiles-hote:has(> .btn) > .etoiles { inset: -16px -9px -12px; }
.etoiles-hote:has(> .btn) > .etoiles > .etoile {
  --course: 76px;
}
.etoiles-hote:has(> .btn) > .etoiles {
  -webkit-mask-image: linear-gradient(to top,
    transparent 0%, #fff 8%, #fff 72%, rgba(255,255,255,.55) 88%, transparent 100%);
          mask-image: linear-gradient(to top,
    transparent 0%, #fff 8%, #fff 72%, rgba(255,255,255,.55) 88%, transparent 100%);
}

/* Un champ serré : les étoiles doivent friser l'élément, pas flotter autour.
   Elles montent de quelques pixels et s'éteignent tout de suite. */
.etoiles {
  position: absolute;
  inset: -12px -6px -4px;
  pointer-events: none;
  overflow: visible;
}
.etoile {
  position: absolute;
  bottom: 0;
  fill: #fff;
  opacity: 0;
  animation-name: etoile-monte;
  animation-timing-function: ease-in;
  animation-iteration-count: infinite;
}
@keyframes etoile-monte {
  0%   { transform: translate(-50%, 0); opacity: 0; }
  14%  { opacity: var(--cime, .5); }
  60%  { opacity: var(--cime, .5); }
  100% { transform: translate(-50%, calc(0px - var(--course, 70px))); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .etoile { animation: none; opacity: 0; }
}

/* ------------------------------------------------- pastille des non-lus */

/* Elle n'avait jamais été dessinée : le compteur sortait en texte nu sous
   l'icône. Positionnée en absolu sur l'onglet, qui est déjà `relative`. */
.tabbar a .badge {
  position: absolute;
  top: 6px; left: 50%;
  transform: translateX(2px);
  min-width: 17px; height: 17px;
  padding: 0 5px;
  display: grid; place-content: center;
  border-radius: 999px;
  background: var(--err, #e0574b); color: #fff;
  font-size: 10.5px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- écran PC */

/* Sous 1024 px l'application reste celle du téléphone : une colonne, la
   navigation en bas sous le pouce. Au-dessus, cette disposition gaspille
   l'écran — quatre vignettes de matière occupaient 700 px de haut, et la
   barre d'onglets barrait toute la largeur pour cinq liens.
   La navigation passe donc sur le côté, là où la souris la cherche, et le
   contenu reprend la largeur disponible. */
@media (min-width: 1024px) {
  :root { --rail-w: 236px; }

  /* Le rail est en `fixed` ; c'est le décalage du corps qui lui fait sa
     place, ce qui laisse `.screen` se centrer tout seul dans le reste. */
  body { padding-left: var(--rail-w); }

  .tabbar {
    top: 0; bottom: 0; right: auto;
    width: var(--rail-w); height: 100%;
    padding: 14px 12px;
    grid-auto-flow: row;
    grid-auto-columns: auto;
    grid-auto-rows: max-content;
    align-content: start;
    gap: 3px;
    border-top: 0;
    border-right: 1px solid var(--line);
  }
  .tabbar a {
    grid-auto-flow: column;
    grid-template-columns: 22px 1fr;
    place-content: stretch;
    justify-items: start;
    align-items: center;
    gap: 13px;
    height: 46px;
    padding: 0 13px;
    border-radius: 10px;
    font-size: 14.5px;
    letter-spacing: 0;
  }
  .tabbar a:hover { background: rgba(255, 255, 255, .06); }
  .tabbar a.on { background: var(--accent-dim); }

  /* Le rail est la seule navigation : le bouton « ≡ » n'a plus d'objet. */
  #menu-btn { display: none; }

  /* Colonne : profil en haut, entrées au milieu, le reste collé en bas. */
  .tabbar { display: flex; flex-direction: column; overflow-y: auto; }
  .tabbar .rail-profil { display: flex !important; height: auto; padding: 10px 13px; margin-bottom: 10px;
                         gap: 12px; border-bottom: 1px solid var(--line); border-radius: 10px; }
  .tabbar .rail-profil-texte { min-width: 0; }
  .tabbar .rail-profil .drawer-mail { font-size: 12.5px; word-break: normal; overflow: hidden; text-overflow: ellipsis; }
  .tabbar .rail-bas { display: flex !important; flex-direction: column; gap: 3px; margin-top: auto; padding-top: 14px;
                      border-top: 1px solid var(--line); }
  .tabbar .rail-bas a { height: 42px; color: var(--text); }
  .tabbar .rail-bas a.on { color: var(--accent-soft); }

  /* Profil et entrées du haut en blanc : le gris est celui de la barre du bas du téléphone. */
  .tabbar > a:not(.on) { color: #fff; }
  .tabbar .rail-profil .avatar { color: #fff; }
  .tabbar .rail-bas .btn { margin-top: 10px; }

  /* Replacée à droite du libellé : au-dessus de l'icône, elle chevauchait le
     texte maintenant qu'ils sont côte à côte. */
  .tabbar a .badge {
    position: static;
    transform: none;
    justify-self: end;
  }

  .topbar { padding: 0 14px; }
  .topbar h1 { text-align: left; padding-left: 4px; }

  .screen {
    max-width: 1040px;
    padding: 26px 32px 56px;
  }

  /* Quatre matières sur une ligne plutôt que deux pavés de 330 px. La même
     règle sert la boutique et la liste des profs, qui partagent cette grille. */
  .grid2 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 16px; }

  /* Rien à faire pour les feuilles, le tiroir ni les toasts : en `fixed`, ils
     se placent par rapport à la fenêtre, pas par rapport au corps décalé. */
}

/* Très large : on cesse d'étirer, le texte deviendrait illisible en lignes
   trop longues, et la colonne se centre dans l'espace restant. */
@media (min-width: 1500px) {
  .screen { max-width: 1120px; }
}

/* ------------------------------------------- glisser pour supprimer */
.glisse { position: relative; overflow: hidden; border-radius: 14px; }
.glisse-actions { position: absolute; top: 0; right: 0; bottom: 0; display: flex; }
.glisse-sup { flex: 1; border: 0; cursor: pointer; color: #fff; font-size: 14px; }
.glisse-sup:last-child { border-radius: 0 14px 14px 0; }
.glisse-piste { position: relative; touch-action: pan-y; display: flex; flex-direction: column; }
.glisse-piste > .row { width: 100%; }

/* ------------------------------------ menu d'un message (ordinateur) */
.msg-ligne { align-self: flex-end; max-width: 82%; display: flex; align-items: center; gap: 4px; }
.msg-outils { position: relative; flex: none; }
.msg-points {
  width: 28px; height: 28px; border: 0; border-radius: 50%; cursor: pointer;
  background: transparent; color: var(--text-dim); font-size: 18px; line-height: 1;
  opacity: 0; transition: opacity .12s;
}
.msg-ligne:hover .msg-points, .msg-points:focus-visible { opacity: 1; }
.msg-points:hover { background: rgba(255, 255, 255, .08); }
.msg-menu {
  position: absolute; right: 0; top: 100%; z-index: 20; min-width: 130px; padding: 4px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow);
}
.msg-menu button {
  display: block; width: 100%; padding: 8px 12px; border: 0; border-radius: 7px; cursor: pointer;
  background: transparent; color: var(--text); font: inherit; font-size: 14px; text-align: left;
}
.msg-menu button:hover { background: rgba(255, 255, 255, .08); }
.msg-menu button:last-child { color: #f08a24; }

/* Champ mot de passe : l'œil se pose à droite, dans le champ. */
.mdp-champ { position: relative; }
.mdp-champ input { padding-right: 46px; }
.oeil {
  position: absolute; top: 0; right: 0; bottom: 0; width: 44px;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 0; color: var(--text-dim); cursor: pointer;
}
.oeil:hover, .oeil[aria-pressed="true"] { color: var(--text); }

/* Avis : cinq étoiles à toucher. */
.etoiles-choix { display: flex; gap: 4px; margin-top: 6px; }
.etoile-choix {
  background: none; border: 0; padding: 2px 4px; cursor: pointer;
  font-size: 40px; line-height: 1; color: var(--text-faint);
  transition: transform .1s, color .1s;
}
.etoile-choix:hover { transform: scale(1.12); }
.etoile-choix.on { color: #f5c542; }

/* ------------------------------------------- survol des cartes (souris) */

/* Une carte cliquable se soulève et grossit à peine quand la souris la survole,
   avec un léger rebond : le mouvement dit « on peut appuyer ici ». Réservé aux
   appareils à souris — au doigt, le survol n'existe pas et resterait collé. */
@media (hover: hover) and (pointer: fine) {
  .tile, a.row, button.row, .cal-jour:not(.hors) {
    cursor: pointer;
    transition: transform .32s cubic-bezier(.34, 1.56, .64, 1), box-shadow .25s ease,
                background-color .15s, border-color .15s;
  }
  .tile:hover, a.row:hover, button.row:hover {
    transform: translateY(-4px) scale(1.025);
    box-shadow: 0 10px 22px rgba(0, 0, 0, .32);
    position: relative; z-index: 2;
  }
  .cal-jour:not(.hors):hover { transform: translateY(-2px) scale(1.1); position: relative; z-index: 2; }
}

/* ------------------------------------------------ texte en bleu (dépôts) */
.texte-bleu, .texte-bleu * { color: var(--accent-soft); }
.texte-bleu input[type="text"] { color: var(--accent-soft); }

/* ------------------------------------------------- écran PC : en-tête et boutique */
@media (min-width: 1024px) {
  /* Sans bouton de menu à gauche, la marque se centrait entre le bord et la
     cloche : on la centre sur la barre entière. */
  .topbar { position: sticky; }
  .topbar .topbar-marque {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    margin: 0;
  }

  /* La boutique : quatre cartes par ligne, plus compactes. */
  .grid-boutique { grid-template-columns: repeat(4, 1fr); gap: 14px; }
  .grid-boutique .tile .tile-label { padding: 8px 10px; font-size: 13px; }
}

/* Un élément de liste (note de cours) qui porte le menu « ⋮ » d'un message. */
.msg-ligne.plein { align-self: stretch; max-width: 100%; }

/* Connexion, inscription, documents légaux : pas de rail à gauche, donc rien à
   décaler — sinon la page se retrouve poussée vers la droite sur ordinateur. */
@media (min-width: 1024px) {
  body.sans-rail { padding-left: 0; }
}
