:root{--sab:env(safe-area-inset-bottom,0px);
  --bg:#0d1014;
  --panel:#151a21;
  --panel-2:#1b222b;
  --line:#252d38;
  --txt:#e8ecf3;
  --txt-dim:#8b96a8;
  --orange:#ff8b3d;
  --cyan:#3ecfe0;
  --green:#4ade80;
  --yellow:#fbbf24;
  --red:#f8717a;
  --violet:#a78bfa;
  --radius:14px;
}
*{box-sizing:border-box}
/* iOS Safari ignore deliberement user-scalable=no depuis iOS 10 : la balise
   viewport ne suffit donc pas a supprimer le zoom au double tap, qui deplace
   toute la page des que Maceo tape deux fois un peu vite. touch-action:
   manipulation le desactive proprement, en gardant le defilement et le
   pincement — signale par Sylvain le 31/08/2026.                        */
html,body{margin:0;padding:0;touch-action:manipulation}
button,a,label,input,textarea,select,.bench,.ca-noeud{touch-action:manipulation}
body{
  background:
    radial-gradient(1200px 600px at 80% -10%, #1c2531 0%, transparent 60%),
    radial-gradient(900px 500px at -10% 110%, #1a2028 0%, transparent 55%),
    var(--bg);
  color:var(--txt);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,sans-serif;
  font-size:15px;line-height:1.5;min-height:100vh;
}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-variant-numeric:tabular-nums}
.hidden{display:none !important}

/* ================= BANDEAU BAC À SABLE ================= */
/* z-index au-dessus de tout le reste (gate:100, modales:500) : jamais masqué. */
.sable-banniere{
  position:fixed;top:0;left:0;right:0;z-index:9999;height:28px;line-height:22px;
  background:#1a0d05;color:var(--yellow);font-weight:800;font-size:12px;letter-spacing:.06em;
  text-align:center;padding:0 10px;box-shadow:0 2px 12px rgba(0,0,0,.5);
  overflow:hidden;white-space:nowrap;text-overflow:ellipsis;box-sizing:border-box;
  border-top:3px solid var(--yellow);border-bottom:3px solid var(--yellow);
}
/* Réserve la place du bandeau : posé sur <body> par app.js seulement quand le
   bandeau est réellement affiché (jamais en production). Les éléments qui
   couvrent tout le viewport (.gate, .prog-fond) et la barre du haut, qui colle
   au sommet, ignorent le padding du body — on décale donc leur "top" aussi. */
body.avec-bandeau{padding-top:28px}
body.avec-bandeau .gate{top:28px}
body.avec-bandeau .prog-fond{top:28px}
body.avec-bandeau .confirm-fond{top:28px}
body.avec-bandeau .topbar{top:28px}

/* ================= ÉCRAN D'ENTRÉE ================= */
.gate{
  position:fixed;inset:0;z-index:100;display:grid;place-items:center;
  background:radial-gradient(800px 500px at 50% 30%,#1b2431,#0d1014 70%);
  padding:20px;
}
.gate-box{width:100%;max-width:370px;text-align:center}
.gate .gear{
  width:60px;height:60px;border-radius:17px;margin:0 auto 20px;
  background:linear-gradient(135deg,var(--orange),#e2551f);
  display:grid;place-items:center;box-shadow:0 0 40px rgba(255,139,61,.4);
}
.gate h1{font-size:24px;letter-spacing:.2em;margin:0 0 6px}
.gate-tagline{color:var(--accent,#ff8b3d);font-size:12px;letter-spacing:.08em;margin:0 0 18px;font-weight:600}
.gate p{color:var(--txt-dim);font-size:13.5px;margin:0 0 26px}
.gate input{
  width:100%;background:var(--panel);border:1px solid var(--line);color:var(--txt);
  border-radius:12px;padding:14px 16px;font-size:17px;text-align:center;
  letter-spacing:.16em;outline:none;font-family:ui-monospace,Menlo,monospace;
}
.gate input:focus{border-color:var(--orange);box-shadow:0 0 0 3px rgba(255,139,61,.13)}
.gate button{
  width:100%;margin-top:12px;padding:13px;border:none;border-radius:12px;cursor:pointer;
  background:linear-gradient(135deg,var(--orange),#e2551f);color:#1a0d05;
  font-size:15px;font-weight:700;font-family:inherit;transition:.15s;
}
.gate button:hover{filter:brightness(1.1)}
.gate button:disabled{opacity:.5;cursor:default}
.gate-err{color:var(--red);font-size:13px;margin-top:14px;min-height:19px}
.gate .gear{cursor:pointer;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
.gate .gear.adm{background:linear-gradient(135deg,#a78bfa,#6d4fd4);box-shadow:0 0 40px rgba(167,139,250,.4);cursor:default}
.jauge{
  width:60px;height:3px;margin:-14px auto 14px;border-radius:999px;background:#20272f;
  opacity:0;transition:opacity .25s;overflow:hidden;
}
.jauge>i{display:block;height:100%;width:0;border-radius:999px;background:var(--orange)}
#admBox h1{color:var(--violet)}
#admBox input:focus{border-color:var(--violet);box-shadow:0 0 0 3px rgba(167,139,250,.13)}
#admBox button{background:linear-gradient(135deg,#a78bfa,#6d4fd4);color:#160e2e}

/* bandeau du mode admin */
.bandeau-admin{
  background:linear-gradient(90deg,rgba(167,139,250,.18),rgba(167,139,250,.06));
  border-bottom:1px solid rgba(167,139,250,.35);
  color:#c9b6ff;font-size:12.5px;padding:8px 20px;text-align:center;letter-spacing:.02em;
}
body[data-role="admin"] .grade-badge,
body[data-role="admin"] .xp-wrap{opacity:.4}

/* ================= TOPBAR ================= */
.topbar{
  display:flex;align-items:center;gap:26px;padding:14px 22px;
  border-bottom:1px solid var(--line);background:rgba(16,20,26,.75);
  backdrop-filter:blur(8px);position:sticky;top:0;z-index:20;flex-wrap:wrap;
}
.brand{display:flex;align-items:center;gap:12px;flex-shrink:0}
.brand .gear{
  width:38px;height:38px;border-radius:11px;
  background:linear-gradient(135deg,var(--orange),#e2551f);
  display:grid;place-items:center;box-shadow:0 0 22px rgba(255,139,61,.35);
}
.brand h1{font-size:17px;margin:0;letter-spacing:.16em;font-weight:700}
.brand span{display:block;font-size:10.5px;color:var(--txt-dim);letter-spacing:.1em;font-weight:400}
.grade-block{display:flex;align-items:center;gap:14px;flex:1;min-width:250px}
.grade-badge{
  padding:5px 12px;border-radius:999px;font-size:12px;font-weight:600;white-space:nowrap;
  background:rgba(167,139,250,.14);color:var(--violet);border:1px solid rgba(167,139,250,.3);
}
/* 28/08/2026 - la jauge dXP occupait toute la largeur libre du bandeau :
   un rail gris de 900 px rempli a 15 %, cetait lobjet le plus grand de
   lecran pour linformation la moins actionnable. Largeur fixe et rail fin. */
.xp-wrap{flex:0 0 auto;width:186px}
.xp-labels{display:flex;justify-content:space-between;gap:10px;font-size:10.5px;color:var(--txt-dim);margin-bottom:3px}
.xp-labels b{color:var(--txt)}
.xp-track{height:5px;background:#20272f;border-radius:999px;overflow:hidden}
.xp-fill{height:100%;border-radius:999px;background:linear-gradient(90deg,#7c5cf0,var(--violet),#d8b4fe);
  box-shadow:0 0 14px rgba(167,139,250,.55);transition:width .9s cubic-bezier(.2,.7,.3,1)}
.pill{
  display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--txt-dim);
  padding:6px 12px;border:1px solid var(--line);border-radius:999px;background:var(--panel);
  cursor:pointer;transition:.15s;
}
.pill:hover{color:var(--txt);border-color:var(--orange)}
.pill b{color:var(--orange)}
.pill.admin{border-color:rgba(167,139,250,.45);color:var(--violet)}

/* ================= LAYOUT ================= */
.wrap{
  display:grid;grid-template-columns:330px minmax(0,1fr) 250px;gap:18px;
  padding:18px 22px 40px;max-width:1600px;margin:0 auto;align-items:start;
}
/* 19/08/2026 — après plusieurs essais en CSS Grid pur (align-items:stretch,
   overflow:hidden, align-self…) qui n'ont pas donné le résultat attendu sans
   pouvoir être vérifiés sur un vrai navigateur, la hauteur de .chat est
   maintenant fixée en JavaScript (app.js, ajusterHauteurChat()) à partir de
   la hauteur RÉELLEMENT MESURÉE de la colonne de droite — fiable par
   construction, sans dépendre des subtilités de calcul de hauteur des
   grilles CSS. Cette règle ne pose qu'un plancher, pour l'affichage avant
   que le JS n'ait tourné. */
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
.card-head{
  padding:12px 16px;border-bottom:1px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:linear-gradient(180deg,rgba(255,255,255,.03),transparent);
}
.card-head h2{margin:0;font-size:12px;letter-spacing:.13em;color:var(--txt-dim);font-weight:600}
.card-body{padding:14px 16px}

/* ================= BANCS ================= */
.bench{padding:9px 10px;border-radius:10px;transition:background .15s}
.bench:hover{background:var(--panel-2)}
.bench-top{display:flex;justify-content:space-between;align-items:baseline;gap:8px;margin-bottom:6px}
.bench-name{font-size:13px;line-height:1.35;min-width:0}
.bench-name i{font-style:normal;color:var(--txt-dim);font-size:11px;margin-right:6px}
.bench-tier{font-size:10.5px;color:var(--txt-dim);margin-top:5px}
.legend{display:flex;flex-wrap:wrap;gap:5px 12px;padding:12px 16px;border-top:1px solid var(--line);font-size:10.5px;color:var(--txt-dim)}
.legend span{display:flex;align-items:center;gap:5px}
.dot{width:8px;height:8px;border-radius:3px;display:inline-block}
.lacune{display:flex;gap:9px;font-size:12.5px;padding:9px 0;border-bottom:1px solid var(--line)}
.lacune:last-child{border:0;padding-bottom:0}
.sev{width:3px;border-radius:2px;flex-shrink:0}
.lacune small{color:var(--txt-dim);display:block;font-size:10.5px;margin-top:2px}
.vide{color:var(--txt-dim);font-size:12.5px;font-style:italic}

/* ================= CHAT =================
   Historique des essais ratés du 19/08/2026 (hauteur fixe à un écran, puis
   align-items:stretch/overflow:hidden en CSS Grid pur) : voir la note sur
   .wrap plus haut. La hauteur de .chat est désormais pilotée par JS
   (app.js, ajusterHauteurChat()), calée sur la vraie hauteur mesurée de la
   colonne de droite. */
.chat{display:flex;flex-direction:column;min-height:440px}
/* min-height:0 : sans lui, un enfant flex avec overflow:auto peut refuser de
   rétrécir sous la hauteur de son contenu dans certains navigateurs — ce qui
   pousserait la barre de saisie (.composer) hors de la zone visible au lieu
   de rester en bas du panneau de chat. */
.chat-log{flex:1;min-height:0;overflow-y:auto;padding:20px 22px;display:flex;flex-direction:column;gap:16px}
.chat-log::-webkit-scrollbar{width:9px}
.chat-log::-webkit-scrollbar-thumb{background:#2a323d;border-radius:9px}
.msg{display:flex;gap:11px;max-width:90%;animation:pop .3s cubic-bezier(.2,.8,.3,1)}
@keyframes pop{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.msg .av{width:30px;height:30px;border-radius:9px;flex-shrink:0;display:grid;place-items:center;font-size:13px;font-weight:700}
.msg.prof .av{background:linear-gradient(135deg,var(--orange),#e2551f);color:#1a0d05}
.msg.eleve{align-self:flex-end;flex-direction:row-reverse}
.msg.eleve .av{background:linear-gradient(135deg,var(--cyan),#1f8f9e);color:#04222a}
.bubble{background:var(--panel-2);border:1px solid var(--line);padding:11px 14px;border-radius:13px;font-size:14.5px;min-width:0;overflow-x:auto}
.msg.prof .bubble{border-top-left-radius:4px}
.msg.eleve .bubble{border-top-right-radius:4px;background:rgba(62,207,224,.09);border-color:rgba(62,207,224,.25)}
.bubble p{margin:0 0 9px}
.bubble p:last-child{margin:0}
.bubble strong{color:var(--orange);font-weight:600}
.msg.eleve .bubble strong{color:var(--cyan)}
.bubble ul,.bubble ol{margin:6px 0;padding-left:20px}
.bubble li{margin:3px 0}
.bubble code{background:#0f1419;border:1px solid var(--line);border-radius:5px;padding:1px 5px;font-size:13px;font-family:ui-monospace,Menlo,monospace}
.bubble pre{background:#0f1419;border:1px solid var(--line);border-radius:9px;padding:11px 13px;overflow-x:auto;margin:9px 0}
.bubble pre code{background:none;border:none;padding:0}
.bubble table{border-collapse:collapse;margin:10px 0;font-size:13px;width:auto}
.bubble th,.bubble td{border:1px solid var(--line);padding:6px 11px;text-align:center}
.bubble th{background:#141a20;color:var(--txt-dim);font-weight:600;font-size:11.5px;letter-spacing:.05em}
.bubble svg{max-width:100%;height:auto;margin:9px 0;display:block}
.bubble hr{border:0;border-top:1px solid var(--line);margin:12px 0}
.bubble .katex{font-size:1.03em}
.bubble .katex-display{margin:12px 0;overflow-x:auto;overflow-y:hidden}
.tex-b{display:block;text-align:center;margin:12px 0;overflow-x:auto}
.tex-i{white-space:nowrap}

.typing{display:flex;align-items:center;gap:4px;padding:4px 2px}
/* Le mot qui accompagne les points pendant que Michel prepare sa reponse.
   Discret : c'est un signe de vie, pas une information. (02/09/2026) */
.typing-mot{margin-left:8px;font-size:12px;color:var(--txt-dim);opacity:.85}
.typing i{width:7px;height:7px;border-radius:50%;background:var(--txt-dim);animation:blink 1.2s infinite}
.typing i:nth-child(2){animation-delay:.2s}
.typing i:nth-child(3){animation-delay:.4s}
@keyframes blink{0%,60%,100%{opacity:.25;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}}
.err-box{
  border:1px solid rgba(248,113,122,.4);background:rgba(248,113,122,.08);
  border-radius:11px;padding:11px 14px;font-size:13.5px;color:#ffc4c8;
}
.err-box b{color:var(--red)}

/* Fin de séance sur plafond de dépense atteint : pas une panne, pas rouge. */
.limite-box{
  border:1px solid rgba(255,139,61,.35);background:rgba(255,139,61,.08);
  border-radius:11px;padding:11px 14px;font-size:13.5px;color:var(--txt,#e8ecf3);
}

/* ================= GRAPHE ================= */
.schema{margin:11px 0;border:1px solid var(--line);border-radius:11px;
  background:linear-gradient(180deg,#101519,#0c1013);padding:12px}
.schema-title{font-size:10.5px;letter-spacing:.12em;color:var(--txt-dim);margin-bottom:8px;
  display:flex;justify-content:space-between;gap:10px}
.schema-ctrl{display:flex;align-items:center;gap:11px;margin-top:10px;font-size:12px;color:var(--txt-dim)}
.schema-ctrl input[type=range]{flex:1;accent-color:var(--orange);height:4px}
.readout{display:flex;gap:10px;margin-top:9px;flex-wrap:wrap}
.readout div{background:#141a20;border:1px solid var(--line);border-radius:8px;padding:6px 11px;font-size:12px}
.readout span{color:var(--txt-dim);font-size:10.5px;display:block;letter-spacing:.06em}
.readout b{font-size:15px;font-weight:700}

/* ================= VIDÉO DE RAPPEL ================= */
.video-card{
  margin:11px 0;border:1px solid var(--line);border-radius:11px;
  overflow:hidden;background:#0c1013;cursor:pointer;max-width:360px;
}
.video-card.lue{cursor:default}
.video-thumb-wrap{position:relative}
.video-thumb-wrap::before{
  content:"▶";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:52px;height:52px;border-radius:50%;background:var(--orange);color:#1a0d05;
  display:grid;place-items:center;font-size:17px;pointer-events:none;
  box-shadow:0 4px 18px rgba(0,0,0,.4);
}
.video-thumb{display:block;width:100%;aspect-ratio:16/9;object-fit:cover;background:#141a20}
.video-thumb-playlist{display:grid;place-items:center;color:var(--txt-dim);font-size:26px}
.video-title{padding:9px 12px;font-size:12.5px;color:var(--txt)}
.video-title small{display:block;color:var(--txt-dim);font-size:10.5px;margin-top:2px}
.video-card iframe{display:block;width:100%;aspect-ratio:16/9;border:0}

/* ================= COMPOSER ================= */
.composer{border-top:1px solid var(--line);padding:12px 16px;background:var(--panel)}
.quick{display:flex;gap:7px;margin-bottom:10px;flex-wrap:wrap}
.chip{font-size:12px;padding:6px 12px;border-radius:999px;cursor:pointer;
  border:1px solid var(--line);background:var(--panel-2);color:var(--txt-dim);transition:.15s}
.chip:hover{color:var(--txt);border-color:var(--orange);background:rgba(255,139,61,.1)}
.composer-row{display:flex;gap:9px;align-items:flex-end}
.composer textarea{
  flex:1;resize:none;background:var(--panel-2);border:1px solid var(--line);color:var(--txt);
  border-radius:11px;padding:11px 13px;font-family:inherit;font-size:14.5px;
  min-height:44px;max-height:150px;outline:none;
}
.composer textarea:focus{border-color:rgba(255,139,61,.5)}
.send{width:44px;height:44px;border-radius:11px;border:none;cursor:pointer;flex-shrink:0;
  background:linear-gradient(135deg,var(--orange),#e2551f);color:#1a0d05;display:grid;place-items:center;transition:.15s}
.send:hover{filter:brightness(1.12)}
.send:disabled{opacity:.4;cursor:default}

.mic{width:44px;height:44px;border-radius:11px;flex-shrink:0;cursor:pointer;transition:.15s;
  background:var(--panel-2);border:1px solid var(--line);color:var(--txt-dim);display:grid;place-items:center}
.mic:hover{color:var(--txt);border-color:rgba(255,139,61,.4)}
.mic.actif{background:#c0392b;border-color:#c0392b;color:#fff;animation:mic-pulse 1.4s ease-in-out infinite}
.mic:disabled{opacity:.4;cursor:default}
@keyframes mic-pulse{0%,100%{box-shadow:0 0 0 0 rgba(192,57,43,.5)}50%{box-shadow:0 0 0 8px rgba(192,57,43,0)}}

/* ================= PHOTO DU BROUILLON (20/08/2026) ================= */
.photo-user{display:flex;flex-direction:column;gap:6px}
.photo-user img{max-width:220px;max-height:220px;border-radius:10px;border:1px solid var(--line);display:block}
.photo-statut{font-size:11px;color:var(--txt-dim)}

/* ================= TABLEAU BLANC DISTANT (20/08/2026) =================
   20/08/2026, plus tard le même soir : la fenêtre à ouvrir à la demande est
   retirée, remplacée par une carte permanente dans le rail droit (voir
   index.html, #cardTableau) — un jeton est créé dès le début de chaque
   séance (app.js, demarrer()), le code affiché est donc toujours valide. */
.tableau-qr{background:#fff;border-radius:10px;padding:8px;display:flex;align-items:center;justify-content:center;
  min-width:140px;min-height:140px}
.tableau-etat{margin:0;font-size:12px;color:var(--txt-dim)}
.tableau-etat.actif{color:#4ade80}
.tableau-etat.err{color:#f8717a}
.tab-copier{border:1px solid var(--line);background:var(--panel-2);color:var(--txt-dim);border-radius:8px;
  padding:6px 12px;font-size:11px;cursor:pointer}
.tab-copier:hover{border-color:rgba(255,139,61,.4);color:var(--txt)}

/* ================= RAIL DROIT ================= */
.gauge-wrap{display:grid;place-items:center;padding:4px 0 2px}
.gauge-val{font-size:30px;font-weight:800;line-height:1}
.gauge-pc{font-size:15px;font-weight:600;margin-left:2px;color:var(--txt-dim)}
.gauge-sub{font-size:9.5px;color:var(--txt-dim);letter-spacing:.09em;margin-top:4px;line-height:1.35}
.gauge-detail{font-size:12px;color:var(--txt);margin-top:5px}
.gauge-note{font-size:9.5px;color:#6c7686;letter-spacing:.09em;margin-top:2px;text-transform:uppercase}
.next{font-size:13px;color:var(--txt-dim);line-height:1.55}
.next b{color:var(--txt)}

/* ================= TOASTS ================= */
.toasts{position:fixed;right:20px;bottom:20px;display:flex;flex-direction:column;gap:9px;z-index:60}
.toast{padding:11px 16px;border-radius:11px;font-size:13.5px;font-weight:600;
  background:var(--panel-2);border:1px solid var(--line);box-shadow:0 10px 30px rgba(0,0,0,.5);
  animation:slide .4s cubic-bezier(.2,.8,.3,1);display:flex;align-items:center;gap:9px}
@keyframes slide{from{opacity:0;transform:translateX(30px)}to{opacity:1;transform:none}}
.toast.xp{border-color:rgba(167,139,250,.45);color:var(--violet)}
.toast.badge-t{border-color:rgba(251,191,36,.45);color:var(--yellow)}
.toast.auto{border-color:rgba(62,207,224,.45);color:var(--cyan)}
.toast.err{border-color:rgba(248,113,122,.45);color:var(--red)}
.toast.ok{border-color:rgba(74,222,128,.45);color:var(--green)}

.sync{font-size:10.5px;color:var(--txt-dim);display:flex;align-items:center;gap:6px}
.sync i{width:7px;height:7px;border-radius:50%;background:var(--green);display:inline-block}
.sync.ko i{background:var(--red)}

@media(max-width:1180px){
  .wrap{grid-template-columns:1fr}
  .chat{height:min(72vh,640px);order:-1;min-height:0}  /* 09/09/2026: le plancher de 440px empechait la conversation de retrecir, la barre de saisie tombait hors ecran */
}
@media(max-width:640px){
  .wrap{padding:12px}
  .topbar{gap:14px;padding:12px 14px}
  .chat-log{padding:14px}
  .msg{max-width:97%}
}


/* --- les trois paliers : des pastilles, pas une barre chiffrée -------------
   Une barre en pourcentage laisserait croire à une précision qu'on n'a pas.
   Trois pastilles disent exactement ce qu'on sait : où en est le module. */
.pastilles { display: flex; gap: 3px; align-items: center; }
.pastilles .pas {
  width: 9px; height: 9px; border-radius: 50%;
  transition: background .5s cubic-bezier(.2,.7,.3,1);
}


/* --- L'EXPLORATEUR DE PROGRAMME ------------------------------------------- */
.prog-fond {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(8,10,13,.78); backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.prog-boite {
  width: min(920px, 100%); max-height: 88vh; display: flex; flex-direction: column;
  background: var(--carte, #151a21); border: 1px solid var(--bord, #2a323d);
  border-radius: 14px; overflow: hidden; box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
.prog-tete {
  display: flex; align-items: flex-start; justify-content: space-between;
  padding: 15px 18px; border-bottom: 1px solid var(--bord, #2a323d);
}
.prog-tete h2 { margin: 0; font-size: 12px; letter-spacing: .16em; }
.prog-tete span { font-size: 11px; color: var(--txt-dim, #8b96a8); }
.prog-fermer {
  all: unset; cursor: pointer; font-size: 24px; line-height: 1;
  color: var(--txt-dim, #8b96a8); padding: 0 4px;
}
.prog-fermer:hover { color: var(--txt, #e8ecf3); }
.prog-chercher {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 18px; border-bottom: 1px solid var(--bord, #2a323d);
}
.prog-chercher input {
  flex: 1; all: unset; box-sizing: border-box; padding: 9px 12px;
  background: #1b222b; border: 1px solid var(--bord, #2a323d); border-radius: 8px;
  color: var(--txt, #e8ecf3); font-size: 13px;
}
.prog-chercher input:focus { border-color: var(--accent, #ff8b3d); }
.prog-chercher span { font-size: 11px; color: var(--txt-dim, #8b96a8); white-space: nowrap; }
.prog-corps { overflow-y: auto; padding: 6px 18px 18px; }

/* --- l'arborescence -------------------------------------------------------
   <details> natif : pliage sans état JavaScript dans le DOM, accessible au
   clavier, et le navigateur gère l'animation. On masque le triangle par
   défaut (deux syntaxes : WebKit et la standard) pour poser le nôtre. */
.prog-partie, .prog-sp { margin: 0; }
.prog-partie > summary, .prog-sp > summary { cursor: pointer; list-style: none; }
.prog-partie > summary::-webkit-details-marker,
.prog-sp > summary::-webkit-details-marker { display: none; }
.prog-chev {
  flex-shrink: 0; width: 12px; color: var(--txt-dim, #8b96a8);
  transition: transform .12s ease; display: inline-block;
}
.prog-chev::before { content: "\25B8"; }                 /* ▸ */
details[open] > summary > .prog-chev { transform: rotate(90deg); }

.prog-partie { margin-top: 16px; }
.prog-partie-tete {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 8px; border-radius: 8px;
}
.prog-partie-tete:hover { background: #171d25; }
.prog-partie-tete h3 {
  margin: 0; font-size: 11px; letter-spacing: .13em; flex: 1;
  color: var(--accent, #ff8b3d); text-transform: uppercase;
}
.prog-partie-tete h3 em { font-style: normal; color: var(--txt-dim, #8b96a8); letter-spacing: .06em; }
.prog-partie-resume {
  font-size: 10.5px; color: var(--txt-dim, #8b96a8); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.prog-partie-corps { padding: 4px 0 2px 21px; }

.prog-sp {
  border: 1px solid var(--bord, #2a323d); border-radius: 10px;
  margin-bottom: 7px; background: #131820;
}
.prog-sp-tete {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 13px; flex-wrap: wrap;
}
.prog-sp-tete:hover { background: #161c25; border-radius: 10px; }
.prog-sp-nom { flex: 1; font-size: 13px; }
.prog-sp-tete i {
  font-style: normal; font-size: 10.5px; color: var(--txt-dim, #8b96a8);
  margin-right: 8px; font-variant-numeric: tabular-nums;
}
.prog-sp-corps { padding: 0 13px 11px; }
.prog-etat { font-size: 11px; white-space: nowrap; }

/* les contenus du programme : ce qu'il faut savoir, avant ce qu'il faut
   savoir FAIRE. Discret — on ne choisit pas un contenu, on choisit une
   capacité. */
.prog-contenus {
  padding: 8px 0 2px; font-size: 12px; color: var(--txt-dim, #8b96a8);
  line-height: 1.5;
}
.prog-contenus b {
  display: block; font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase;
  color: #6c7686; margin-bottom: 4px; font-weight: 600;
}
.prog-contenus span { display: block; padding: 1.5px 0 1.5px 12px; position: relative; }
.prog-contenus span::before { content: "·"; position: absolute; left: 3px; }

.prog-cap {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 6px 0; border-top: 1px solid #1e242c; font-size: 12.5px; line-height: 1.45;
}
.prog-go {
  all: unset; cursor: pointer; flex-shrink: 0;
  padding: 5px 10px; border-radius: 7px; font-size: 11px;
  background: #232c37; color: var(--txt, #e8ecf3); white-space: nowrap;
}
.prog-go:hover { background: var(--accent, #ff8b3d); color: #1a0d05; }
.prog-go-module {
  display: block; width: 100%; box-sizing: border-box; text-align: center;
  margin: 2px 0 4px; background: rgba(255,139,61,.12); color: var(--accent, #ff8b3d);
}
.prog-actions-module { display: flex; gap: 8px; margin: 2px 0 4px; }
.prog-actions-module .prog-go-module { flex: 1; margin: 0; }
.prog-video-btn {
  all: unset; cursor: pointer; flex-shrink: 0; box-sizing: border-box;
  padding: 5px 12px; border-radius: 7px; font-size: 11px; white-space: nowrap;
  background: rgba(62,207,224,.12); color: var(--cyan, #3ecfe0);
}
.prog-video-btn:hover { background: rgba(62,207,224,.25); }
.prog-video-slot:empty { display: none; }
.prog-video-slot .video-card { max-width: none; margin: 0 0 10px; }
.prog-plier {
  all: unset; cursor: pointer; flex-shrink: 0; white-space: nowrap;
  padding: 6px 10px; border-radius: 7px; font-size: 10.5px;
  color: var(--txt-dim, #8b96a8); border: 1px solid var(--bord, #2a323d);
}
.prog-plier:hover { color: var(--txt, #e8ecf3); border-color: #3c4653; }
.prog-pied {
  padding: 12px 18px; border-top: 1px solid var(--bord, #2a323d);
  font-size: 11px; color: var(--txt-dim, #8b96a8); line-height: 1.5;
}
.prog-pied b { color: #f8717a; }

/* --- SAUVEGARDES & HISTORIQUE (admin) --------------------------------------- */
.sauv-assiduite {
  display: flex; gap: 18px; flex-wrap: wrap; font-size: 12.5px;
  color: var(--txt-dim, #8b96a8); padding: 4px 2px 2px;
}
.sauv-assiduite b { color: var(--txt, #e8ecf3); }
.sauv-titre {
  margin: 18px 0 8px; font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--txt-dim, #8b96a8);
}
.sauv-titre:first-child { margin-top: 6px; }
#sauvegardesCorps table {
  border-collapse: collapse; width: 100%; font-size: 12.5px; margin-bottom: 6px;
}
#sauvegardesCorps th, #sauvegardesCorps td {
  border: 1px solid var(--bord, #2a323d); padding: 7px 10px; text-align: left;
}
#sauvegardesCorps th {
  background: #141a20; color: var(--txt-dim, #8b96a8); font-weight: 600;
  font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
}
.sauv-restaurer {
  all: unset; cursor: pointer; padding: 4px 10px; border-radius: 7px; font-size: 11.5px;
  color: var(--accent, #ff8b3d); border: 1px solid rgba(255,139,61,.45);
}
.sauv-restaurer:hover { background: rgba(255,139,61,.14); }
.sauv-marquee { background: rgba(255,139,61,.06); }
.sauv-marquee td:nth-child(2) { color: var(--accent, #ff8b3d); font-size: 11.5px; }

/* --- CONFIRMATION (remplace confirm() natif) -------------------------------
   Même famille visuelle que .prog-fond/.prog-boite, en plus petit et
   au-dessus de tout (z-index supérieur à .prog-fond, une confirmation peut
   se déclencher depuis une modale déjà ouverte, ex. restaurer une sauvegarde). */
.confirm-fond {
  position: fixed; inset: 0; z-index: 700;
  background: rgba(8,10,13,.78); backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.confirm-boite {
  width: min(380px, 100%);
  background: var(--carte, #151a21); border: 1px solid var(--bord, #2a323d);
  border-radius: 14px; padding: 20px 20px 16px;
  box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
.confirm-boite p {
  margin: 0 0 18px; font-size: 13.5px; line-height: 1.5;
  color: var(--txt, #e8ecf3); white-space: pre-line;
}
.confirm-actions { display: flex; justify-content: flex-end; gap: 10px; }
.confirm-annuler, .confirm-ok {
  all: unset; cursor: pointer; padding: 8px 16px; border-radius: 8px;
  font-size: 12.5px; font-weight: 600;
}
.confirm-annuler {
  color: var(--txt-dim, #8b96a8); border: 1px solid var(--bord, #2a323d);
}
.confirm-annuler:hover { color: var(--txt, #e8ecf3); border-color: var(--txt-dim, #8b96a8); }
.confirm-ok { background: var(--accent, #ff8b3d); color: #1a0d05; }
.confirm-ok:hover { filter: brightness(1.08); }

/* --- L'ALBUM --------------------------------------------------------------- */
.pill-alerte { background: rgba(255,139,61,.16) !important; color: var(--accent, #ff8b3d); }
.alb-boite { width: min(1040px, 100%); }
.alb-jetons {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 18px; background: rgba(255,139,61,.1);
  border-bottom: 1px solid var(--bord, #2a323d); font-size: 13px;
}
.alb-jetons b { color: var(--accent, #ff8b3d); font-size: 15px; }
.alb-jetons button {
  all: unset; cursor: pointer; margin-left: auto;
  padding: 7px 16px; border-radius: 8px;
  background: var(--accent, #ff8b3d); color: #1a0d05; font-size: 12.5px; font-weight: 600;
}
.alb-theme { margin-top: 20px; }
.alb-theme-tete { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px; }
.alb-theme-tete h3 { margin: 0; font-size: 11.5px; letter-spacing: .13em; text-transform: uppercase; }
.alb-theme-tete span { font-size: 11px; color: var(--txt-dim, #8b96a8); }
.alb-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 10px; }
.alb-case {
  position: relative; aspect-ratio: 3/4; border-radius: 8px; overflow: hidden;
  background: #131820; border: 1px solid #232c37;
  display: flex; align-items: center; justify-content: center;
}
.alb-case.eue { cursor: pointer; }
.alb-case.eue:hover { transform: translateY(-2px); transition: transform .15s; }
.alb-case img { width: 100%; height: 100%; object-fit: cover; }
.alb-num {
  position: absolute; top: 6px; left: 7px; z-index: 2;
  font-size: 11px; color: #e8ecf3; opacity: .75;
  background: rgba(8,10,13,.6); border-radius: 4px; padding: 1px 4px;
}
.alb-vide { font-size: 22px; color: #2a323d; }
.alb-nom {
  position: absolute; bottom: 0; left: 0; right: 0; z-index: 2;
  font-size: 11.5px; line-height: 1.3; padding: 18px 8px 7px;
  background: linear-gradient(transparent, rgba(8,10,13,.92));
  color: #e8ecf3;
}

/* --- la fiche et le quiz --------------------------------------------------- */
@keyframes albOuvre {
  from { opacity: 0; transform: scale(.9) translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.quiz-boite {
  animation: albOuvre .32s cubic-bezier(.2,.8,.3,1);
  width: min(620px, 100%); max-height: 88vh; overflow-y: auto;
  background: var(--carte, #151a21); border: 1px solid var(--bord, #2a323d);
  border-radius: 14px; box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
.alb-fiche img { width: 100%; display: block; }
.alb-fiche-corps { padding: 16px 18px; }
.alb-fiche-tete { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.alb-fiche-tete h3 { margin: 0 0 4px; font-size: 16px; }
.alb-rarete { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; border: 1px solid; border-radius: 20px; padding: 3px 9px; white-space: nowrap; }
.alb-fiche-corps p { font-size: 13px; line-height: 1.55; color: var(--txt, #e8ecf3); margin: 10px 0; }
.alb-fun { color: var(--txt-dim, #8b96a8) !important; font-style: italic; }
.alb-specs { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 12px; }
.alb-specs th { text-align: left; color: var(--txt-dim, #8b96a8); font-weight: 400; padding: 4px 0; }
.alb-specs td { text-align: right; font-variant-numeric: tabular-nums; padding: 4px 0; }
.alb-credit { margin-top: 12px; font-size: 10px; color: #5c6672; }
.quiz-corps { padding: 20px; }
.quiz-titre { font-size: 13px; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-dim, #8b96a8); margin-bottom: 14px; text-align: center; }
.quiz-photo { width: 100%; border-radius: 10px; display: block; transition: filter .5s; }
/* Le flou du premier essai. 9 px effaçaient la silhouette et le quiz
   devenait un tirage au sort ; 5 px cachent les inscriptions et les détails
   sans supprimer la forme. C'est le seul endroit où régler cette valeur. */
.quiz-photo.floutee { filter: blur(5px); }
.quiz-choix { display: grid; gap: 7px; margin-top: 16px; }
.quiz-choix button {
  all: unset; cursor: pointer; text-align: center; padding: 11px;
  border-radius: 9px; background: #1f2731; font-size: 13px;
}
.quiz-choix button:hover { background: var(--accent, #ff8b3d); color: #1a0d05; }
.quiz-gagnee { padding: 14px 18px 0; font-size: 13px; color: #4ade80; }
.quiz-actions { display: flex; gap: 8px; padding: 14px 18px 18px; }
.quiz-actions button {
  all: unset; cursor: pointer; flex: 1; text-align: center; padding: 10px;
  border-radius: 9px; background: #232c37; font-size: 12.5px;
}
.quiz-actions button:first-child { background: var(--accent, #ff8b3d); color: #1a0d05; font-weight: 600; }


/* --- la fiche en grand ------------------------------------------------------ */
.alb-fiche img { width: 100%; display: block; max-height: 46vh; object-fit: cover; }
.alb-fiche-corps h3 { font-size: 20px; }
.alb-fiche-corps p { font-size: 14px; }
.alb-fun {
  border-left: 2px solid var(--accent, #ff8b3d); padding-left: 12px;
  margin-left: 0; color: #cfd6e0 !important; font-style: normal !important;
}
.alb-fun b { color: var(--accent, #ff8b3d); font-weight: 600; display: block;
  font-size: 10px; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 3px; }
.alb-specs { margin-top: 14px; }
.alb-specs th, .alb-specs td { padding: 6px 0; border-top: 1px solid #1e242c; font-size: 13px; }


/* --- LES DEUX NIVEAUX ------------------------------------------------------
   Maceo révise la seconde et attaque la première. Le niveau en cours est
   déplié, l'autre replié : dix-neuf modules d'un coup, c'est décourageant. */
.niv { margin-bottom: 10px; }
.niv-tete {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 7px 0 8px; cursor: pointer; user-select: none;
  border-bottom: 1px solid var(--bord, #2a323d); margin-bottom: 8px;
}
.niv-tete b { font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; }
.niv-tete em { font-style: normal; font-size: 10.5px; color: var(--txt-dim, #8b96a8); }
.niv-tete::before {
  content: "▾"; margin-right: 7px; font-size: 10px; color: var(--txt-dim, #8b96a8);
  transition: transform .18s;
}
.niv.replie .niv-tete::before { content: "▸"; }
.niv-compte { font-size: 10.5px; color: var(--txt-dim, #8b96a8); }
.niv.replie .niv-corps { display: none; }

.prog-onglets {
  display: flex; gap: 6px; padding: 11px 18px 0;
}
.prog-onglets button {
  all: unset; cursor: pointer; padding: 7px 14px; border-radius: 8px 8px 0 0;
  font-size: 12px; color: var(--txt-dim, #8b96a8); background: #131820;
}
.prog-onglets button.actif {
  background: var(--carte, #151a21); color: var(--accent, #ff8b3d);
  box-shadow: inset 0 2px 0 var(--accent, #ff8b3d);
}


/* --- le calendrier (28/08/2026) ------------------------------------------
   Le panneau réutilise les classes du programme et des sauvegardes ; il n a
   besoin en propre que du petit formulaire d ajout, réservé à Sylvain. */
.cal-titre{margin:20px 0 8px;font-size:12px;letter-spacing:.09em;text-transform:uppercase;opacity:.65}
.cal-titre:first-child{margin-top:0}
.cal-ajout{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:12px 0 4px}
.cal-ajout input{padding:6px 9px;border-radius:4px;border:1px solid rgba(128,128,128,.45);background:transparent;color:inherit;font:inherit;font-size:13px}
.cal-ajout input[type=text]{min-width:150px}
.cal-ajout button{cursor:pointer}


/* --- la grille du calendrier (28/08/2026) -------------------------------- */
.cal-nav{display:flex;align-items:center;gap:8px;margin-bottom:12px}
.cal-nav b{flex:1;text-transform:capitalize;font-size:15px}
.cal-nav button,.cal-ajout button{background:var(--panel-2);border:1px solid var(--line);color:var(--txt);border-radius:8px;padding:5px 11px;cursor:pointer;font:inherit;font-size:13px}
.cal-nav button:hover,.cal-ajout button:hover{border-color:var(--cyan)}
.cal-jours{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;margin-bottom:5px}
.cal-jours span{text-align:center;font-size:11px;letter-spacing:.08em;color:var(--txt-dim)}
.cal-grille{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}
.cal-case{min-height:64px;background:var(--panel-2);border:1px solid var(--line);border-radius:9px;padding:5px;display:flex;flex-direction:column;gap:3px;align-items:flex-start;cursor:pointer;color:var(--txt);font:inherit;text-align:left;overflow:hidden}
.cal-case:hover{border-color:var(--cyan)}
.cal-num{font-size:12px;color:var(--txt-dim);font-variant-numeric:tabular-nums}
.cal-dehors{opacity:.3}
.cal-auj{border-color:var(--orange)}
.cal-auj .cal-num{color:var(--orange);font-weight:700}
.cal-choisi{border-color:var(--cyan);box-shadow:0 0 0 1px var(--cyan) inset}
.cal-ep{font-size:10px;background:rgba(255,139,61,.18);color:var(--orange);border-radius:5px;padding:1px 5px;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-detail{margin-top:14px;border-top:1px solid var(--line);padding-top:12px}
.cal-detail-titre{font-size:11.5px;letter-spacing:.07em;color:var(--txt-dim);margin-bottom:8px}
.cal-item{background:var(--panel-2);border:1px solid var(--line);border-radius:9px;padding:8px 11px;margin-bottom:6px;font-size:13.5px}
.cal-note{color:var(--txt-dim);font-size:12.5px;margin-top:6px;line-height:1.45}
.cal-vide{color:var(--txt-dim);font-style:italic;font-size:13px}
.cal-suite{margin-top:16px}


/* --- contenu des cases : sujet travaille et teinte du jour (28/08/2026) --- */
.cal-case{min-height:78px;justify-content:flex-start}
.cal-tete{display:flex;justify-content:space-between;align-items:baseline;width:100%;gap:4px}
.cal-min{font-size:9.5px;color:var(--txt-dim);font-variant-numeric:tabular-nums;white-space:nowrap}
.cal-mod{font-size:9.5px;line-height:1.4;width:100%;border-radius:4px;padding:1px 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-mod.bien{background:rgba(74,222,128,.16);color:var(--green)}
.cal-mod.moyen{background:rgba(251,191,36,.16);color:var(--yellow)}
.cal-mod.dur{background:rgba(248,113,122,.16);color:var(--red)}
.cal-plus{font-size:9.5px;color:var(--txt-dim);padding-left:4px}
.cal-legende{display:flex;flex-wrap:wrap;gap:14px;margin-top:10px;font-size:11px;color:var(--txt-dim)}
.cal-legende span{display:flex;align-items:center;gap:5px}
.cal-pt{width:9px;height:9px;border-radius:3px;display:inline-block}
.cal-pt.bien{background:var(--green)}
.cal-pt.moyen{background:var(--yellow)}
.cal-pt.dur{background:var(--red)}
.cal-pt.ep{background:var(--orange)}


/* --- la fiche detaillee dun jour, cote admin (28/08/2026) --- */
.cal-mesures{margin-top:9px;display:grid;gap:3px}
.cal-mesure{display:flex;gap:7px;align-items:baseline;font-size:12.5px}
.cal-fl{width:11px;flex:0 0 11px;font-size:10px;text-align:center}
.cal-fl.bien{color:var(--green)}
.cal-fl.moyen{color:var(--yellow)}
.cal-fl.dur{color:var(--red)}
.cal-chiffre{color:var(--txt-dim);font-size:12px;font-variant-numeric:tabular-nums}

/* --- la grille ne setire plus en hauteur (28/08/2026) ---------------------
   Le panneau donne toute sa hauteur a la grille : sur un mois vide, les six
   rangees setiraient jusqua repousser la legende et le detail hors de lecran.
   Une hauteur de rangee fixe garde la grille compacte et laisse la place a ce
   qui vient dessous. */
.cal-grille{grid-auto-rows:78px;align-content:start}
.cal-case{min-height:0;height:100%}
.cal-legende{padding-bottom:4px}


/* --- effacer une epreuve (28/08/2026) --- */
.cal-avec-croix{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.cal-suppr{background:none;border:1px solid var(--line);color:var(--txt-dim);border-radius:6px;width:24px;height:24px;line-height:1;cursor:pointer;font-size:15px;flex:0 0 24px}
.cal-suppr:hover{border-color:var(--red);color:var(--red)}

/* --- les notes de Maceo (28/08/2026) --- */
.notes-saisie{display:flex;flex-direction:column;gap:8px;margin-bottom:18px}
.notes-saisie textarea{width:100%;background:var(--panel-2);border:1px solid var(--line);border-radius:9px;color:var(--txt);font:inherit;font-size:14px;padding:10px 12px;resize:vertical}
.notes-saisie textarea:focus{outline:none;border-color:var(--cyan)}
.notes-saisie button{align-self:flex-start;background:var(--panel-2);border:1px solid var(--line);color:var(--txt);border-radius:8px;padding:6px 13px;cursor:pointer;font:inherit;font-size:13px}
.notes-saisie button:hover{border-color:var(--cyan)}
.note-tete{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.note-lue{font-size:11px;color:var(--txt-dim)}
.note-neuve{font-size:11px;color:var(--orange)}
.note-actions{margin-left:auto;display:flex;gap:6px}
.note-btn{background:none;border:1px solid var(--line);color:var(--txt-dim);border-radius:6px;padding:2px 8px;cursor:pointer;font:inherit;font-size:11px}
.note-btn:hover{border-color:var(--cyan);color:var(--txt)}
.note-texte{font-size:14px;line-height:1.5;white-space:pre-wrap}

/* --- le detail du jour se remarque (28/08/2026) --- */
.cal-detail-plein{border-top:2px solid var(--cyan);background:rgba(62,207,224,.04)}

/* 28/08/2026 - depuis le retrait des « pannes ouvertes », la carte des
   modules flottait en haut dune colonne a moitie vide. Elle prend
   desormais toute la hauteur, et la liste respire au lieu de se serrer. */
.colonne-gauche{display:flex;flex-direction:column;gap:18px}
.colonne-gauche > .card{flex:1 1 auto;display:flex;flex-direction:column;min-height:0}
.colonne-gauche > .card #benches{flex:1 1 auto;max-height:none}

/* La demande deposee pendant une seance : visible, mais discrete. Ce n est
   pas une parole de Maceo, c est un geste — il merite un autre traitement
   que sa bulle habituelle (29/08/2026). */
.demande-note{
  display:inline-flex;align-items:center;gap:8px;font-size:12.5px;
  color:var(--orange);background:rgba(255,139,61,.10);
  border:1px solid rgba(255,139,61,.32);border-radius:9px;padding:7px 12px;
}

/* ==========================================================================
   LA CARTE (29/08/2026, v2)
   --------------------------------------------------------------------------
   Une seule teinte porte letat dun module : eteint, cercle, plein,
   incandescent. La v1 etait illisible — traits en travers des mots, compte a
   rebours pose sur un module, dix-neuf noeuds relies en plat de spaghettis.
   Ici : etiquettes sur fond plein, bandeau separe pour les chiffres, et tout
   ce qui ne concerne pas le module choisi seffface.
   -------------------------------------------------------------------------- */
.ca-cadre{display:grid;grid-template-columns:minmax(0,1fr) 268px;min-height:620px}
.ca-gauche{display:flex;flex-direction:column;border-right:1px solid var(--line);min-width:0}

.ca-bandeau{
  display:flex;align-items:center;gap:22px;padding:14px 20px;
  border-bottom:1px solid var(--line);flex-shrink:0;
}
.ca-jauge{display:flex;align-items:center;gap:11px;font-size:10px;letter-spacing:.14em;color:var(--txt-dim)}
.ca-jauge i{width:132px;height:4px;border-radius:99px;background:#20272f;display:block;overflow:hidden}
.ca-jauge i b{display:block;height:100%;border-radius:99px;background:linear-gradient(90deg,#ffb27a,var(--orange))}
.ca-chiffre{color:#ffb27a;font-variant-numeric:tabular-nums;letter-spacing:.04em}
.ca-encours{font-size:11px;color:var(--txt-dim)}
.ca-echeance{margin-left:auto;display:flex;align-items:baseline;gap:11px}
.ca-echeance b{font-size:23px;font-weight:800;letter-spacing:-.03em;color:var(--orange);line-height:1}
.ca-echeance span{font-size:11px;color:var(--txt-dim)}

/* Une teinte a peine perceptible separe les deux annees : lannee qui commence
   est plus froide, le socle de seconde plus chaud. Assez pour que loeil situe
   les deux zones sans y penser, trop peu pour concurrencer lorange, qui reste
   la seule couleur porteuse de sens (letat dun module). */
.ca-scene{
  position:relative;flex:1;min-height:560px;overflow:hidden;
  background:
    radial-gradient(600px 300px at 72% 22%,rgba(255,139,61,.07),transparent 62%),
    radial-gradient(520px 300px at 22% 84%,rgba(255,139,61,.05),transparent 60%),
    linear-gradient(to bottom,
      rgba(126,163,224,.09) 0 49%,
      rgba(126,163,224,.03) 53%,
      rgba(255,168,92,.045) 55%,
      rgba(255,168,92,.075) 62% 100%);
}
/* pointer-events:none, sinon ce calque avale tous les clics « dans le vide »
   et on ne peut plus deselectionner un module (29/08/2026). */
.ca-liens{position:absolute;inset:0;width:100%;height:100%;overflow:visible;fill:none;pointer-events:none}
/* 29/08/2026 - a 5 % dopacite les traits etaient invisibles a lecran : ce
   qui se lisait bien sur ma capture ne se voyait pas du tout chez Sylvain. */
.ca-lien{stroke:rgba(214,226,240,.20);stroke-width:1.1;transition:stroke .2s,opacity .2s}
.ca-lien.vif{stroke:rgba(255,139,61,.62);stroke-width:1.6}
.ca-scene.cible .ca-lien{opacity:.28}
.ca-scene.cible .ca-lien.lie{opacity:1;stroke:rgba(255,139,61,.85);stroke-width:1.8}

.ca-horizon{position:absolute;left:0;right:0;top:53.5%;border-top:1px dashed rgba(255,255,255,.11)}
.ca-bande-nom{
  position:absolute;left:16px;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:#4d5665;pointer-events:none;
}
.ca-bande-haut{top:12px;color:#6f80a0}
.ca-bande-bas{top:53.5%;margin-top:10px;color:#94795f}

.ca-noeud{
  /* 29/08/2026 — les traits partaient du centre du BOUTON, cest-a-dire entre
     la perle et son etiquette : ils sarretaient a cote de la bulle au lieu
     de la viser. La perle fait 34 px, on decale donc de 17 px pour que son
     centre tombe exactement sur le point ou le trait aboutit. */
  position:absolute;transform:translate(-50%,-22px);width:136px;padding:0;border:0;
  background:none;font:inherit;cursor:pointer;display:flex;flex-direction:column;
  align-items:center;gap:8px;transition:opacity .2s ease;
}
.ca-noeud:focus-visible{outline:none}
.ca-noeud:focus-visible .ca-perle{box-shadow:0 0 0 3px rgba(255,255,255,.5)}
.ca-scene.cible .ca-noeud.loin{opacity:.3}

.ca-perle{
  position:relative;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  border:1.5px solid #313a47;background:#0f141a;color:#67717f;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9.5px;
  transition:transform .18s ease,box-shadow .25s ease;
}
.ca-noeud:hover .ca-perle{transform:scale(1.1)}
.ca-perle.en_cours{border-color:rgba(255,139,61,.8);background:#1c1309;color:#ffb27a}
.ca-perle.solide{
  border-color:transparent;color:#180a02;font-weight:600;
  background:radial-gradient(circle at 32% 30%,#ffc79b,var(--orange) 64%);
  box-shadow:0 0 20px rgba(255,139,61,.5);
}
.ca-perle.maitrise{
  border-color:transparent;color:#180a02;font-weight:600;
  background:radial-gradient(circle at 34% 30%,#fff,#ffc79b 72%);
  box-shadow:0 0 28px rgba(255,199,155,.7);
}
.ca-perle.rafraichir::after{
  content:"";position:absolute;top:-2px;right:-2px;width:9px;height:9px;border-radius:50%;
  background:var(--yellow);border:2px solid var(--panel);
}
/* La selection ne doit JAMAIS emprunter une couleur qui a deja un sens sur la
   carte. Elle etait orange : un module vert, une fois clique, devenait orange
   et semblait retomber en « en cours » (signale par Sylvain le 29/08/2026).
   Elle est desormais un anneau blanc — le blanc ne veut rien dire dautre que
   « cest celui-la que tu regardes » — et le halo garde, lui, la couleur du
   module pour que son etat reste lisible pendant quon le consulte.       */
.ca-noeud.actif .ca-perle{box-shadow:0 0 0 2px rgba(255,255,255,.92),0 0 26px var(--teinte,rgba(255,255,255,.25))}

/* Fond plein derriere chaque nom : sans lui, les traits passent au milieu
   des mots et plus rien ne se lit. */
.ca-etiq{
  font-size:11.5px;line-height:1.32;text-align:center;color:#8e99a7;
  background:rgba(13,16,21,.92);border-radius:7px;padding:3px 7px;
}
.ca-noeud.allume .ca-etiq{color:#d5dde7}
.ca-noeud.actif .ca-etiq{color:#fff;background:rgba(255,255,255,.15)}

.ca-detail{padding:20px 18px;display:flex;flex-direction:column;gap:15px;background:var(--panel-2);overflow-y:auto}
.ca-code{font-family:ui-monospace,monospace;font-size:10px;letter-spacing:.16em;color:var(--orange)}
.ca-detail h3{margin:7px 0 3px;font-size:18px;line-height:1.2;letter-spacing:-.01em}
.ca-partie{font-size:11.5px;color:var(--txt-dim)}
.ca-mesures{display:flex;flex-direction:column;gap:9px}
.ca-mesure{
  display:flex;justify-content:space-between;gap:14px;align-items:baseline;font-size:12px;
  color:var(--txt-dim);border-bottom:1px solid var(--line);padding-bottom:8px;
}
.ca-mesure b{color:var(--txt);text-align:right;font-weight:500;max-width:62%}
.ca-mesure b.feu{color:#ffb27a}
.ca-action{
  margin-top:auto;background:var(--orange);color:#150802;border:0;border-radius:9px;
  padding:12px 14px;font:inherit;font-weight:600;font-size:13.5px;cursor:pointer;
}
.ca-action:hover{background:#ffa063}
.ca-legende{
  display:flex;flex-direction:column;gap:7px;font-size:11px;color:var(--txt-dim);
  border-top:1px solid var(--line);padding-top:13px;
}
.ca-legende div{display:flex;align-items:center;gap:9px}
.ca-pt{width:12px;height:12px;border-radius:50%;border:1.5px solid #313a47;background:#0f141a;flex:0 0 auto}
.ca-pt.en_cours{border-color:rgba(255,139,61,.8)}
.ca-pt.solide{border-color:transparent;background:radial-gradient(circle at 32% 30%,#ffc79b,var(--orange) 64%)}
.ca-pt.maitrise{border-color:transparent;background:radial-gradient(circle at 34% 30%,#fff,#ffc79b 72%)}
@media (max-width:980px){
  .ca-cadre{grid-template-columns:minmax(0,1fr)}
  .ca-gauche{border-right:0;border-bottom:1px solid var(--line)}
}

/* La carte a besoin de place : dix-neuf modules dans 1040 px, ils se
   touchent. On elargit la boite pour ce panneau-la seulement, et on retire
   le rembourrage du corps — la carte gere ses propres marges. */
/* La carte occupait la moitie de lecran et se retrouvait coupee en bas :
   dix-neuf modules dans 560 px de haut, les etiquettes du dernier rang
   passaient sous le bord. Elle prend maintenant la hauteur disponible, et
   la scene setire avec elle — les positions etant en pourcentage, tout
   respire davantage sans quon touche a la mise en place (29/08/2026). */
#carteFond .prog-boite{width:min(1320px,96vw);height:min(94vh,1000px);max-height:94vh}
#carteFond .prog-corps{padding:0;overflow:hidden;flex:1;min-height:0}
#carteFond .ca-cadre{height:100%;min-height:0}
#carteFond .ca-gauche{min-height:0}
#carteFond .ca-scene{min-height:0}

.ca-tout{
  font:inherit;font-size:11px;color:var(--txt-dim);cursor:pointer;
  background:transparent;border:1px solid var(--line);border-radius:99px;padding:5px 12px;
  opacity:0;pointer-events:none;transition:opacity .2s,color .2s,border-color .2s;
}
.ca-tout.on{opacity:1;pointer-events:auto}
.ca-tout:hover{color:var(--txt);border-color:#39424f}

/* Pourquoi un module en porte un autre : le nom seul ne dit rien, la raison
   citee du programme, si. */
.ca-chaine h4{
  margin:0 0 8px;font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--txt-dim);font-weight:600;
}
.ca-maillon{
  border-left:2px solid rgba(255,139,61,.4);padding:0 0 0 10px;margin-bottom:10px;
}
.ca-maillon b{display:block;font-size:12.5px;font-weight:500;color:var(--txt);margin-bottom:2px}
.ca-maillon span{display:block;font-size:11px;line-height:1.45;color:var(--txt-dim)}

/* ==========================================================================
   LA TABLE DE CRAFT (29/08/2026)
   --------------------------------------------------------------------------
   Un module dont tous les appuis sont solides est PRET : on a les
   ingredients. Sa perle porte un anneau ouvert, comme une case encore vide
   quon peut remplir. Rien nest jamais verrouille — cest Michel qui decide
   de ce quon travaille, la carte ne fait que dire ce qui est mur.
   -------------------------------------------------------------------------- */
.ca-perle.pret{border-style:dashed;border-color:rgba(255,178,122,.85);color:#ffc79b}
@media (prefers-reduced-motion:no-preference){
  .ca-perle.pret{animation:ca-pret 3.4s ease-in-out infinite}
  @keyframes ca-pret{
    0%,100%{box-shadow:0 0 0 0 rgba(255,178,122,.35)}
    50%{box-shadow:0 0 0 6px rgba(255,178,122,0)}
  }
}
.ca-prets{
  font:inherit;font-size:11px;color:#ffc79b;cursor:pointer;
  background:rgba(255,139,61,.12);border:1px solid rgba(255,139,61,.4);
  border-radius:99px;padding:5px 12px;
}
.ca-prets:hover{background:rgba(255,139,61,.2)}

.ca-recette h4{
  margin:0 0 9px;font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--txt-dim);font-weight:600;
}
.ca-ingredient{display:flex;align-items:baseline;gap:8px;font-size:12px;margin-bottom:7px}
.ca-ingredient i{font-style:normal;font-size:11px;width:13px;flex:0 0 auto}
.ca-ingredient b{font-weight:500;color:var(--txt)}
.ca-ingredient span{margin-left:auto;font-size:10.5px;color:var(--txt-dim);white-space:nowrap}
.ca-ingredient.ok i{color:#ffb27a}
.ca-ingredient.manque i{color:#4d5665}
.ca-ingredient.manque b{color:var(--txt-dim)}
.ca-verdict{
  margin-top:10px;font-size:11.5px;padding:8px 11px;border-radius:8px;
}
.ca-verdict.pret{background:rgba(255,139,61,.12);color:#ffc79b}
.ca-verdict.attente{background:var(--panel);color:var(--txt-dim)}

/* Ce que le programme officiel met dans un module : la carte disait ou on en
   est, jamais de quoi il sagit (29/08/2026). */
.ca-contenu h4{
  margin:0 0 7px;font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--txt-dim);font-weight:600;
}
.ca-contenu ul{margin:0 0 4px;padding:0 0 0 15px;list-style:none}
.ca-contenu li{
  position:relative;font-size:11.5px;line-height:1.45;color:var(--txt);
  margin-bottom:6px;
}
.ca-contenu li::before{
  content:"";position:absolute;left:-13px;top:7px;width:4px;height:4px;
  border-radius:50%;background:rgba(255,139,61,.55);
}
.ca-contenu + .ca-contenu h4{margin-top:12px}

.ca-pt.pret{border-style:dashed;border-color:rgba(255,178,122,.85)}
.ca-pt.jaune{border-color:transparent;background:var(--yellow);width:9px;height:9px;margin:0 1px}
.ca-vide{
  font-size:11.5px;color:var(--txt-dim);font-style:italic;
  border-top:1px solid var(--line);padding-top:13px;margin-top:auto;
}

/* ==========================================================================
   LA BULLE QUI SE REMPLIT (29/08/2026)
   --------------------------------------------------------------------------
   Depuis que le seuil de « solide » suit le standard pedagogique, dix modules
   sur onze affichent « en cours » et se ressemblaient tous. Le liquide monte a
   proportion de ce quil reste a faire pour valider : deux exercices et vingt
   ne se peignent plus pareil, et le progres se voit dune semaine a lautre.
   La vague est deux formes arrondies plus larges que la bulle, ancrees en bas
   et animees en rotation : leur bord superieur ondule comme une surface.
   -------------------------------------------------------------------------- */
.ca-perle{overflow:hidden;background:#0b0f14}
.ca-perle b{position:relative;z-index:2;font-weight:500;font-family:inherit}
/* Le liquide et sa vague ont ete retires le 29/08/2026 : lanneau seul suffit,
   Sylvain le trouve plus calme. Le code est dans style.css.avant-... si on
   veut le revoir. La bulle redevient un simple disque teinte. */
.ca-perle{overflow:hidden;background:var(--panel-2,#1b222b)}
.ca-perle b{position:relative;z-index:2;font-weight:500;font-family:inherit}
/* les paliers ne peignent plus le fond : cest le liquide qui porte la couleur */
.ca-perle.solide,.ca-perle.maitrise{background:#0b0f14;border-color:transparent}
.ca-perle.solide{box-shadow:0 0 18px rgba(63,191,106,.42)}
.ca-perle.maitrise{box-shadow:0 0 28px rgba(126,231,150,.6)}
.ca-perle.en_cours{background:#0b0f14}
.ca-pt.solide{border-color:transparent;background:radial-gradient(circle at 32% 30%,#7ee796,#3fbf6a 62%)}
.ca-pt.maitrise{border-color:transparent;background:radial-gradient(circle at 34% 30%,#fff,#7ee796 70%)}

/* Le vert dit « valide », partout : dans la bulle comme dans le libelle. */
.ca-mesure b.vert{color:#7ee796}
.ca-mesure b.jaune{color:var(--yellow)}

/* ==========================================================================
   LANNEAU DE PROGRESSION (29/08/2026)
   --------------------------------------------------------------------------
   Idee de Sylvain : une jauge dans la bulle. Loeil compare des angles bien
   mieux que des hauteurs de liquide dans un cercle — lanneau donne donc la
   MESURE, et le liquide garde la SENSATION. La meme valeur, lue deux fois.
   Larc part du haut et se ferme dans le sens des aiguilles.
   -------------------------------------------------------------------------- */
.ca-anneau{
  position:relative;width:44px;height:44px;border-radius:50%;
  display:grid;place-items:center;flex:0 0 auto;
  background:conic-gradient(from -90deg,var(--teinte,#7a3e14) var(--p,0%),rgba(255,255,255,.07) 0);
  transition:background .5s ease;
}
.ca-anneau::after{
  content:"";position:absolute;inset:4px;border-radius:50%;background:var(--panel-2,#1b222b);
}
.ca-perle{z-index:1}
.ca-noeud:hover .ca-anneau{transform:scale(1.06)}
.ca-anneau{transition:background .5s ease,transform .18s ease}

/* La legende doit expliquer lanneau, pas seulement les six etats. Les lignes
   passent sur deux lignes de texte : on aligne les pastilles en haut. */
.ca-legende div{align-items:flex-start;line-height:1.45}
.ca-pt{margin-top:2px}
.ca-cle{padding-bottom:7px;margin-bottom:3px;border-bottom:1px solid var(--line)}
.ca-cle b{color:var(--txt);font-weight:600}
.ca-pt.anneau{
  width:14px;height:14px;border:0;position:relative;
  background:conic-gradient(from -90deg,#e08a3c 62%,rgba(255,255,255,.12) 0);
}
.ca-pt.anneau::after{content:"";position:absolute;inset:3px;border-radius:50%;background:var(--panel-2,#1b222b)}

/* Un lien entre deux modules acquis est vert. La carte montre alors le chemin
   deja consolide, et plus seulement les bulles une par une (29/08/2026,
   demande de Sylvain : « entre deux verts, le lien pourrait passer au vert »).
   La regle de survol reste plus specifique, donc on la redecline ici aussi. */
.ca-lien.acquis{stroke:rgba(63,191,106,.55);stroke-width:1.6}
.ca-scene.cible .ca-lien.acquis.lie{opacity:1;stroke:rgba(126,231,150,.9);stroke-width:1.9}

/* Six bulles en premiere contre treize en seconde : on lit spontanement un
   trou dans les donnees. Ce nen est pas un — Maceo ne prend pas la
   specialite maths. La bande le dit maintenant. (29/08/2026) */
.ca-bande-nom em{display:block;font-style:normal;text-transform:none;letter-spacing:0;
  font-size:10.5px;opacity:.72;margin-top:2px}

/* La bulle de la carte, en miniature : tableau de bord et programme parlent
   maintenant la meme langue quelle. Les trois pastilles disaient « un palier
   sur trois » — une echelle que le moteur nemploie plus. (30/08/2026) */
.ca-anneau.ca-mini{width:22px;height:22px}
.ca-anneau.ca-mini::after{inset:3px}
.ca-anneau.ca-mini .ca-perle{width:15px;height:15px;border-width:1.2px;box-shadow:none}
.ca-anneau.ca-mini .ca-perle.solide{box-shadow:0 0 10px rgba(63,191,106,.45)}
.ca-anneau.ca-mini .ca-perle.maitrise{box-shadow:0 0 12px rgba(126,231,150,.6)}
.ca-anneau.ca-mini .ca-perle.rafraichir::after{width:7px;height:7px;top:-1px;right:-1px;border-width:1.5px}
.ca-anneau.ca-micro{width:18px;height:18px}
.ca-anneau.ca-micro::after{inset:2.5px}
.ca-anneau.ca-micro .ca-perle{width:12px;height:12px}
.pastilles{gap:0}

/* Reprise d'une photo interrompue (09/09/2026, voir app.js) */
.photo-reprise{max-width:180px;border-radius:8px;margin-top:8px;display:block}
.btn-reprise{margin-top:8px;cursor:pointer}
