/* =========================================================================
   rotatestudy · espace client (pages rendues par le Worker : src/pages.js page())
   Chargee apres ds/tokens.css, ds/base.css et ds/components.css (ni site.css ni motion.css). Lit les jetons, jamais
   une couleur, une police, un rayon ou une courbe en dur ; espacements multiples de 8. Boutons, bascule de theme,
   marque, champs, onglets : ds/components.css, pas redefinis ici.
   Plan 2 de la refonte 2026-10. Tache 1 : la coquille (1) et des regles de transition (2, 3) pour les corps d'avant ;
   les taches 2 a 7 les ont remplaces, la tache 8 a garde en section 2 ce qu'un ecran lit encore (lecteur nomme).
   ========================================================================= */

/* ---- 1. Coquille : barre, colonne, pied ----
   <header class="top"><a class="brand" href="/">…</a> <button class="theme-btn">…</button> {lienHaut}</header>
   <main>…</main> <footer class="app-foot"><nav><a href="/terms.html">Terms</a>…</nav></footer>
   La barre n'est pas collante : l'espace client est une suite d'ecrans courts, rien ne la recouvre.
   :root:not(.reader-on) : ni la colonne du corps ni l'alias --text ne touchent une fiche du lecteur (section 7). */
:root:not(.reader-on) body{display:flex;flex-direction:column;min-height:100vh;min-height:100dvh}
header.top{display:flex;align-items:center;gap:var(--sp2);width:100%;max-width:calc(var(--col) + 2 * var(--pad));
  height:var(--nav-h);margin-inline:auto;padding-inline:var(--pad)}
header.top .brand{margin-right:auto}
header.top a.l{color:var(--dim);font-size:var(--s1);white-space:nowrap;text-decoration:none;
  transition:color var(--t-hover) var(--ease)}
header.top a.l:hover{color:var(--ink)}
main{flex:1 0 auto;width:100%;max-width:calc(var(--col) + 2 * var(--pad));margin-inline:auto;
  padding:var(--sp3) var(--pad) var(--sp7)}
.app-foot{border-top:1px solid var(--line)}
.app-foot nav{display:flex;flex-wrap:wrap;gap:var(--sp1) var(--sp3);max-width:calc(var(--col) + 2 * var(--pad));
  margin-inline:auto;padding:var(--sp3) var(--pad)}
.app-foot a{color:var(--dim);font-size:var(--s1);text-decoration:none;transition:color var(--t-hover) var(--ease)}
.app-foot a:hover{color:var(--ink)}

/* ---- 2. Regles communes gardees de la transition (nettoyee a la tache 8 : seul reste ce qu'un ecran lit encore) ----
   Retire a la tache 8 (plus aucun lecteur, verifie dans Chrome en retirant chaque regle : styles calcules identiques) :
   main h1, main label (sa marge s'ajoutait au gap des .field ; la colonne calme et /review l'annulaient a la main),
   le champ generique main :where(input, select, textarea), main textarea, form+p. Les cartes, la boite des messages et
   les alias --card, --faint, --fc, --text etaient partis aux taches 3, 4 et 7. */
/* Paragraphes des corps de .espace (e-mail sous le titre, ligne des appareils de /account/notes) ; quiz.css remet la
   marge a zero dans #quiz avec le meme poids. */
main p{margin:0 0 var(--sp2)}
/* Note discrete : ligne des appareils de /account/notes (src/pages.js pageNotes) ; quiz.js et communaute.js ont la leur
   (#quiz .faint dans quiz.css). */
.faint{color:var(--dim);font-size:var(--s1)}

/* Bouton Extend des lignes de reste (src/pages.js ligneReste, matiereFinie) : petit, contour. */
.btn.s{min-height:40px;padding:0 var(--sp2);background:transparent;color:var(--ink);font-size:var(--s1);
  box-shadow:inset 0 0 0 1px var(--line)}
.btn.s:not(:disabled):not(.inert):hover{background:var(--surface-2);box-shadow:inset 0 0 0 1px var(--dim)}
/* Boutons des formules (src/pages.js sectionFormules, #formules) : contour bleu, une fois ouverts par achat.js (fermes,
   ils prennent l'aspect .inert du ds/). */
.btn.p{background:transparent;color:var(--blue-ink);box-shadow:inset 0 0 0 1px var(--blue-ink)}
.btn.p:not(:disabled):not(.inert):hover{background:var(--surface-2)}

/* Lignes de reste (« Questions: 54 days left · until … ») : tableau de bord, /account/plan.
   Classes lues par les tests (contrat du plan 2). */
.reste{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp1) var(--sp2);margin:var(--sp2) 0 0;font-size:var(--s1);
  font-variant-numeric:tabular-nums}
.reste.alerte{color:var(--orange-ink)}
.reste .btn.s{min-height:32px}


/* ---- 3. (Tache 1 : transition de l'ancienne lib/quiz.css en theme clair ; retiree a la tache 4, quiz.css lit les jetons.) */

/* ---- 4. Connexion, « Check your inbox », fiche profil (tache 2) : une colonne calme ----
   <section class="calme"><h1>Your account</h1> <a class="btn ghost">G Continue with Google</a> <p class="ou"><span>or</span></p>
   <form><div class="field">…</div> <button class="btn">…</button></form></section>
   420 px au centre, posee sur le fond (pas de carte) ; champs .field et boutons .btn du ds/, a toute la largeur.
   Le lien « Not you? Sign out » est un bouton (formulaire POST) qui se lit comme un lien : --blue-ink, AA aux deux themes. */
.calme{display:flex;flex-direction:column;gap:var(--sp3);max-width:420px;margin-inline:auto;padding-top:var(--sp6)}
.calme h1{margin:0;font-size:var(--s5);line-height:1.04;letter-spacing:-.035em}
.calme p{margin:0}
.calme b{overflow-wrap:anywhere}
.calme form{display:flex;flex-direction:column;gap:var(--sp3)}
.calme .field>label{text-wrap:balance}
.calme .btn{width:100%}
.calme .ou{display:flex;align-items:center;gap:var(--sp2);color:var(--dim);font-size:var(--s1)}
.calme .ou::before,.calme .ou::after{content:"";flex:1;height:1px;background:var(--line)}
.calme .dev{padding:var(--sp1) var(--sp2);border:1px dashed var(--line-strong);border-radius:var(--r-paper);word-break:break-all}
.calme .qui{flex-direction:row;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:0 var(--sp2);
  padding-top:var(--sp2);border-top:1px solid var(--line)}
.calme .qui span{overflow-wrap:anywhere}
.calme .lien{padding:0;border:0;background:none;color:var(--blue-ink);font:inherit;cursor:pointer;
  text-underline-offset:.18em;transition:color var(--t-hover) var(--ease)}
.calme .lien:hover{text-decoration:underline;text-decoration-thickness:1px}
@media (max-width:480px){
  .calme{padding-top:var(--sp4)}
}

/* Message de service (paiement recu) : une surface et un filet, rien de plus. Pas .note, reservee a « Remember » et
   « Exam trap » ; jamais de barre a gauche. */
.notice{margin:0;padding:var(--sp2) var(--sp3);border-radius:var(--r-screen);background:var(--surface);
  box-shadow:inset 0 0 0 1px var(--line)}
/* Compte sans rien (19/10/2026) : la phrase et « Sign out » en bouton-lien, sur la meme surface. */
.vide-aide{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 var(--sp2)}
.vide-aide p{margin:0}
.vide-aide form{display:contents}
.vide-aide .lien{padding:0;border:0;background:none;color:var(--blue-ink);font:inherit;cursor:pointer;text-underline-offset:.18em}
.vide-aide .lien:hover{text-decoration:underline;text-decoration-thickness:1px}

/* ---- 5. Tableau de bord (/account) et bibliotheque des fiches (/account/notes) (tache 3) ----
   <header class="top"> … <nav class="app-nav"><a href="/account" aria-current="page">Dashboard</a> … <form>Sign out</form></nav>
   <div class="espace"><div class="tete"><h1>…</h1><p class="small">e-mail</p>.reste</div>
     <section id="start" class="lanceur"> <div id="dashboard"> <section class="mes-notes"><ol class="lignes"> <section id="formules"></div>
   Une colonne, des sections separees par un filet au-dessus (l'encadre de la charte), aucune carte. Les fiches sont des
   lignes de matiere (.subject-row du ds/, section 6) dans une liste a filets, comme les listes du site public. */

/* Menu de l'espace client : a droite de la marque, avant la bascule de theme ; l'entree courante en encre pleine,
   soulignee. Sous 760 px il quitte la barre haute pour la barre basse (.app-nav.bas, sous-section « Lot 1 » plus bas). */
header.top{flex-wrap:wrap;height:auto;min-height:var(--nav-h)}
header.top:has(.app-nav) .theme-btn{order:2}
.app-nav{order:1;display:flex;flex-wrap:wrap;align-items:center;gap:0 var(--sp3)}
.app-nav form{display:contents}
.app-nav :is(a,button){display:inline-flex;align-items:center;min-height:40px;padding:0;border:0;background:none;
  color:var(--dim);font:500 var(--s1)/1 var(--fb);white-space:nowrap;text-decoration:none;cursor:pointer;
  text-underline-offset:.5em;transition:color var(--t-hover) var(--ease)}
.app-nav :is(a,button):hover{color:var(--ink)}
.app-nav [aria-current="page"]{color:var(--ink);text-decoration:underline;text-decoration-thickness:1px}

.espace{display:flex;flex-direction:column;gap:var(--sp5);padding-top:var(--sp4)}
.espace .tete{display:flex;flex-direction:column;gap:var(--sp1)}
.espace .tete h1{margin:0;font-size:var(--s5);line-height:1.04;letter-spacing:-.035em}
.espace .tete .small{overflow-wrap:anywhere}
.espace .tete .reste{margin-top:var(--sp1)}
.espace h2{margin:0;font-size:var(--s4);line-height:1.15;letter-spacing:-.02em}
.espace>section{display:flex;flex-direction:column;gap:var(--sp3);padding-top:var(--sp3);border-top:1px solid var(--line)}
#dashboard:empty{display:none}
/* Liste de fiches dans une section du tableau de bord : pas de filet sous la derniere ligne, la section suivante ouvre
   deja sur le sien (sinon deux filets a 48 px l'un de l'autre). */
.espace>section .lignes>li:last-child{border-bottom:0}

/* Offre (banque fermee) : une phrase et un bouton ; le bouton seul quand la date de fin vient d'etre dite. */
.offre{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp2) var(--sp3);margin:0}
.offre p{flex:1 1 320px;margin:0;color:var(--dim);font-variant-numeric:tabular-nums}

/* Lanceur : matiere, nombre de questions, Start, sur une ligne a l'ordinateur ; sur telephone, la matiere sur toute la
   largeur (son libelle entier), puis le nombre et Start. */
.lanceur form{display:grid;grid-template-columns:minmax(0,1fr) 160px auto;gap:var(--sp2);align-items:end}
.lanceur select{font-variant-numeric:tabular-nums}
@media (max-width:760px){
  .lanceur form{grid-template-columns:112px minmax(0,1fr)}
  .lanceur form .field:first-child{grid-column:1/-1}
}

/* Lignes de fiches : code, nom (et sa ligne de reste propre), puis Read et PDF par langue, ou Buy. Alignees sur la ligne
   de base : le code, la premiere ligne du nom et les libelles des boutons tombent sur la meme ligne, a un ou deux etages. */
.bloc-tete{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:var(--sp1) var(--sp3)}
.plus{font-size:var(--s1)}
.plus:hover{text-decoration:underline;text-decoration-thickness:1px}
.lignes{margin:0;padding:0;list-style:none;border-top:1px solid var(--line)}
.lignes .subject-row{grid-template-columns:64px minmax(0,1fr) auto;grid-template-rows:auto;align-items:baseline;min-height:0;
  padding:var(--sp2) 0;border-bottom:1px solid var(--line)}
.lignes .subject-row .code{grid-column:1;grid-row:1}
.lignes .subject-row:hover .name{color:var(--ink)}
.lignes .subject-row.libre .name{color:var(--dim)}
.lignes .nom{display:flex;flex-direction:column;gap:var(--sp1);min-width:0}
.lignes .reste{margin:0;color:var(--dim)}
.lignes .reste.alerte{color:var(--orange-ink)}
.lignes .ops{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--sp1) var(--sp3)}
.lignes .op{display:flex;align-items:center;gap:var(--sp1)}
.lignes .lib{color:var(--dim);font-size:var(--s1)}
@media (max-width:760px){
  .lignes .subject-row{grid-template-columns:40px minmax(0,1fr);row-gap:var(--sp2)}
  .lignes .ops{grid-column:2;justify-content:flex-start}
  /* Matiere a acheter : Buy reste sur la ligne du nom, a droite. */
  .lignes .subject-row.libre{grid-template-columns:40px minmax(0,1fr) auto}
  .lignes .subject-row.libre .ops{grid-column:3;grid-row:1}
}

/* Formules (#formules, ancre des mails de rappel) : quatre durees, puis une matiere au choix. */
.formules .prix{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:var(--sp1)}
.formules .une{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp1) var(--sp2)}
.formules .une span{flex:1 1 100%;color:var(--dim);font-size:var(--s1);font-variant-numeric:tabular-nums}
/* Select de la formule d'une matiere (#fm-sel) : seul champ de l'espace client hors d'un .field ; meme aspect que
   les champs .field du ds/ (contour --line-strong, anneau de focus). */
main .formules select{flex:1 1 160px;width:auto;min-width:0;min-height:48px;border:0;
  border-radius:var(--r-pill);color:var(--ink);box-shadow:inset 0 0 0 1px var(--line-strong);
  transition:box-shadow var(--t-hover) var(--ease)}
main .formules select:hover{box-shadow:inset 0 0 0 1px var(--ink)}
main .formules select:focus-visible{outline:2px solid var(--focus);outline-offset:2px;box-shadow:inset 0 0 0 1px var(--focus)}
.formules .btn{font-variant-numeric:tabular-nums}

/* Tableau de bord, GO 1 (cahier du 19/10/2026, planches de ds/design.html #dashboard) : une colonne, des sections a filet
   au-dessus dans l'ordre de etatCompte(), les memes elements aux memes places d'un etat a l'autre. Les phrases posees
   directement dans une nouvelle section (phrase de Your first step) n'ont pas de marge : le gap de la
   section les espace. La route vide de l'etat « fiches » (« Your results will appear here. ») : p.vide, en gris. */
:is(.today,.faiblesses,.premier-pas,.mocks)>p,.espace>section>p.vide{margin:0}
.espace>section>p.vide{color:var(--dim)}

/* Tete : la ligne d'acces a gauche, la prochaine epreuve a droite ; dessous sur telephone (retour a la ligne). */
.espace .tete .acces{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:var(--sp1) var(--sp3)}
.espace .tete .acces .reste{margin:0}
.prochain{margin:0;font-size:var(--s1);color:var(--ink);font-variant-numeric:tabular-nums}

/* Today : une ligne par matiere a date prevue : code, nom, quota, barre fine du jour (.meter, ds/ 6c), Start. La colonne
   du bouton reste la meme sans bouton (« Done for today ») : barres et quotas tombent a l'aplomb, lignes de meme hauteur.
   Telephone : le nom, le quota puis la barre l'un sous l'autre, Start a droite. Dessous, les chiffres du jour
   (.figures, ds/ 10b). */
.today .subject-row{grid-template-columns:64px minmax(0,1fr) 176px 160px 96px;align-items:center;
  min-height:calc(48px + 2 * var(--sp2))}
.today .quota{text-align:right;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.today .quota.fait{color:var(--green-ink)}
.today .subject-row .btn{justify-self:end}
@media (max-width:760px){
  .today .subject-row{grid-template-columns:40px minmax(0,1fr) 96px;row-gap:var(--sp1);min-height:0}
  .today .quota{grid-column:2;grid-row:2;text-align:left}
  .today .meter{grid-column:2;grid-row:3}
  .today .subject-row .btn{grid-column:3;grid-row:1/4}
}

/* Dates d'examen (GO 1 : dans Today, repliees sous les lignes du jour ; GO 2 : Your exams). Le titre du repli suit la FAQ
   de l'accueil (+ et moins). Une ligne par matiere (code, nom, date), les jours de repos en sept cases (.case, section 8),
   Save en contour : le bouton plein de la section reste Start. */
.dates{border-top:1px solid var(--line)}
.dates>summary{display:flex;align-items:center;justify-content:space-between;gap:var(--sp2);min-height:56px;list-style:none;
  font:600 var(--s2)/1.3 var(--fd);letter-spacing:-.015em;color:var(--ink);cursor:pointer;transition:color var(--t-hover) var(--ease)}
.dates>summary::-webkit-details-marker{display:none}
.dates>summary::after{content:"+";flex:none;width:1em;text-align:center;font-weight:400;color:var(--dim)}
.dates[open]>summary::after{content:"\2212"}
.dates>summary:hover{color:var(--blue-ink)}
.dates form{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp3);padding-bottom:var(--sp1)}
.dates .lignes{align-self:stretch}
.dates .lignes .field{grid-template-columns:minmax(0,1fr) 200px;align-items:center;gap:var(--sp2);padding:var(--sp1) 0;
  border-bottom:1px solid var(--line)}
.dates .lignes .field>label{display:flex;align-items:baseline;gap:var(--sp2);font:600 var(--s2)/1.25 var(--fd);letter-spacing:-.015em}
.dates .lignes .code{flex:none;width:64px;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.repos{min-width:0;margin:0;padding:0;border:0}
.repos legend{margin:0 0 var(--sp1);padding:0;font:500 var(--s1)/1.3 var(--fb);color:var(--ink)}
.repos>div{display:flex;flex-wrap:wrap;gap:0 var(--sp3)}
.repos .case{align-items:center;min-height:40px}
@media (max-width:760px){
  .dates .lignes .field{grid-template-columns:minmax(0,1fr) 168px}
  .dates .lignes .code{width:40px}
}

/* Your route : la route du site public (ol.route, .subject-row sans --p) en liste a filets. La colonne de la balise
   s'elargit : le RS-1 vu de dessus (cap 090, taille de la route de l'accueil, components.css 18) est pose a gauche de la
   balise de la prochaine epreuve (li.next), le nez a 3 px d'elle, sans animation. Balise reussie : .wp.passed (ds/ 6a).
   Cellules : vues (« 297 / 417 seen »), dernier examen blanc, etat (« Passed June 2026 » en vert, « Exam 22 Oct · D-3 ») ;
   Practise a droite. Le nom n'est pas un lien ici : pas de voile sur la ligne (.route .name::after). Chaque cellule a sa
   place explicite (la balise, hors grille, laisse la premiere colonne vide) ; jamais de grid-row sur la balise ni sur
   l'avion : poses en absolu, ils se placeraient dans la rangee et non plus dans la ligne. La liste ne reprend pas les
   rangees partagees de la route de l'accueil (subgrid de .route) : hors de .fpl-route, Chrome y bornait chaque ligne a
   une rangee et la deuxieme ligne du telephone debordait sur la matiere suivante. Telephone (comme la route de l'accueil) :
   code, nom et Practise sur la premiere ligne, les cellules dessous : vues et examen blanc cote a cote (a l'aplomb
   d'une ligne a l'autre), l'etat sous elles. */
.bloc-tete .compte{margin:0;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.route-dash{grid-template-rows:none}
.route-dash .subject-row{grid-template-columns:72px minmax(48px,max-content) minmax(0,1fr) 128px 112px 200px auto;grid-template-rows:auto;
  align-items:center;min-height:calc(40px + 2 * var(--sp2))}
.route-dash .subject-row .code{grid-column:2;grid-row:1}
.route-dash .name{grid-column:3;grid-row:1}
.route-dash .name::after{content:none}
.route-dash .cellules{display:contents}
.route-dash :is(.qs,.mock,.etat){grid-row:1;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.route-dash .qs{grid-column:4;text-align:right}
.route-dash .mock{grid-column:5;text-align:right}
.route-dash .etat{grid-column:6;padding-left:var(--sp2);color:var(--ink)}
.route-dash .etat.ok{color:var(--green-ink)}
.route-dash .btn{grid-column:7;grid-row:1;justify-self:end}
.route-dash .wp{left:54px;top:36px}
.route-dash .rs1{--rs1-u:2.5px;--hdg:90deg;left:23px;top:36px}
@media (max-width:760px){
  .route-dash .subject-row{grid-template-columns:56px minmax(40px,max-content) minmax(0,1fr) auto;row-gap:var(--sp1)}
  .route-dash .cellules{display:grid;grid-template-columns:112px minmax(0,1fr);column-gap:var(--sp2);grid-column:2/-1;grid-row:2}
  .route-dash .btn{grid-column:4}
  .route-dash :is(.qs,.mock,.etat){text-align:left;padding:0;line-height:20px}
  .route-dash .qs{grid-column:1;justify-self:start}
  .route-dash .mock{grid-column:2}
  .route-dash .etat{grid-column:1/-1;grid-row:2}
  .route-dash .etat:empty{display:none}
  .route-dash .wp{left:48px}
  .route-dash .rs1{--rs1-u:2.2px;left:20px}
}

/* Where you lose points : le selecteur de matiere, puis une ligne par sous-chapitre, du plus faible au plus solide : code
   court, nom (chapitres de la banque publiee), barre des bonnes reponses, « 62 % · 21 answers » ; les sous-chapitres sans
   reponse en fin de liste (« not started »). Puis Practise my weak spots. Telephone : la barre sous le nom. */
.faiblesses>.field{max-width:360px}
.faiblesses .subject-row{grid-template-columns:64px minmax(0,1fr) 200px 152px;align-items:center}
.faiblesses .pct{text-align:right;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.faiblesses>.btn{align-self:flex-start}
@media (max-width:760px){
  .faiblesses .subject-row{grid-template-columns:40px minmax(0,1fr) auto;row-gap:var(--sp1)}
  .faiblesses .name{grid-column:2}
  .faiblesses .meter{grid-column:2/-1;grid-row:2}
}

/* Page reelle (tache 6), ce que les planches ne montrent pas : plusieurs lignes d'acces (matieres datees, a vie) l'une
   sous l'autre ; Start par defaut sans objectif (phrase a gauche, bouton a droite) ; date d'examen passee (libelle et
   message orange sous le champ, sur toute la ligne) ; « Loading… » en gris ; bouton des points faibles desactive tant que
   lib/dashboard.js ne l'a pas remplace ; liste des examens blancs vide = aucun filet. */
.espace .tete .acces-lignes{display:flex;flex-direction:column;gap:var(--sp1)}
.today .defaut{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--sp2) var(--sp3);margin:0}
.dates .lignes .field.alerte>label{color:var(--orange-ink)}
.dates .lignes .field>.field-msg{grid-column:1/-1;margin:0}
.faiblesses [data-loading] .name{color:var(--dim);font-weight:400}
.faiblesses>.btn[aria-disabled="true"]{cursor:default;opacity:.45;pointer-events:none}
.mocks .lignes:empty{display:none}

/* Practise : Subject, Questions, Filter (les compteurs suivent la matiere), Start sur une ligne ; en essai (.essai), le
   lanceur d'avant, sans filtre. Telephone : la matiere, puis le nombre et le filtre, puis Start. */
.lanceur .filtre{grid-template-columns:minmax(0,1fr) 120px minmax(0,1fr) auto}
@media (max-width:760px){
  .lanceur .filtre{grid-template-columns:112px minmax(0,1fr)}
  .lanceur .filtre .btn{grid-column:1/-1;justify-self:start}
}

/* Mock exams : les cinq derniers examens blancs, toutes matieres : date, matiere, score, pourcentage (vert a partir de
   75 %, orange dessous), duree. Telephone : la matiere seule sur la premiere ligne. */
.mocks .subject-row{grid-template-columns:112px minmax(0,1fr) 80px 64px 72px}
.mocks :is(time,.score,.pct,.duree){font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.mocks :is(.score,.pct,.duree){text-align:right}
.mocks .matiere{font:600 var(--s2)/1.25 var(--fd);letter-spacing:-.015em;color:var(--ink)}
.mocks .matiere .code{margin-right:var(--sp1)}
.mocks .pct{font-weight:600}
.mocks .pct.ok{color:var(--green-ink)}
.mocks .pct.ko{color:var(--orange-ink)}
@media (max-width:760px){
  .mocks .subject-row{grid-template-columns:minmax(0,1fr) auto auto auto;gap:var(--sp1) var(--sp2)}
  .mocks .matiere{grid-column:1/-1;grid-row:1}
  .mocks time{grid-row:2}
}

/* Your first step (compte sans rien) : la phrase, puis la matiere et Start sur une ligne, en essai ; sur telephone, Start
   sous la matiere (son libelle entier reste lisible). */
.premier-pas>p{color:var(--dim)}
.premier-pas form{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--sp2);align-items:end;max-width:640px}
@media (max-width:760px){
  .premier-pas form{grid-template-columns:minmax(0,1fr)}
  .premier-pas .btn{justify-self:start}
}

/* Tableau de bord, GO 2 (cahier 4.0, 4.3, 4.7, 4.8, 4.13 ; planches de ds/design.html #dashboard2, tache 0). Meme grammaire
   que le GO 1 : sections a filet au-dessus, listes a filets, chiffres en grand (.figures), un seul bouton plein par section
   (les autres en contour, la suppression en texte), vert = reussi, orange = a revoir. Les memes elements aux memes places
   d'un ecran a l'autre : un sous-bloc titre a la mesure du repli « Exam dates », une liste a filets, puis l'action. */

/* Sous-bloc d'une section (I sat an exam, Recorded exams, Your tests, Your reports) : un filet, un titre sur une ligne de
   56 px comme le repli « Exam dates » (meme police), puis son contenu. Une liste qui suit garde son filet du haut. */
.sous{display:flex;flex-direction:column;gap:var(--sp2);border-top:1px solid var(--line)}
.sous-t{display:flex;align-items:center;min-height:56px;margin:0;font:600 var(--s2)/1.3 var(--fd);letter-spacing:-.015em;color:var(--ink)}
.sous>p.vide{margin:0;color:var(--dim)}
/* Choix a deux ou quatre cases (Passed / Failed, Study / Exam, bonne reponse) : la grammaire des jours de repos, sur la
   hauteur d'un champ (48 px) pour tomber a l'aplomb des champs voisins. Mention « (optional) » en gris. */
.choix{min-width:0;margin:0;padding:0;border:0}
.choix legend{margin:0 0 var(--sp1);padding:0;font:500 var(--s1)/1.3 var(--fb);color:var(--ink)}
.choix>div{display:flex;flex-wrap:wrap;align-items:center;gap:0 var(--sp3);min-height:48px}
.choix .case{align-items:center;min-height:40px}
.opt{color:var(--dim);font-weight:400}
/* Suppression et annulation : un bouton texte, gris, souligne au survol (cible de 40 px de haut). Le lien d'action
   « Different at the exam? » en bleu. */
:is(.etat-examens,.tests,.vu-examen) .lien{display:inline-flex;align-items:center;min-height:40px;padding:0 var(--sp1);border:0;
  background:none;color:var(--dim);font:500 var(--s1)/1 var(--fb);cursor:pointer;text-underline-offset:.3em;
  transition:color var(--t-hover) var(--ease)}
:is(.etat-examens,.tests,.vu-examen) .lien:hover{color:var(--ink);text-decoration:underline;text-decoration-thickness:1px}
.vu-examen>.lien{padding:0;color:var(--blue-ink)}
.vu-examen>.lien:hover{color:var(--blue-ink)}
:is(.etat-examens,.tests,.feedback,.pg-exams) .field-hint{margin:0}

/* Test in progress (4.0) : premiere section, avant la tete. Une ligne : ce qui est en cours, la barre fine du test (muette,
   le texte dit « 12 of 40 »), Resume (plein) et Discard (contour, dialogue qzConfirm). Telephone : la phrase, la barre,
   puis les deux boutons, en haut de l'ecran. */
.espace>.en-cours{display:grid;grid-template-columns:minmax(0,1fr) 160px auto;align-items:center;gap:var(--sp2) var(--sp3)}
.en-cours .quoi{margin:0;color:var(--dim);font-variant-numeric:tabular-nums}
.en-cours .quoi b{font:600 var(--s2)/1.3 var(--fd);letter-spacing:-.015em;color:var(--ink)}
.en-cours .code{font:600 var(--s1)/1 var(--fd);color:var(--dim)}
.en-cours .actes{display:flex;flex-wrap:wrap;gap:var(--sp1)}
.en-cours .field-msg{grid-column:1/-1;margin:0}
/* Regions role="status" de My tests et Test in progress : toujours dans le DOM (annoncees quand le texte arrive), vides
   au repos ; vides, elles sortent du flux (ni ligne ni espacement), sans quitter l'arbre d'accessibilite. */
:is(.tests,.en-cours) .field-msg[data-msg]:empty{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%)}
@media (max-width:760px){
  .espace>.en-cours{grid-template-columns:minmax(0,1fr);gap:var(--sp2)}
}

/* Your route, GO 2 : tentatives restantes sous l'etat, en orange, seulement quand il en reste 1 ou 0 (« 1 attempt left »,
   « 0 attempts left ») ; a cote de l'etat sur telephone.
   Rappel sous la route (une date prevue passee depuis moins de 30 jours) : une ligne discrete, le lien en bleu. */
.route-dash .etat .tentatives{display:block;color:var(--orange-ink)}
.rappel{margin:0;font-size:var(--s1);color:var(--dim)}
.rappel a{color:var(--blue-ink);text-underline-offset:.3em}
.rappel a:hover{text-decoration:underline;text-decoration-thickness:1px}
@media (max-width:760px){
  .route-dash .etat .tentatives{display:inline;margin-left:var(--sp2)}
  /* Etat vide avant (aucune date prevue) : « 0 attempts left » reste a l'aplomb des vues, sans retrait. */
  .route-dash .etat .tentatives:first-child{margin-left:0}
}

/* Your exams (4.7) : les dates (repli du GO 1), « I sat an exam » (matiere, mois, resultat ; pays, score, Record), la liste
   des examens enregistres (mois, matiere, Passed en vert ou Failed en orange, score, pays, Delete), puis la fenetre de 18 mois
   en trois chiffres (.figures, sous un filet comme les sous-blocs) et les matieres a risque (1 ou 0 tentative restante,
   cahier 4.3). Fenetre depassee : chiffres et phrase en orange (.figure.alerte,
   ds/ 10b). Telephone : le formulaire en une colonne ; la matiere sur la premiere ligne de chaque examen. */
:is(.etat-examens,.pg-exams) .examen{display:grid;grid-template-columns:minmax(0,1fr) 200px minmax(0,1fr);gap:var(--sp2) var(--sp3);align-items:end}
:is(.etat-examens,.pg-exams) .examen .btn{justify-self:start}
:is(.examen,.contexte)>.field{min-width:0}
.examens .subject-row{grid-template-columns:96px minmax(0,1fr) 72px 56px 104px auto;align-items:center}
.examens :is(time,.res,.score,.pays){font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.examens .score{text-align:right}
:is(.examens,.liste-tests) .matiere{font:600 var(--s2)/1.25 var(--fd);letter-spacing:-.015em;color:var(--ink)}
:is(.examens,.liste-tests) .matiere .code{margin-right:var(--sp1)}
.examens .res{font-weight:600}
.examens .res.ok{color:var(--green-ink)}
.examens .res.ko{color:var(--orange-ink)}
.fenetre{display:flex;flex-direction:column;gap:var(--sp2);padding-top:var(--sp3);border-top:1px solid var(--line)}
.fenetre p{margin:0;font-size:var(--s1)}
.fenetre :is(.tentatives,.alerte-t){color:var(--orange-ink)}
/* Page reelle (tache 3 du GO 2), ce que les planches ne montrent pas : Delete est le bouton d'un petit formulaire
   (POST /api/examens/supprimer, sans JavaScript) qui ne compte pas dans la grille de la ligne ; dans « Exam dates », une
   matiere reussie qui garde une date prevue a sa ligne grisee, « Passed » dessous. */
.examens form{display:contents}
.dates .lignes .field.passee>label,.dates .lignes .field.passee input{color:var(--dim)}
.dates .lignes .field>.field-hint{grid-column:1/-1;margin:0}
/* Les treize matieres reussies : la fenetre laisse place a une ligne verte, sous le meme filet. */
/* « I passed » : un lien discret sous la liste, quand un examen est reussi (passed.html). */
.etat-examens .partage{margin:var(--sp1) 0 0}
.etat-examens .partage .lien{padding:0}
.etat-examens .toutes-reussies{margin:0;padding-top:var(--sp3);border-top:1px solid var(--line);font-size:var(--s1);color:var(--green-ink)}
@media (max-width:760px){
  :is(.etat-examens,.pg-exams) .examen{grid-template-columns:minmax(0,1fr)}
  .examens .subject-row{grid-template-columns:72px 56px 48px minmax(0,1fr) auto;gap:var(--sp1) var(--sp2)}
  .examens .matiere{grid-column:1/5;grid-row:1}
  .examens time{grid-column:1;grid-row:2}
  .examens .res{grid-column:2;grid-row:2}
  .examens .score{grid-column:3;grid-row:2;text-align:left}
  .examens .pays{grid-column:4;grid-row:2}
  .examens .lien{grid-column:5;grid-row:1/3}
}

/* My tests (4.8) : le composeur (matiere, sous-chapitres a cocher en liste a filets avec leur nombre de questions, puis
   filtre, nombre, ordre et mode sur une ligne, la repartition en petit, Compose a test), puis la liste des tests : date,
   matiere et chapitres, avancement (« 12 of 40 ») ou score (« 31 / 40 · 78 % », vert a partir de 75 %, orange dessous),
   actions en contour, Delete en texte. Telephone : la matiere, puis date et score, puis les actions. */
.tests .composeur{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp3)}
.composeur>:not(.btn){align-self:stretch}
.composeur>.field{max-width:360px}
.chapitres{min-width:0;margin:0;padding:0;border:0}
.chapitres legend{margin:0 0 var(--sp1);padding:0;font:500 var(--s1)/1.3 var(--fb);color:var(--ink)}
:is(.chapitres,.resultats) li{border-bottom:1px solid var(--line)}
.case.chap{display:grid;grid-template-columns:20px 48px minmax(0,1fr) auto;align-items:center;gap:var(--sp2);min-height:56px;padding:var(--sp1) 0}
:is(.case.chap,.case.trouve) .code{font:600 var(--s1)/1.3 var(--fd);color:var(--dim);font-variant-numeric:tabular-nums}
.case.chap .name{font:600 var(--s2)/1.25 var(--fd);letter-spacing:-.015em;color:var(--ink)}
.case.chap .nbq{font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
/* Finitions du 12/11/2026 : Filter, Questions, Order et Mode en pastilles (radios dans un fieldset), Order et Mode cote a cote ;
   les chapitres dans un repli ferme (.qz-chapitres), ouvert : la liste a filets d'avant. */
.composeur .reglages{display:flex;flex-wrap:wrap;gap:var(--sp3) var(--sp4)}
/* /practise/custom : le sous-menu porte deja le filet, la section du composeur n'en redessine pas un second. */
.espace>section#composer{padding-top:0;border-top:0}

/* Pastilles du lot 2 (lib/quiz.js, accueil : bouton aria-pressed) et du composeur Custom test (src/pages-tableau.js,
   sectionTests : label.qz-chip autour d'un radio .sr ; cochee et focus clavier lus par :has). Repli des chapitres :
   details.qz-chapitres. Venues de lib/quiz.css le 12/11/2026 pour servir les deux pages, memes jetons. */
fieldset.qz-champ-c{min-width:0;margin:0;padding:0;border:0}
fieldset.qz-champ-c>legend{margin:0 0 var(--sp1);padding:0;font:500 var(--s1)/1.3 var(--fb);color:var(--ink)}
.qz-chips{display:flex;flex-wrap:wrap;gap:var(--sp1)}
.qz-chip{position:relative;display:inline-flex;align-items:center;gap:var(--sp1);min-height:44px;padding:0 var(--sp2);border:0;border-radius:var(--r-pill);
  background:none;color:var(--dim);font:500 var(--s1)/1.2 var(--fb);text-align:left;cursor:pointer;
  box-shadow:inset 0 0 0 1px var(--line-strong);transition:box-shadow var(--t-hover) var(--ease),color var(--t-hover) var(--ease)}
.qz-chip:hover{color:var(--ink);box-shadow:inset 0 0 0 1px var(--ink)}
.qz-chip:is([aria-pressed="true"],:has(input:checked)){color:var(--ink);background:var(--surface-2);box-shadow:inset 0 0 0 2px var(--blue-ink)}
.qz-chip:has(input:focus-visible){outline:2px solid var(--focus);outline-offset:2px}
.qz-chip-n{color:var(--dim);font-variant-numeric:tabular-nums}
.qz-chip-n:empty{display:none}
.qz-chapitres>summary{display:inline-flex;align-items:center;min-height:44px;font:500 var(--s1)/1.3 var(--fb);color:var(--ink);cursor:pointer}
.qz-chapitres>summary{gap:var(--sp1);list-style:none}
.qz-chapitres>summary::-webkit-details-marker{display:none}
.qz-chapitres>summary::after{content:"+";flex:none;width:1em;text-align:center;font-weight:400;color:var(--dim)}
.qz-chapitres[open]>summary::after{content:"\2212"}
.qz-chapitres[open]>summary{margin-bottom:var(--sp1)}
.liste-tests .subject-row{grid-template-columns:112px minmax(0,1fr) 136px auto;align-items:center}
.liste-tests :is(time,.score){font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.liste-tests .score{text-align:right}
.liste-tests .en-cours-l .score{color:var(--ink)}
.liste-tests .chap{display:block;font:400 var(--s1)/1.6 var(--fb);letter-spacing:0;color:var(--dim)}
.liste-tests .pct{font-weight:600}
.liste-tests .pct.ok{color:var(--green-ink)}
.liste-tests .pct.ko{color:var(--orange-ink)}
.liste-tests .ops{align-items:center;gap:var(--sp1)}
@media (max-width:760px){
  .case.chap{grid-template-columns:20px 32px minmax(0,1fr);row-gap:0}
  .case.chap .nbq{grid-column:3}
  .tests .composeur,.composeur .reglages{gap:var(--sp2)}
  .liste-tests .subject-row{grid-template-columns:minmax(0,1fr) auto;gap:var(--sp1) var(--sp2)}
  .liste-tests .matiere{grid-column:1/-1;grid-row:1}
  .liste-tests time{grid-column:1;grid-row:2}
  .liste-tests .score{grid-column:2;grid-row:2}
  .liste-tests .ops{grid-column:1/-1;grid-row:3;justify-content:flex-start}
}

/* Feedback (/account/feedback, 4.13) : trois sections dans l'ordre du cahier. Seen at my exam : matiere, mois et pays sur
   une ligne (le pays porte son drapeau, seule exception aux emoji), la recherche, les questions trouvees a cocher (numero,
   enonce), puis Send (le seul bouton plein de la page) et le compteur. Report a question : la liste des retours (date,
   question coupee sur une ligne, nature, statut : Fixed en vert, Declined en gris). Ideas : un champ libre, son compteur
   a droite, Send en contour. « Thank you » en vert, comme « Done for today ». */
.feedback .tete .small{max-width:var(--measure)}
/* Lot 1 : « Seen at my exam » vit aussi sur /account/exams (div.pg-exams) ; ses regles suivent le bloc, pas la page. */
:is(.feedback>section,.pg-exams>.vu)>p:not([class]){margin:0;color:var(--dim)}
:is(.feedback,.pg-exams .vu) form{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp3)}
:is(.feedback,.pg-exams .vu) form>:not(.btn){align-self:stretch}
:is(.feedback,.pg-exams) .contexte{display:grid;grid-template-columns:minmax(0,1fr) 200px minmax(0,1fr);gap:var(--sp2) var(--sp3);align-items:end}
:is(.feedback,.pg-exams) .recherche{max-width:480px}
.case.trouve{display:grid;grid-template-columns:20px 72px minmax(0,1fr);align-items:baseline;gap:var(--sp2);padding:var(--sp2) 0}
.case.trouve .q{font-size:var(--s2);line-height:1.5;color:var(--ink)}
.envoi{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp2) var(--sp3)}
.envoi .compte{margin:0;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.merci{margin:0;font:500 var(--s1)/1.4 var(--fb);color:var(--green-ink)}
.rapports .subject-row{grid-template-columns:112px minmax(0,1fr) 176px 200px;align-items:baseline}
.rapports :is(time,.type,.statut){font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.rapports .q{min-width:0;overflow:hidden;font-size:var(--s1);color:var(--ink);white-space:nowrap;text-overflow:ellipsis}
.rapports .q .code{margin-right:var(--sp1)}
.rapports .statut{text-align:right;font-weight:500;color:var(--ink)}
.rapports .statut.ok{color:var(--green-ink)}
.rapports .statut.non{color:var(--dim)}
.idee .compteur{text-align:right;font-variant-numeric:tabular-nums}
@media (max-width:760px){
  :is(.feedback,.pg-exams) .contexte{grid-template-columns:minmax(0,1fr)}
  .case.trouve{grid-template-columns:20px minmax(0,1fr);row-gap:var(--sp1)}
  .case.trouve .q{grid-column:2}
  .rapports .subject-row{grid-template-columns:auto minmax(0,1fr);gap:var(--sp1) var(--sp2)}
  .rapports .q{grid-column:1/-1;grid-row:1;white-space:normal}
  .rapports time{grid-column:1;grid-row:2}
  .rapports .type{grid-column:2;grid-row:2}
  .rapports .statut{grid-column:1/-1;grid-row:3;text-align:left}
}

/* Sous une question (/train/<code>, 4.13) : la ligne du verdict porte a droite « Seen at my exam » (contour, petit) ; il
   ouvre sous elle, apres un filet, pays et mois preremplis (memorises), Save et Cancel. Enregistre : « Recorded <drapeau>
   Oct 2026 » en vert et le lien « Different at the exam? », qui ouvre l'enonce et les quatre reponses preremplis, la bonne
   reponse, « What was different? » et Send ; son titre a la taille d'un titre de sous-bloc (--s3), pas celle des etiquettes
   de #quiz h3 (quiz.css). Les onglets Explanation / Comments / Improve restent dessous, inchanges. */
.vu-examen{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--sp1) var(--sp3);align-self:stretch}
.vu-ok{margin:0 0 0 auto;font:500 var(--s1)/1.4 var(--fb);color:var(--green-ink)}
.vu-verif{flex:1 0 100%;margin:0;font:400 var(--s1)/1.4 var(--fb);color:var(--dim)}
.vu-form{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--sp2);flex:1 0 100%;padding-top:var(--sp2);border-top:1px solid var(--line)}
.vu-form .field{flex:1 1 200px}
.vu-form .field+.field{flex:0 1 200px}
.vu-form .qz-err{flex:1 0 100%;margin:0}
.difference{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp2);align-self:stretch;padding-top:var(--sp2);
  border-top:1px solid var(--line)}
.difference>:not(.btn){align-self:stretch}
.difference .field textarea{min-height:96px}
#quiz .difference>.titre-v{font:600 var(--s3)/1.3 var(--fd);letter-spacing:-.015em}
.difference .reps-v{display:grid;gap:var(--sp2)}
.difference .reps-v textarea{min-height:72px}
@media (max-width:760px){
  .vu-form .field+.field{flex:1 1 200px}
}
/* Fin du tableau de bord, GO 2. */

/* Lot 1 (20/10/2026) : menu a quatre entrees, barre basse, tete.
   Telephone : la barre haute perd son menu, une barre fixe de quatre entrees (Home, Practise, Notes, Account) prend le bas de
   l'ecran. page() pose la classe avec-bas sur body : le pied reste lisible au-dessus de la barre. */
.app-nav.bas{display:none}
@media (max-width:760px){
  header.top .app-nav{display:none}
  .app-nav.bas{position:fixed;left:0;right:0;bottom:0;z-index:20;display:flex;justify-content:space-around;gap:0;
    padding:0 var(--pad) env(safe-area-inset-bottom);border-top:1px solid var(--line);
    background:var(--nav-bg);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}
  .app-nav.bas a{flex:1;justify-content:center;min-height:56px;font-size:var(--s1);text-decoration:none}
  .app-nav.bas [aria-current="page"]{color:var(--ink);text-decoration:none;box-shadow:inset 0 2px 0 var(--blue-ink)}
  body.avec-bas{padding-bottom:calc(56px + env(safe-area-inset-bottom))}
  /* Pages sans barre basse (admin : menu propre, admin-coquille.js) : la barre haute garde son menu. */
  body:not(.avec-bas) header.top .app-nav{display:flex}
}
/* Tete : la ligne d'acces en gris ; Today : le bouton Start de la ligne par defaut garde sa taille. */
.espace .tete .acces .reste{color:var(--dim)}
.today .defaut .btn{flex:none}
/* Lot 1, feuille 1.2 : /account/settings (liste de lignes), phrase calme des etats sans offre. Jetons seulement.
   Page Account : le nom de la rubrique, ce qu'elle contient, une action a droite (contour) ; la ligne Devices n'a pas
   d'action, sa derniere cellule reste vide pour garder la grille. */
.espace .offre-calme{margin:0;color:var(--dim)}
.compte-lignes{border-top:0}
.compte-lignes .subject-row{grid-template-columns:160px minmax(0,1fr) auto;align-items:center;min-height:56px;column-gap:var(--sp3)}
.compte-lignes .subject-row .name{grid-column:1}
.compte-lignes .det{grid-column:2;font-size:var(--s1);color:var(--dim);line-height:1.4}
.compte-lignes .subject-row>:last-child{grid-column:3;justify-self:end}
@media (max-width:760px){
  .compte-lignes .subject-row{grid-template-columns:minmax(0,1fr) auto;row-gap:var(--sp1);padding-block:var(--sp2)}
  .compte-lignes .det{grid-column:1;grid-row:2}
  .compte-lignes .subject-row>:last-child{grid-column:2;grid-row:1}
}
/* Lot 1, feuille 1.3 : tableau de bord en trois blocs (planches « Dashboard, part 3 »). Jetons seulement.
   Route : trois lignes au-dessus du pli (prochaines epreuves), les autres derriere « All 13 subjects » (meme repli que les
   dates, .dates). Sous la prochaine epreuve, ses deux chapitres les plus faibles (li.faibles) et Drill : c'est l'ancien
   « Where you lose points » sans selecteur. */
.route-dash li.faibles{display:block;padding:var(--sp1) 0 var(--sp3) 120px;border-bottom:1px solid var(--line)}
.faibles .faibles-t{margin:0 0 var(--sp1);font:500 var(--s1)/1.3 var(--fb);color:var(--dim)}
.faibles .lignes{border-top:0}
.faibles .subject-row{grid-template-columns:40px minmax(0,1fr) 160px 150px;align-items:center;min-height:40px}
.faibles .subject-row .code{grid-column:1;grid-row:1}
.faibles .subject-row .name{grid-column:2;grid-row:1;font-weight:500}
.faibles .subject-row .meter{grid-column:3;grid-row:1}
.faibles .pct{grid-column:4;grid-row:1;text-align:right;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.faibles .subject-row:last-child{border-bottom:0}
.faibles [data-loading] .name{color:var(--dim);font-weight:400}
.faibles>.btn{margin-top:var(--sp2)}
.faibles>.btn[aria-disabled="true"]{cursor:default;opacity:.45;pointer-events:none}
.route-plus .lignes{border-top:0}
.route-plus>summary{font-size:var(--s1);color:var(--dim)}
@media (max-width:760px){
  .route-dash li.faibles{padding-left:0}
  .faibles .subject-row{grid-template-columns:40px minmax(0,1fr) auto;row-gap:var(--sp1)}
  .faibles .subject-row .name{grid-column:2}
  .faibles .pct{grid-column:3}
  .faibles .subject-row .meter{grid-column:2/-1;grid-row:2}
  /* Chiffres du jour sur une rangee, plus petits : la hauteur de la page compte sur telephone. */
  .today .figures{flex-direction:row;flex-wrap:nowrap;gap:var(--sp3)}
  .today .figure{flex:1 1 0}
  .today .figure .num{font-size:var(--s4)}
}
/* Continue : les derniers tests, Redo et Redo mistakes ; Delete reste sur la page des tests. */
.continue .field-msg[data-msg]:empty{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%)}
@media (max-width:760px){
  /* Telephone : la matiere et le score sur la premiere ligne, la date et les boutons sur la seconde. */
  .continue .liste-tests .subject-row{grid-template-columns:minmax(0,1fr) auto;row-gap:var(--sp1);align-items:center}
  .continue .liste-tests .matiere{grid-column:1;grid-row:1}
  .continue .liste-tests .score{grid-column:2;grid-row:1;white-space:nowrap;text-align:right}
  .continue .liste-tests time{grid-column:1;grid-row:2}
  .continue .liste-tests .ops{grid-column:2;grid-row:2;justify-content:flex-end}
}
/* Rappel de fin de banque sous Today (30 jours ou moins) : orange a 7 jours ou moins. */
.espace .offre-calme.alerte{color:var(--orange-ink)}
.espace .offre-calme a{color:var(--blue-ink);text-underline-offset:.3em}
.espace .offre-calme a:hover{text-decoration:underline;text-decoration-thickness:1px}
/* Fin du lot 1, feuilles 1.1, 1.2 et 1.3. */

/* Your route, ligne PPL seule (12/11/2026) : le code complet (« PPL 010 ») ne se coupe jamais ; sa colonne (section « Your
   route » plus haut) s'elargit au besoin, minmax(48px | 40px, max-content) : les codes ATPL gardent leur largeur. */
.route-dash .subject-row .code{white-space:nowrap}

/* Page Progress (/account/progress, 12/11/2026 ; src/pages-progres.js, lib/progres.js). Jetons seulement, aucune carte :
   des sections a filet (.espace>section), des listes a filets, des chiffres tabulaires. Jauges : <progress> a 4 px (6 px
   pour les examens), fond au filet, part faite en --blue ; vert seulement pour ce qui est reussi, orange pour ce qui est
   a travailler. Telephone : cibles de 44 px, quatre chiffres en deux rangees. */
.pg-progres :is(h3,p){margin:0}
.pg-progres .ligne-titre{font:600 var(--s1)/1.3 var(--fb);color:var(--dim)}
.pg-progres .sous-t{font:600 var(--s2)/1.3 var(--fd);letter-spacing:-.015em;color:var(--ink)}
.pg-progres .plus{display:inline-flex;align-items:center;min-height:44px}
.pg-progres progress{-webkit-appearance:none;appearance:none;display:block;width:100%;height:4px;margin:0;border:0;
  border-radius:var(--r-pill);background:var(--line);overflow:hidden}
.pg-progres progress::-webkit-progress-bar{background:var(--line);border-radius:var(--r-pill)}
.pg-progres progress::-webkit-progress-value{background:var(--blue);border-radius:var(--r-pill)}
.pg-progres progress::-moz-progress-bar{background:var(--blue);border-radius:var(--r-pill)}
/* 1. Exams : un bloc par ligne de produits (deux colonnes a l'ordinateur quand le compte a les deux). */
.jauges{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:var(--sp4) var(--sp5)}
.jauge{display:flex;flex-direction:column;gap:var(--sp1);min-width:0}
.jauge-n{font:600 var(--s5)/1.05 var(--fd);letter-spacing:-.03em;color:var(--ink);font-variant-numeric:tabular-nums}
.jauge progress{height:6px;margin:var(--sp1) 0 0}
.jauge-reste{font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.jauge-reste.ok{color:var(--green-ink)}
.reussites .subject-row{grid-template-columns:minmax(64px,max-content) minmax(0,1fr) auto 64px;column-gap:var(--sp2);align-items:baseline}
.reussites .subject-row .code{grid-column:1;grid-row:1;white-space:nowrap}
.reussites .subject-row .name{grid-column:2;grid-row:1}
.reussites time{grid-column:3;grid-row:1}
.reussites .score{grid-column:4;grid-row:1}
.reussites :is(time,.score){font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums;white-space:nowrap}
.reussites .score{text-align:right;color:var(--green-ink)}
/* 2. Quatre chiffres sur une rangee ; deux par rangee sur telephone. */
.pg-chiffres .figures{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--sp3)}
.pg-chiffres .figure .num{font-size:var(--s4);white-space:nowrap}
/* 3. Activity : barres du SVG (couleur ici, geometrie en attributs), base au filet, dates des bornes dessous. */
.semaines svg{display:block;width:100%;height:96px}
.semaines .base{fill:var(--line-strong)}
.semaines .barre{fill:var(--blue)}
.semaines .axe{display:flex;justify-content:space-between;gap:var(--sp2);margin-top:var(--sp1);font-size:var(--s1);color:var(--dim);
  font-variant-numeric:tabular-nums}
/* 4. Needs work : code, nom, precision en orange, Practise. */
.pg-faibles .subject-row{grid-template-columns:minmax(64px,max-content) minmax(0,1fr) auto auto;column-gap:var(--sp2);align-items:center}
.pg-faibles .subject-row .code{grid-column:1;grid-row:1;white-space:nowrap}
.pg-faibles .subject-row .name{grid-column:2;grid-row:1}
.pg-faibles .pct{grid-column:3;grid-row:1}
.pg-faibles .btn{grid-column:4;grid-row:1}
.pg-faibles .subject-row .pct{font-size:var(--s1);color:var(--orange-ink);font-variant-numeric:tabular-nums;white-space:nowrap}
/* 5. Scores : la courbe (ds/ 10c), echelle de 50 a 100 %, seuil de 75 % a mi-hauteur ; puis date, matiere, mode, bonnes / total, %. */
.pg-scores .courbe[hidden],.pg-scores .lignes[hidden]{display:none}
.liste-scores .subject-row{grid-template-columns:112px minmax(0,1fr) 96px 64px 56px;column-gap:var(--sp2);align-items:baseline}
.liste-scores .matiere{min-width:0;font:600 var(--s2)/1.25 var(--fd);letter-spacing:-.015em;color:var(--ink)}
.liste-scores .matiere .code{margin-right:var(--sp1);white-space:nowrap}
.liste-scores :is(time,.mode,.score,.pct){font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums;white-space:nowrap}
.liste-scores :is(.score,.pct){text-align:right}
.liste-scores .pct{font-weight:600}
.liste-scores .pct.ok{color:var(--green-ink)}
.liste-scores .pct.ko{color:var(--orange-ink)}
/* 6. By subject : code, nom, jauge des vues, « 297 / 417 seen · 78 % correct », etat, Practise. */
.par-matiere .subject-row{grid-template-columns:minmax(64px,max-content) minmax(0,1fr) 144px 240px 152px 104px;column-gap:var(--sp2);
  align-items:center;min-height:calc(40px + 2 * var(--sp2))}
.par-matiere .subject-row .code{grid-column:1;white-space:nowrap}
.par-matiere .subject-row .name{grid-column:2}
.par-matiere progress{grid-column:3}
.par-matiere .vu{grid-column:4;font-size:var(--s1);color:var(--dim);font-variant-numeric:tabular-nums}
.par-matiere .etat{grid-column:5;font-size:var(--s1);color:var(--ink);font-variant-numeric:tabular-nums}
.par-matiere .etat.ok{color:var(--green-ink)}
.par-matiere .btn{grid-column:6;justify-self:end}
.pg-calme{display:flex;flex-direction:column;gap:var(--sp1)}
@media (max-width:760px){
  .pg-progres .btn.sm{min-height:44px}
  .pg-chiffres .figures{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp3) var(--sp2)}
  .reussites .subject-row{grid-template-columns:minmax(40px,max-content) minmax(0,1fr) auto;row-gap:var(--sp1)}
  .reussites time{grid-column:2;grid-row:2}
  .reussites .score{grid-column:3;grid-row:1}
  .pg-faibles .subject-row{grid-template-columns:minmax(40px,max-content) minmax(0,1fr) auto;row-gap:var(--sp1)}
  .pg-faibles .pct{grid-column:2;grid-row:2}
  .pg-faibles .btn{grid-column:3;grid-row:1/3}
  .liste-scores .subject-row{grid-template-columns:minmax(0,1fr) auto auto;row-gap:var(--sp1)}
  .liste-scores .matiere{grid-column:1;grid-row:1}
  .liste-scores .score{grid-column:2;grid-row:1}
  .liste-scores .pct{grid-column:3;grid-row:1}
  .liste-scores time{grid-column:1;grid-row:2}
  .liste-scores .mode{grid-column:2/-1;grid-row:2;text-align:right}
  .par-matiere .subject-row{grid-template-columns:minmax(40px,max-content) minmax(0,1fr) auto;row-gap:var(--sp1);min-height:0}
  .par-matiere progress{grid-column:2;grid-row:2}
  .par-matiere .vu{grid-column:2;grid-row:3}
  .par-matiere .etat{grid-column:2;grid-row:4}
  .par-matiere .btn{grid-column:3;grid-row:1/4;align-self:center}
}
/* Fin de la page Progress. */

/* ---- 6. Page d'entrainement (/train/<code>) (tache 5) ----
   <div class="entrainement"> p.bandeau  <div id="quiz" data-…>  <p class="retour"><a class="btn ghost sm"></div>
   En haut, en petit, l'etat de la banque : jours restants, acces a vie, ou date de fin passee. Puis, en essai, le bandeau :
   une surface et un filet (comme .notice), la phrase et l'action sur une ligne a l'ordinateur, l'action dessous au
   telephone ; jamais de barre a gauche. p.bandeau est un contrat (classe lue par les tests). L'erreur de /contact est un .field-msg depuis la tache 7. */
.entrainement{padding-top:var(--sp4)}
.bandeau{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--sp2) var(--sp3);
  margin:0 0 var(--sp4);padding:var(--sp2) var(--sp3);border-radius:var(--r-screen);background:var(--surface);
  box-shadow:inset 0 0 0 1px var(--line);font-variant-numeric:tabular-nums}
.bandeau span{flex:1 1 320px;min-width:0;text-wrap:pretty}
.bandeau .btn{flex:none}
.entrainement .retour{margin:var(--sp6) 0 0}
@media (max-width:480px){
  .bandeau{padding:var(--sp2)}
  .entrainement .retour{margin-top:var(--sp5)}
}

/* ---- 7. Lecteur de fiches (/_c/…-web.html, via /read/<code>/<lang>) (tache 6) ----
   <html class="reader-on"> … <body><header class="top reader" data-theme><a class="brand">…</a>
     <a class="l" href="/account">Back to your dashboard</a> <button class="theme-btn">…</button></header> <nav class="rail">…
   La fiche est generee hors de ce depot (../_atpl/web.py, screen.css) ; src/contenu.js (HTMLRewriter) y pose la classe,
   la barre, THEME_HEAD, ds/tokens.css et cette feuille AVANT les siennes : sur <html>, ses variables (--bg, --line, --dim,
   --blue, --col, --measure…) gagnent, la fiche ne bouge pas. La barre porte data-theme (recopie de <html> par son script) :
   les jetons du ds/ s'appliquent a elle seule. Ni ds/base.css ni ds/components.css (les editions ont aussi des .wrap,
   .nav, .top, .trap) : la marque et la bascule reprennent ici les declarations de components.css (test : a l'identique).
   Barre collante de 56 px au-dessus de tout ; le sommaire de la fiche (fixe a gauche au-dessus de 1080 px, barre collante
   en dessous) passe dessous, decale de --reader-top ; les ancres tombent sous la barre (scroll-padding). */
html.reader-on{--reader-top:56px;scroll-padding-top:var(--reader-top)}
header.top.reader{position:sticky;top:0;z-index:40;max-width:none;height:var(--reader-top);min-height:0;flex-wrap:nowrap;
  background:var(--bg);border-bottom:1px solid var(--line);color:var(--ink)}
/* Telephone etroit (360 px et moins) : le retour passe sur deux lignes plutot que d'etre coupe. */
header.top.reader a.l{min-width:0;white-space:normal;text-align:right;line-height:1.25;text-wrap:balance}
header.top.reader .brand{display:inline-flex;align-items:center;gap:var(--sp1);flex:none;color:var(--ink);
  font:700 var(--s2)/1 var(--fd);letter-spacing:-.02em;text-decoration:none}
header.top.reader .brand>span>span{color:var(--blue)}
header.top.reader .brand svg{display:block;width:20px;height:20px;flex:none}
header.top.reader .theme-btn{display:grid;place-items:center;width:40px;height:40px;flex:none;padding:0;border:0;border-radius:var(--r-pill);
  background:transparent;color:var(--dim);cursor:pointer;
  transition:background-color var(--t-hover) var(--ease),color var(--t-hover) var(--ease)}
header.top.reader .theme-btn:hover{color:var(--ink);background:var(--surface-2)}
header.top.reader .theme-btn svg{display:block;width:18px;height:18px}
header.top.reader :focus-visible{outline:2px solid var(--focus);outline-offset:3px}
html.reader-on .rail{top:var(--reader-top)}
html.reader-on .rail.open{max-height:calc(100vh - var(--reader-top));max-height:calc(100dvh - var(--reader-top))}
/* Filet de progression de lecture de la fiche (.prog, fixe en haut, z 50, screen.css) : pose sur le filet du bas de la
   barre (3 px au-dessus de son bord), jamais sur la marque ni sur la bascule. */
html.reader-on .prog{top:calc(var(--reader-top) - 3px)}

/* ---- 8. Contact, avis apres achat, pages de message (tache 7) ----
   Pages de message (pageMessage) et Contact : la colonne calme de la section 4. Contact connecte : menu de l'espace
   client (entree « Contact » courante) ; sans session, la barre seule. Erreur sous le champ fautif (.field-msg du ds/).
   <section class="calme contact"><h1>Contact</h1><p class="small">…</p><form>.field (select, textarea) .sr .btn</form></section>
   La colonne de Contact s'elargit un peu : le select des matieres porte des noms longs (« 021 Airframe, Systems… »). */
.calme.contact{max-width:560px}

/* /review (src/avis.js) : deux colonnes a l'ordinateur (titre et promesse a gauche, formulaire a droite, 5/7 de la
   grille), une sur telephone. Aucune carte : le formulaire pose sur le fond, comme la connexion.
   <section class="avis"><div class="avis-tete"><h1>…</h1><p class="small">…</p></div>
     <form> <fieldset class="etoiles"><legend>Your rating</legend><div>(input.sr radio + label>svg) x 5</div></fieldset>
     .field (textarea) x 2 <label class="case"><input type="checkbox"> …</label> <div class="deux">.field x 2</div> .btn</form></section>
   Etoiles : le pictogramme de l'etoile de lib/quiz.js (trait 1,6 sur 20 x 20), --dim vide, --blue-ink pleine jusqu'a la
   note choisie (le bleu de texte de la charte, comme l'etoile suivie de l'entrainement ; pas d'or). Au survol, apercu
   jusqu'a l'etoile pointee. Sans :has() (Firefox avant 121, Safari avant 15.4), seules l'etoile choisie et l'etoile
   survolee se remplissent : leurs regles sont separees de celles qui lisent :has(). */
.avis{display:grid;gap:var(--sp5);padding-top:var(--sp6)}
.avis-tete{display:flex;flex-direction:column;gap:var(--sp3)}
.avis-tete h1{margin:0;font-size:var(--s5);line-height:1.04;letter-spacing:-.035em;text-wrap:balance}
.avis-tete p{margin:0;max-width:30em;text-wrap:pretty}
.avis form{display:flex;flex-direction:column;gap:var(--sp3);min-width:0}
.avis .btn{align-self:flex-start}
@media (min-width:900px){
  .avis{grid-template-columns:minmax(0,5fr) minmax(0,7fr);gap:var(--sp3) var(--sp6)}
  .avis-tete{position:sticky;top:var(--sp4);align-self:start}
}
@media (max-width:480px){
  .avis{gap:var(--sp4);padding-top:var(--sp4)}
  .avis .btn{align-self:stretch}
}

.etoiles{min-width:0;margin:0;padding:0;border:0}
.etoiles legend{margin:0 0 var(--sp1);padding:0;font:500 var(--s1)/1.3 var(--fb);color:var(--ink)}
.etoiles>div{display:flex;margin-left:calc(-1 * var(--sp1))}
.etoiles label{display:grid;place-items:center;width:48px;height:48px;margin:0;border-radius:var(--r-pill);color:var(--dim);
  cursor:pointer;transition:color var(--t-hover) var(--ease)}
.etoiles svg{display:block;width:32px;height:32px}
.etoiles path{fill:transparent;transition:fill var(--t-hover) var(--ease)}
/* Une regle sans :has(), une avec : un navigateur sans :has() invalide toute la liste ou il parait, le repli doit vivre
   dans sa propre regle (test). */
.etoiles input:checked+label{color:var(--blue-ink)}
.etoiles label:has(~ input:checked){color:var(--blue-ink)}
.etoiles input:checked+label path{fill:var(--blue-ink)}
.etoiles label:has(~ input:checked) path{fill:var(--blue-ink)}
.etoiles>div:hover label{color:var(--dim)}
.etoiles>div:hover label path{fill:transparent}
.etoiles>div:hover label:hover{color:var(--blue-ink)}
.etoiles>div:hover label:has(~ label:hover){color:var(--blue-ink)}
.etoiles>div:hover label:hover path{fill:var(--blue-ink)}
.etoiles>div:hover label:has(~ label:hover) path{fill:var(--blue-ink)}
.etoiles input:focus-visible+label{outline:2px solid var(--focus);outline-offset:-2px}

/* Case a cocher (accord de publication) : la case a gauche, la phrase a cote, a l'encre. */
.case{display:flex;align-items:flex-start;gap:var(--sp2);margin:0;color:var(--ink);font-size:var(--s1);cursor:pointer;
  text-wrap:pretty}
.case input{flex:none;width:20px;height:20px;margin:0;accent-color:var(--blue-ink);cursor:pointer}

/* Prenom et pays : cote a cote, l'un sous l'autre sur telephone. */
.deux{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--sp3) var(--sp2)}
@media (max-width:480px){
  .deux{grid-template-columns:minmax(0,1fr)}
}

/* ---- 9. Administration (/admin, /admin/clients, commentaires, retours, messages, recensements, versions, idees, avis) ----
   src/admin-coquille.js : <div class="admin-page"> <div class="onglets-defile"><nav class="tabs admin-onglets">…</nav></div>
   <div class="tete"><h1>…</h1></div> <p id="msg" class="alerte"> puis des <section class="bloc"> (filet au-dessus, comme les
   sections de l'espace client). Tableaux : div.table-defile > table.admin ; statuts en texte : .st.ok (vert), .st.ko (orange),
   .st.nd (gris), jamais de rouge. Champs .field, cases .case, boutons .btn et .btn.ghost.sm du ds/. Jetons seulement. */
.admin-page{display:flex;flex-direction:column;gap:var(--sp4);padding-top:var(--sp2)}
.admin-page p{margin:0}
.admin-page .tete{display:flex;flex-direction:column;gap:var(--sp1)}
/* Titre a --s4 : l'onglet nomme deja la page, l'admin est un outil de tous les jours (pas une vitrine). */
.admin-page h1{margin:0;font-size:var(--s4);line-height:1.1;letter-spacing:-.025em}
.admin-page h2{margin:0;font-size:var(--s3);line-height:1.2;letter-spacing:-.015em}
.admin-page h3{margin:0;font-size:var(--s3);line-height:1.3;letter-spacing:-.015em}
.admin-page ul.simple,.admin-page ol{margin:0;padding-left:var(--sp3)}
.admin-page .alerte{color:var(--orange-ink);font-size:var(--s1)}
.admin-page .alerte:empty{display:none}

/* Onglets a l'ordinateur ; sur telephone, un menu deroulant (#admin-aller, meme liste et compteurs) les remplace : la page
   ne defile jamais de cote. position:relative : le texte .sr des compteurs reste dans la rangee. */
.onglets-defile{position:relative;overflow-x:auto;scrollbar-width:none}
.onglets-defile::-webkit-scrollbar{display:none}
.admin-onglets{display:flex;width:max-content}
.admin-onglets a{white-space:nowrap;gap:var(--sp1)}
.admin-onglets .cpt{color:var(--orange-ink);font-variant-numeric:tabular-nums}
.admin-aller{display:none}
@media (max-width:760px){
  .onglets-defile{display:none}
  .admin-aller{display:grid}
}

/* Sections et blocs : un filet au-dessus. Les elements d'une liste (commentaire, message, version) sont des .bloc plus serres. */
.admin-page .bloc{display:flex;flex-direction:column;gap:var(--sp3);min-width:0;padding-top:var(--sp3);border-top:1px solid var(--line)}
.admin-page .liste{display:flex;flex-direction:column;gap:var(--sp3)}
.admin-page .liste>.bloc{gap:var(--sp2);padding-top:var(--sp2)}
.admin-page .liste>.bloc>h2{font-size:var(--s3)}
.admin-page .masque{opacity:.6}
.admin-page .meta{color:var(--dim);font-size:var(--s1)}
.admin-page .texte{white-space:pre-wrap;overflow-wrap:anywhere}
.admin-page .prop{display:flex;flex-direction:column;gap:var(--sp1);padding-top:var(--sp2);border-top:1px solid var(--line)}
.admin-page .prop:first-of-type{padding-top:0;border-top:0}
.admin-page .verdict{display:flex;flex-direction:column;gap:var(--sp1);padding-top:var(--sp2);border-top:1px solid var(--line)}
.admin-page .verdict ul{margin:0;padding-left:var(--sp3)}

/* Actions et filtres sur une ligne ; les champs d'une ligne se partagent la largeur, l'un sous l'autre sur telephone. */
.admin-page .bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp1) var(--sp2)}
.admin-page .bar>.field{min-width:224px}
.admin-page .bar:has(>.field){align-items:end}
.admin-page .deux{align-items:start}
.admin-page .bloc>.field{max-width:560px}
.admin-page .field textarea{min-height:96px}
.admin-page .rep{display:flex;flex-direction:column;gap:var(--sp2)}
.admin-page .rep[hidden]{display:none}
.admin-page .cbs{min-width:0;margin:0;padding:0;border:0}
.admin-page .cbs legend{margin:0 0 var(--sp1);padding:0;font:500 var(--s1)/1.3 var(--fb);color:var(--ink)}
.admin-page .cbs-liste{display:flex;flex-wrap:wrap;gap:var(--sp1) var(--sp3)}
.admin-page .cbs-liste .case{gap:var(--sp1)}

/* Statuts en texte colore : vert = en ordre, orange = a faire (jamais de rouge, « Suspendu » reste orange). */
.st{font-weight:500}
.st.ok{color:var(--green-ink)}
.st.ko{color:var(--orange-ink)}
.st.nd{color:var(--dim)}

/* Tableaux : filets fins, en-tetes en petites capitales sobres, chiffres tabulaires, ligne survolee en --surface-2. */
.table-defile{max-width:100%;overflow-x:auto}
table.admin{width:100%;border-collapse:collapse;font-size:var(--s1);font-variant-numeric:tabular-nums}
table.admin :is(th,td){padding:var(--sp1) var(--sp2);border-bottom:1px solid var(--line);text-align:left;vertical-align:top}
table.admin td{white-space:nowrap}
/* Lignes a bouton : texte et bouton centres sur la meme ligne ; les tables de texte long restent alignees en haut. */
table.admin:not(.texte) td{vertical-align:middle}
table.admin :is(th,td):first-child{padding-left:0}
table.admin :is(th,td):last-child{padding-right:0}
table.admin th{border-top:1px solid var(--line);color:var(--dim);font-weight:500;font-variant-caps:all-small-caps;letter-spacing:.04em;white-space:nowrap}
table.admin :is(th,td).n{text-align:right}
table.admin tbody tr:hover{background:var(--surface-2)}
table.admin tr.clic{cursor:pointer}
table.admin tr.total td{font-weight:600}
table.admin.texte td{white-space:normal;overflow-wrap:anywhere}
table.admin.texte td.nw{white-space:nowrap}
table.admin td .bar{margin-top:var(--sp1)}
.admin-page .retire{opacity:.5;text-decoration:line-through}

/* Aperçu : seules les files non vides, une ligne entiere cliquable (libelle, nombre en orange, chevron). Meme grille que les
   reglages de la fiche client : libelle a gauche, valeur puis action alignees a droite, a la meme position d'une ligne a l'autre. */
.files,.admin-page .reglages{margin:0;padding:0;list-style:none;border-top:1px solid var(--line)}
.files li,.admin-page .reglages li{border-bottom:1px solid var(--line)}
.files a{display:grid;grid-template-columns:minmax(0,1fr) auto 24px;align-items:center;gap:var(--sp2);min-height:56px;
  color:var(--ink);text-decoration:none;transition:color var(--t-hover) var(--ease)}
.files a:hover{color:var(--blue-ink)}
.files .combien{font:600 var(--s3)/1 var(--fd);color:var(--orange-ink);font-variant-numeric:tabular-nums}
.files .fl{justify-self:end;color:var(--dim);font-size:var(--s3)}
.admin-page .reglages li{display:grid;grid-template-columns:176px minmax(0,1fr) auto;align-items:center;gap:var(--sp2);min-height:56px;padding:var(--sp1) 0}
.admin-page .reglages .nom{color:var(--dim);font-size:var(--s1)}
.admin-page .reglages .val{min-width:0;overflow-wrap:anywhere}
@media (max-width:480px){
  .admin-page .reglages li{grid-template-columns:minmax(0,1fr) auto}
  .admin-page .reglages .nom{grid-column:1/-1}
}

/* Fiche client : titre, puis des blocs a un seul niveau de titre. */
.admin-page .fiche{gap:var(--sp4)}
.admin-page .tete-fiche{display:flex;flex-direction:column;gap:var(--sp1)}
.admin-page .groupe{display:flex;flex-direction:column;gap:var(--sp2)}
.admin-page .groupe>h2{font-size:var(--s2)}
.admin-page .groupe>.field:has(select){max-width:400px}

/* Telephone : les trois chiffres de l'Aperçu restent sur une rangee (trois nombres courts), la liste des clients perd la
   colonne « Dernière visite » (la fiche la donne) : rien n'est coupe dans la table. */
@media (max-width:760px){
  .admin-page .figures{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--sp2)}
  #clients table.admin :is(th,td):nth-child(3){display:none}
  #clients table.admin :is(th,td):nth-child(2){padding-right:0}
}

/* Clients : liste et fiche cote a cote a partir de 1100 px quand une fiche est ouverte, l'une sous l'autre en dessous. */
.admin-page .maitre{display:flex;flex-direction:column;gap:var(--sp4)}
@media (min-width:1100px){
  .admin-page .maitre:has(#fiche:not([hidden])){display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);align-items:start;gap:var(--sp5)}
}
table.admin td .meta{display:block}
table.admin tr[aria-current]{background:var(--surface-2)}
table.admin tr[aria-current] td:first-child{font-weight:600}

/* Repli (annonces) : le titre de section sert de bouton, + ferme et − ouvert, comme la FAQ du site. */
.admin-page details.bloc{display:block}
.admin-page details.repli>summary{display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp3);list-style:none;cursor:pointer}
.admin-page details.repli>summary::-webkit-details-marker{display:none}
.admin-page details.repli>summary::after{content:"+";flex:none;width:1em;text-align:center;font-size:var(--s3);color:var(--dim)}
.admin-page details.repli[open]>summary::after{content:"\2212"}
.admin-page details.repli>summary:hover{color:var(--blue-ink)}
.admin-page .repli-corps{display:flex;flex-direction:column;gap:var(--sp3);padding-top:var(--sp3)}
.admin-page .repli-corps>.field{max-width:560px}

/* ---- Menus de l'espace client (12/11/2026) ----
   Barre haute : Dashboard, Practise, Tests, Progress, Notes, Account (+ Admin). Telephone : barre basse a cinq entrees (Home,
   Practise, Tests, Progress, Notes), Account en lien a droite de la bascule de theme (a.compte-tel, page()).
   Sous-menu (.sous-nav, sousMenu() de src/pages.js) : une rangee de liens sous le titre, filet sous la rangee, l'onglet
   courant en encre pleine avec un filet bleu dessous (la grammaire de la barre basse) ; defile a l'horizontale s'il ne tient
   pas. Lien « Notes » (.lien-notes) : lien texte, jamais un bouton. */
.compte-tel{display:none}
@media (max-width:760px){
  .app-nav.bas{padding-inline:var(--sp1)}
  body.avec-bas header.top .compte-tel{order:3;display:inline-flex;align-items:center;min-height:44px;color:var(--dim);
    font:500 var(--s1)/1 var(--fb);white-space:nowrap;text-decoration:none;text-underline-offset:.5em;transition:color var(--t-hover) var(--ease)}
  body.avec-bas header.top .compte-tel:hover{color:var(--ink)}
  body.avec-bas header.top .compte-tel[aria-current="page"]{color:var(--ink);text-decoration:underline;text-decoration-thickness:1px}
}
.sous-nav{display:flex;gap:var(--sp3);min-width:0;max-width:100%;margin-top:var(--sp2);overflow-x:auto;overscroll-behavior-x:contain;
  scrollbar-width:none;border-bottom:1px solid var(--line)}
.sous-nav::-webkit-scrollbar{display:none}
.sous-nav a{flex:none;display:inline-flex;align-items:center;min-height:44px;color:var(--dim);font:500 var(--s1)/1 var(--fb);
  white-space:nowrap;text-decoration:none;transition:color var(--t-hover) var(--ease)}
.sous-nav a:hover{color:var(--ink)}
.sous-nav [aria-current="page"]{color:var(--ink);box-shadow:inset 0 -2px 0 var(--blue-ink)}
.sous-nav a:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.lien-notes{display:inline-flex;align-items:center;min-height:40px;font-size:var(--s1);white-space:nowrap}
.lien-notes:hover{text-decoration:underline;text-decoration-thickness:1px}
.lignes .ops .lien-notes{align-self:center}
/* Your route : Notes puis Practise dans la derniere colonne ; sur telephone, Practise reste en premiere ligne et Notes se
   pose au bout de la ligne d'etat (les cellules gardent toute la largeur : « last mock 78 % » tient sur une ligne). */
.route-dash .acts{grid-column:7;grid-row:1;justify-self:end;display:flex;align-items:center;gap:var(--sp2)}
@media (max-width:760px){
  .route-dash .acts{display:contents}
  .route-dash .acts .btn{grid-row:1}
  .route-dash .lien-notes{grid-column:4;grid-row:2;justify-self:end;align-self:end;align-items:flex-end}
}
/* Pages Tests et Custom test : la section suit le titre sans titre propre. Exam dates sur sa page (/account/exams/dates,
   section nommee par aria-label, sans h2) : le filet du sous-menu suffit, la liste suit le titre. */
.espace>section.tests.seul{gap:var(--sp2)}
.espace>section.dates[aria-label]{padding-top:0;border-top:0}
