/* ══════════════════════════════════════════════════════════════════════════
   LE TABLEAU DE BORD PROFESSEUR SUR TÉLÉPHONE, TABLETTE ET PLIABLE
   05/09/2026

   AVANT CE FICHIER : zéro requête média dans teacher-dashboard.html. La page
   était dessinée pour 1400 points et servie telle quelle à un écran de 390.
   Vingt cartes de 170 points de haut sur deux colonnes font environ 1700
   points de défilement — cinq écrans — avant d'atteindre le moindre contenu.

   CE QUI EST FAIT ICI, ET CE QUI NE L'EST PAS
   Ce fichier ne change AUCUN balisage et AUCUNE logique. Il ne fait que
   redessiner ce qui existe à trois paliers :

     ≤ 690 de large            téléphone debout, et pliable REPLIÉ
     OU hauteur ≤ 500 au doigt  téléphone COUCHÉ — voir ci-dessous
     691-839 de large           pliable DÉPLIÉ, presque carré : 3 colonnes
     ≥ 840 de large             tablette et bureau — inchangé

   ⚠️ LE PAYSAGE SE RECONNAÎT À LA HAUTEUR, PAS À LA LARGEUR.
   Un téléphone couché mesure environ 844 × 390. Piloté sur la seule largeur,
   il tombait dans « ≥ 840 » et recevait la grille cinq colonnes du bureau sur
   390 points de haut, sans barre basse. C'est le défaut le plus facile à
   écrire et le plus difficile à voir : on ne teste jamais en tournant le
   téléphone. La condition retenue est donc :

       (max-width: 690px), (max-height: 500px) and (max-width: 950px)

   Le « pointer: coarse » borne le second cas aux écrans tactiles : une
   fenêtre de bureau réduite en hauteur ne doit pas recevoir une barre basse.

   En paysage, la ressource rare n'est plus la largeur mais la HAUTEUR : les
   libellés de la barre disparaissent, l'en-tête se réduit, et la grille passe
   à quatre colonnes puisque la place horizontale, elle, ne manque pas.

   Le pliable n'a pas de règle à lui : replié il tombe dans le premier palier,
   déplié dans le second. Une seule chose lui est propre, et elle est en bas
   de ce fichier : aligner les séparations sur la charnière.

   POURQUOI DES « !important »
   apps/teacher/core/dashboard.css impose des couleurs et des tailles avec
   !important sur des sélecteurs très larges (`button:not(...)` sur une
   quarantaine d'exceptions). Les surcharger proprement demanderait de
   réécrire ce balai — travail réel, risque réel, et sans rapport avec
   l'affichage mobile. Les !important d'ici sont donc délibérés et bornés aux
   classes préfixées « pmb- », qui n'existent que dans ce fichier.

   Contrôlé par scripts/test-responsive-prof.js.
   ══════════════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────────────────
   RIEN NE DOIT DÉBORDER LATÉRALEMENT — à toutes les tailles.
   Une page qui défile de côté sur un téléphone donne l'impression d'être
   cassée avant même qu'on ait lu une ligne.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 839px) {
  html, body { overflow-x: hidden; max-width: 100%; }

  /* Les tableaux larges défilent DANS leur propre boîte, pas avec la page. */
  .tab-content table { display: block; overflow-x: auto; max-width: 100%; }
  .tab-content pre,
  .tab-content .overflow-auto { overflow-x: auto; max-width: 100%; }
  .tab-content img,
  .tab-content canvas,
  .tab-content svg:not(.dashboard-icon) { max-width: 100%; height: auto; }
}

/* ─────────────────────────────────────────────────────────────────────────
   19/09/2026 — LE CONTENEUR DU TABLEAU EST BORNÉ PAR SON PARENT.

   Mesuré : la page défilait de côté de 379 px sur un téléphone couché (844)
   et de 187 px sur un iPad couché (1024). Les deux passent juste au-dessus de
   la borne « max-width: 839px » ci-dessus et recevaient la mise en page de
   bureau.

   J'avais d'abord ajouté un palier « pointer: coarse ». Le banc l'a refusé,
   avec raison : « les requêtes de capacité mentent — un téléphone avec une
   souris répond fine, une tablette Windows aussi ». En cherchant à respecter
   cette règle, la vraie cause est apparue, et elle ne demande aucun palier.

   Le tableau vit déjà dans un « <div class="overflow-x-auto"> », dont c'est
   le seul rôle. Il ne l'absorbait pas parce que RIEN NE LE BORNAIT : sans
   max-width, un bloc grandit pour contenir son enfant. Le conteneur prenait
   donc la largeur du tableau, et c'est la page qui partait de côté.

   Une ligne, valable à toute largeur, sur tout appareil, sans rien demander
   au navigateur sur ce qu'il croit être. Vérifié sur huit écrans par
   scripts/test-liste-eleves-ecrans.js.
   ───────────────────────────────────────────────────────────────────────── */
.overflow-x-auto { max-width: 100%; overflow-x: auto; }

/* ─────────────────────────────────────────────────────────────────────────
   19/09/2026 — DES CIBLES QU'UN DOIGT PEUT VISER.

   Les neuf outils d'une ligne d'élève font 32 px, à 4 px l'un de l'autre :
   sous les 44 px que recommandent Apple comme Google. Et depuis qu'ils sont
   sur deux rangées, ⏱️ « Tiers-temps » se trouve à 4 px sous 🗑️ « Supprimer
   l'élève » : un doigt qui glisse vers le haut tombe sur la suppression. Elle
   demande confirmation, donc c'est rattrapable — mais faire dépendre la
   sécurité d'une boîte qu'on apprend à fermer sans lire n'est pas une
   réponse.

   40 px et 8 px d'écart : 48 px d'un centre à l'autre, ce qui est la mesure
   qui compte pour ne pas toucher le voisin. La colonne passe à 264 px, ce
   qu'on peut se permettre puisque le tableau défile dans sa boîte.

   BORNÉ EN LARGEUR, à 1366 : tous les téléphones et toutes les tablettes,
   iPad Pro couché compris. J'avais d'abord borné à 1024 ; le banc des huit
   écrans a montré que l'iPad Pro — une tablette qu'on ne touche qu'au doigt,
   et que des professeurs utilisent en classe — retombait alors sur les cibles
   de 32 px.

   Conséquence assumée : un portable de 1366 reçoit aussi les grandes cibles,
   et sa colonne passe de 208 à 264 px. C'est abordable depuis que le tableau
   défile dans sa boîte (règle ci-dessus) : plus rien ne déborde, quelle que
   soit la largeur. Entre un doigt qui rate « Supprimer l'élève » et 56 px de
   colonne sur un vieux portable, le choix est vite fait.

   Toujours pas de « pointer » : la largeur ne ment pas.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 1366px) {
  #tableEleves thead th:last-child,
  #tableEleves tbody td:last-child {
    width: 264px !important;
    min-width: 264px !important;
    max-width: 264px !important;
  }
  #tableEleves .action-buttons {
    grid-template-columns: repeat(5, 40px) !important;
    gap: 8px !important;
  }
  #tableEleves .action-buttons .act-btn,
  #tableEleves .action-buttons button {
    width: 40px !important;
    min-width: 40px !important;
    height: 40px !important;
    font-size: 17px !important;
  }
  /* La case du nom se saisit aussi au doigt : même exigence de hauteur. */
  #tableEleves .nom-lecture,
  #tableEleves .nom-champ { min-height: 34px; padding: 7px 8px; }
}

/* ═══════════ TÉLÉPHONE — debout (≤ 690) OU couché (hauteur ≤ 500) ════════ */
@media (max-width: 690px), (max-height: 500px) and (max-width: 950px) {

  /* ── L'en-tête prenait un tiers de l'écran pour dire son nom ─────────── */
  /* Mesuré : l'en-tête occupait 390 des 780 points du premier écran — la
     moitié, pour un titre et une phrase de présentation. Le titre tient
     désormais sur une ligne, et la phrase disparaît : elle s'adresse à
     quelqu'un qui découvre la plateforme, pas à un professeur qui l'ouvre
     entre deux salles. */
  .glass.p-8 { padding: 10px 12px !important; margin-bottom: 10px !important; }
  #dashboardTitle {
    font-size: 17px !important; gap: 7px !important; line-height: 1.2 !important;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #dashboardTitle svg { width: 22px !important; height: 22px !important; }
  #dashboardSubtitle { display: none !important; }
  .max-w-7xl { padding-left: 10px; padding-right: 10px; }

  /* ── LA GRILLE DISPARAÎT — 21/09/2026 ─────────────────────────────────
     Elle restait ici comme « index complet », et c'était défendable tant que
     la barre basse n'offrait que quatre raccourcis. Mais deux chemins vers le
     même outil, c'est deux endroits où chercher : on faisait défiler dix-neuf
     tuiles alors qu'une barre attendait en bas, ou l'inverse.

     La barre porte maintenant TOUT et glisse. La grille n'a donc plus de
     rôle ici — sur écran large elle reprend sa place entière, où elle en a
     un : on y voit tout d'un coup d'œil, ce qu'une barre ne fera jamais.

     Elle reste dans le document, masquée : c'est elle que mobile-nav.js lit
     pour construire la barre. La retirer du DOM viderait la navigation. */
  #dashboardGrid { display: none !important; }

  /* ── Les panneaux ─────────────────────────────────────────────────────── */
  .tab-content { padding-left: 0 !important; padding-right: 0 !important; }
  .tab-content .grid { grid-template-columns: 1fr !important; }
  .tab-content .flex { flex-wrap: wrap; }

  /* ── La barre basse occupe le bas de l'écran : le contenu se termine
        au-dessus, jamais dessous. La barre de gestes de l'iPhone est prise
        en compte par env(safe-area-inset-bottom) dans .pmb-barre. ──────── */
  body.pmb-actif { padding-bottom: 76px; }
}

/* ══════════════════ 691–839 : PLIABLE DÉPLIÉ, PRESQUE CARRÉ ══════════════ */
@media (min-width: 691px) and (max-width: 839px) {
  /* 690 points ne suffisent pas aux cinq colonnes du bureau, et sont
     largement de trop pour une seule. Trois. */
  #dashboardGrid {
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    gap: 10px !important;
  }
  #dashboardGrid .dashboard-card { padding: 14px 10px !important; }
  #dashboardGrid .dashboard-icon {
    width: 38px !important; height: 38px !important; margin: 0 auto 8px !important;
  }
  #dashboardGrid .dashboard-label { font-size: 12.5px !important; }
  .glass.p-8 { padding: 20px !important; }
  #dashboardTitle { font-size: 26px !important; }
}

/* ═══════════════════════ LA BARRE BASSE (≤ 690) ══════════════════════════
   Construite par apps/teacher/core/mobile-nav.js à partir des cartes
   RÉELLEMENT rendues : elle ne peut donc pas proposer un outil que le
   forfait ou les droits ferment.
   ═════════════════════════════════════════════════════════════════════════ */
.pmb-barre {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 900;
  display: none;
  background: rgba(255, 255, 255, .97);
  border-top: 1px solid #e2e8f0;
  box-shadow: 0 -2px 14px rgba(15, 23, 42, .09);
  padding: 5px 2px calc(5px + env(safe-area-inset-bottom, 0px));
  backdrop-filter: blur(8px);

  /* ── ELLE GLISSE — 21/09/2026 ─────────────────────────────────────────
     Elle portait quatre outils et un bouton « Plus » ; elle les porte tous.
     `nowrap` est ce qui compte : sans lui, dix-neuf boutons passeraient à la
     ligne et la barre mangerait le tiers de l'écran.

     `overscroll-behavior-x: contain` n'est pas un détail de confort. Sans
     lui, arriver au bout de la barre en glissant continue le geste dans le
     navigateur : sur Android c'est le retour arrière, et le professeur
     quitte la page en cherchant son dernier outil.

     Aucun `scroll-snap` : une barre qui se recale sous le doigt pendant
     qu'on la parcourt donne l'impression de lutter contre elle. */
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
/* La barre d'ascenseur mangerait six points de hauteur sur un écran qui n'en
   a pas. Le glissement reste possible — c'est le seul geste au doigt. */
.pmb-barre::-webkit-scrollbar { display: none; }
@media (max-width: 690px), (max-height: 500px) and (max-width: 950px) {
  .pmb-barre { display: flex; }
}

.pmb-dest {
  /* ILS NE SE PARTAGENT PLUS L'ÉCRAN, ils se suivent. La largeur est choisie
     pour qu'un bouton DÉPASSE toujours du bord : c'est cette moitié de bouton
     coupée qui annonce qu'il y en a d'autres derrière. Un dégradé de bord
     aurait fait le même travail en effaçant aussi le fond de la barre, qui
     laisserait alors voir la page au travers. */
  flex: 0 0 auto;
  width: 21.5vw; min-width: 64px; max-width: 86px;
  display: flex !important; flex-direction: column; align-items: center;
  justify-content: center; gap: 3px;
  background: transparent !important; border: 0 !important;
  border-radius: 10px !important;
  padding: 9px 2px 7px !important;   /* cible ≥ 48 points, debout */
  width: auto !important; height: auto !important;
  color: #64748b !important;
  font: inherit; cursor: pointer; position: relative;
  -webkit-tap-highlight-color: transparent;
}
.pmb-dest svg,
.pmb-dest .dashboard-icon {
  width: 22px !important; height: 22px !important; margin: 0 !important;
  color: currentColor !important; flex-shrink: 0;
}
.pmb-dest span {
  font-size: 10px; font-weight: 600; line-height: 1.1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%; color: currentColor;
}
.pmb-dest[aria-current="true"] {
  color: #4f46e5 !important;
  background: rgba(79, 70, 229, .09) !important;
}
.pmb-dest:focus-visible { outline: 2px solid #4f46e5; outline-offset: -2px; }
/* 01/10/2026 — la mention « IA » des cartes, reportée sur la barre du
   téléphone : même dégradé que la pastille (blanc ≥ 5,1:1 sur ses deux
   teintes), posée sur le coin de l'icône. */
.pmb-dest .pmb-ia {
  position: absolute; top: 4px; left: calc(50% + 6px);
  padding: 1px 4px; border-radius: 6px; pointer-events: none;
  background: linear-gradient(135deg, #7c3aed, #2563eb) !important;
  color: #fff !important; font-size: 9px; font-weight: 800; font-style: normal;
  letter-spacing: .03em; line-height: 1.2;
}

/* ══════════════════════ TÉLÉPHONE COUCHÉ (PAYSAGE) ═══════════════════════
   844 × 390 : la largeur ne manque pas, la hauteur si. Tout ce qui est
   horizontal peut s'étaler ; tout ce qui est vertical doit maigrir.
   ═════════════════════════════════════════════════════════════════════════ */
@media (orientation: landscape) and (max-height: 500px) and (max-width: 950px) {
  /* L'en-tête : deux lignes de titre valent 90 points sur 390. Une suffit. */
  .glass.p-8 { padding: 8px 12px !important; margin-bottom: 8px !important; }
  #dashboardTitle { font-size: 16px !important; }
  #dashboardTitle svg { width: 22px !important; height: 22px !important; }
  #dashboardSubtitle { display: none !important; }

  /* La barre : icônes seules. Un libellé de 10 points coûte 14 points de
     hauteur sur les 390 disponibles — c'est 3,5 % de l'écran pour répéter ce
     que l'icône dit déjà. Le nom complet reste dans aria-label et title. */
  .pmb-barre { padding: 3px 2px calc(3px + env(safe-area-inset-bottom, 0px)); }
  .pmb-dest { padding: 10px 2px !important; min-height: 44px; }
  .pmb-dest span { display: none; }
  .pmb-dest svg, .pmb-dest .dashboard-icon {
    width: 24px !important; height: 24px !important;
  }
  body.pmb-actif { padding-bottom: 52px; }

  /* Couché, les libellés tombent et les boutons se resserrent : on en voit
     plus d'un coup, et le glissement sert moins. */
  .pmb-dest { width: 13vw; min-width: 58px; max-width: 76px; }
}

/* ══════════════════════════ LA CHARNIÈRE ═════════════════════════════════
   Un pliable expose la position de son pli. Quand il y a deux segments côte
   à côte, la gouttière de la grille s'aligne dessus plutôt que de laisser
   une carte tomber dans le creux.

   Aucun appareil non pliable ne lit cette règle : elle ne coûte rien aux
   autres. La propriété est encore préfixée sur certains moteurs, d'où les
   deux écritures.
   ═════════════════════════════════════════════════════════════════════════ */
@media (horizontal-viewport-segments: 2) {
  #dashboardGrid {
    grid-template-columns:
      calc(env(viewport-segment-width 0 0) - 20px)
      calc(env(viewport-segment-width 1 0) - 20px) !important;
    column-gap: calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0)) !important;
  }
}
@media (spanning: single-fold-vertical) {
  #dashboardGrid {
    grid-template-columns: calc(env(fold-left) - 20px) 1fr !important;
    column-gap: env(fold-width) !important;
  }
}

/* ══════════════════════════ CONFORT ══════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .pmb-dest { transition: none !important; }
  /* Le recadrage de la barre sur l'outil ouvert se fait alors d'un coup :
     mobile-nav.js lit la même préférence avant d'animer. */
  .pmb-barre { scroll-behavior: auto !important; }
}
@media print {
  .pmb-barre { display: none !important; }
}
