mise à niveau de tout le site
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
/* ==================================================================
|
||||
Cours de traitement de texte (3e TQ, 4e TQ)
|
||||
Chargé après assets/theme.css, dont il reprend toutes les couleurs.
|
||||
Mise en page « document long » : un sommaire latéral qui suit la
|
||||
lecture, et une feuille de papier au centre.
|
||||
================================================================== */
|
||||
|
||||
/* ---------- gabarit à deux colonnes ---------- */
|
||||
|
||||
.wrap {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 16rem minmax(0, 1fr);
|
||||
gap: 2rem;
|
||||
max-width: 80rem;
|
||||
margin: 0 auto;
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.sommaire-lat {
|
||||
position: sticky;
|
||||
top: 1.5rem;
|
||||
align-self: start;
|
||||
max-height: calc(100vh - 3rem);
|
||||
overflow: auto;
|
||||
}
|
||||
.sommaire-lat h2 {
|
||||
font-family: var(--police-texte);
|
||||
font-size: .78rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--encre-douce);
|
||||
margin: 1.4rem 0 .4rem;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
.sommaire-lat h2:first-of-type { margin-top: 0; }
|
||||
.sommaire-lat a {
|
||||
display: block;
|
||||
padding: .28rem .55rem;
|
||||
color: var(--encre);
|
||||
text-decoration: none;
|
||||
border-left: 3px solid transparent;
|
||||
font-size: .93rem;
|
||||
}
|
||||
.sommaire-lat a:hover { background: var(--accent-fond); }
|
||||
.sommaire-lat a.on {
|
||||
border-left-color: var(--accent);
|
||||
background: var(--accent-fond);
|
||||
font-weight: 600;
|
||||
}
|
||||
.sommaire-lat .top {
|
||||
font-family: var(--police-titre);
|
||||
font-weight: 700;
|
||||
font-size: .98rem;
|
||||
margin-bottom: .8rem;
|
||||
color: var(--accent-encre);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* ---------- la feuille ---------- */
|
||||
|
||||
.feuille {
|
||||
background: var(--blanc);
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .3rem;
|
||||
box-shadow: 0 12px 30px -20px rgba(22, 48, 43, .5);
|
||||
}
|
||||
/* Règle graduée, comme en haut de la fenêtre de Writer. */
|
||||
.regle {
|
||||
height: 20px;
|
||||
border-bottom: 1px solid var(--trait);
|
||||
background: var(--papier);
|
||||
background-image: repeating-linear-gradient(to right, var(--trait) 0 1px, transparent 1px 56px);
|
||||
background-position: 24px 0;
|
||||
position: relative;
|
||||
}
|
||||
.regle::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 24px; right: 24px; bottom: 0;
|
||||
height: 5px;
|
||||
background: var(--accent);
|
||||
opacity: .45;
|
||||
}
|
||||
.inner { padding: 2.4rem clamp(1.2rem, 4vw, 3.4rem) 3rem; max-width: 46rem; }
|
||||
|
||||
.module-tag {
|
||||
display: inline-block;
|
||||
font-family: var(--police-titre);
|
||||
font-size: .75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--papier);
|
||||
background: var(--accent-encre);
|
||||
padding: .1rem .5rem;
|
||||
border-radius: .2rem;
|
||||
margin-bottom: .3rem;
|
||||
}
|
||||
|
||||
/* ---------- blocs de contenu ---------- */
|
||||
|
||||
/* Alias historique de .encadre--cle, conservé pour le contenu existant. */
|
||||
.regle-cle {
|
||||
border-left: .35rem solid var(--cible);
|
||||
background: var(--cible-fond);
|
||||
border-radius: 0 .4rem .4rem 0;
|
||||
padding: .9rem 1.1rem;
|
||||
margin: 1.4rem 0;
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
.regle-cle p { margin: 0; }
|
||||
|
||||
.specimen {
|
||||
font-family: var(--police-doc);
|
||||
font-size: 1rem;
|
||||
line-height: 1.75;
|
||||
background: var(--papier);
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .3rem;
|
||||
padding: 1rem 1.2rem;
|
||||
}
|
||||
.pil { color: var(--cible); font-weight: 700; }
|
||||
|
||||
details {
|
||||
border-bottom: 1px solid var(--trait);
|
||||
padding: .6rem 0;
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
summary { cursor: pointer; font-weight: 600; }
|
||||
summary::marker { color: var(--accent); }
|
||||
details[open] summary { margin-bottom: .6rem; }
|
||||
|
||||
/* ---------- boutons ---------- */
|
||||
|
||||
button {
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--accent-encre);
|
||||
background: var(--blanc);
|
||||
color: var(--accent-encre);
|
||||
padding: .4rem .85rem;
|
||||
border-radius: .3rem;
|
||||
}
|
||||
button:hover { background: var(--accent-fond); }
|
||||
button.plein { background: var(--accent-encre); color: var(--papier); }
|
||||
button.plein:hover { background: var(--encre); border-color: var(--encre); }
|
||||
|
||||
/* ---------- démonstration des marques de paragraphe ---------- */
|
||||
|
||||
.demo { border: 1px solid var(--trait); border-radius: .3rem; margin: 1.2rem 0; overflow: hidden; }
|
||||
.demo-barre {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
background: var(--papier);
|
||||
border-bottom: 1px solid var(--trait);
|
||||
padding: .55rem .8rem;
|
||||
font-size: .9rem;
|
||||
}
|
||||
.demo-corps { display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
|
||||
.demo-col { padding: .9rem 1rem; font-family: var(--police-doc); line-height: 1.7; overflow: hidden; }
|
||||
.demo-col:first-child { border-right: 1px solid var(--trait); }
|
||||
.demo-col h4 {
|
||||
margin: 0 0 .5rem;
|
||||
font-family: var(--police-texte);
|
||||
font-size: .82rem;
|
||||
color: var(--encre-douce);
|
||||
}
|
||||
.marque { color: var(--cible); font-weight: 700; }
|
||||
.esp { color: var(--trait-fort); }
|
||||
@media (max-width: 640px) {
|
||||
.demo-corps { grid-template-columns: 1fr; }
|
||||
.demo-col:first-child { border-right: 0; border-bottom: 1px solid var(--trait); }
|
||||
}
|
||||
|
||||
/* ---------- zones cliquables de la fenêtre de Writer ---------- */
|
||||
|
||||
.zones { display: flex; flex-wrap: wrap; gap: .4rem; margin: .8rem 0; }
|
||||
.zones button { font-size: .9rem; }
|
||||
.zones button[aria-pressed="true"] { background: var(--accent-encre); color: var(--papier); }
|
||||
#zone-txt {
|
||||
min-height: 3.2rem;
|
||||
background: var(--accent-fond);
|
||||
border-radius: .3rem;
|
||||
padding: .7rem .9rem;
|
||||
font-size: .95rem;
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
|
||||
/* ---------- validateur de nom de fichier ---------- */
|
||||
|
||||
.nomtest input {
|
||||
font: inherit;
|
||||
font-family: ui-monospace, "JetBrains Mono", Consolas, monospace;
|
||||
padding: .45rem .6rem;
|
||||
border: 1px solid var(--trait-fort);
|
||||
border-radius: .3rem;
|
||||
width: min(28rem, 100%);
|
||||
}
|
||||
.check { list-style: none; padding: 0; margin: .8rem 0; font-size: .95rem; }
|
||||
.check li { padding-left: 1.7rem; position: relative; margin-bottom: .3rem; }
|
||||
.check li::before { position: absolute; left: 0; font-weight: 700; }
|
||||
.check li.ok::before { content: "\2713"; color: var(--juste); }
|
||||
.check li.ko::before { content: "\2715"; color: var(--erreur); }
|
||||
|
||||
/* ---------- chasse aux fautes ---------- */
|
||||
|
||||
.chasse {
|
||||
font-family: var(--police-doc);
|
||||
line-height: 2;
|
||||
background: var(--papier);
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .3rem;
|
||||
padding: 1rem 1.2rem;
|
||||
}
|
||||
.chasse span { cursor: pointer; padding: 0 .1rem; border-bottom: 2px solid transparent; }
|
||||
.chasse span:hover { background: var(--accent-fond); }
|
||||
.chasse span.trouve { background: var(--cible); border-bottom-color: #B8912A; }
|
||||
.chasse span.rate { background: var(--erreur-fond); border-bottom-color: var(--erreur); }
|
||||
.score { font-weight: 600; margin-top: .6rem; }
|
||||
|
||||
/* ---------- quiz ---------- */
|
||||
|
||||
.quiz {
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .4rem;
|
||||
padding: 1.1rem 1.2rem;
|
||||
margin: 1.2rem 0;
|
||||
background: var(--blanc);
|
||||
}
|
||||
.q { margin-bottom: 1.3rem; }
|
||||
.q p { font-weight: 600; margin-bottom: .5rem; }
|
||||
.q label { display: block; padding: .32rem .5rem; cursor: pointer; border-left: 3px solid transparent; }
|
||||
.q label:hover { background: var(--accent-fond); }
|
||||
.q input { margin-right: .5rem; }
|
||||
.q label.bon { background: var(--juste-fond); border-left-color: var(--juste); }
|
||||
.q label.mauvais { background: var(--erreur-fond); border-left-color: var(--erreur); }
|
||||
.verdict { margin-top: .5rem; font-size: .93rem; color: var(--encre-douce); }
|
||||
|
||||
/* ---------- chronomètre de frappe ---------- */
|
||||
|
||||
.chrono {
|
||||
display: flex;
|
||||
gap: 1.2rem;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
background: var(--papier);
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .3rem;
|
||||
padding: .9rem 1rem;
|
||||
}
|
||||
.temps {
|
||||
font-family: ui-monospace, "JetBrains Mono", Consolas, monospace;
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
#zone-frappe {
|
||||
width: 100%;
|
||||
min-height: 9rem;
|
||||
font-family: var(--police-doc);
|
||||
font-size: 1rem;
|
||||
line-height: 1.7;
|
||||
padding: .8rem;
|
||||
border: 1px solid var(--trait-fort);
|
||||
border-radius: .3rem;
|
||||
margin-top: .8rem;
|
||||
}
|
||||
|
||||
/* ---------- filtre des raccourcis ---------- */
|
||||
|
||||
#filtre {
|
||||
font: inherit;
|
||||
padding: .45rem .6rem;
|
||||
border: 1px solid var(--trait-fort);
|
||||
border-radius: .3rem;
|
||||
width: min(22rem, 100%);
|
||||
}
|
||||
|
||||
/* ---------- petits écrans ---------- */
|
||||
|
||||
@media (max-width: 880px) {
|
||||
.wrap { grid-template-columns: 1fr; padding: .8rem; }
|
||||
.sommaire-lat {
|
||||
position: static;
|
||||
max-height: none;
|
||||
background: var(--blanc);
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .3rem;
|
||||
}
|
||||
.sommaire-lat a { display: inline-block; border-left: 0; border-bottom: 3px solid transparent; }
|
||||
.sommaire-lat a.on { border-left: 0; border-bottom-color: var(--accent); }
|
||||
}
|
||||
|
||||
@media print {
|
||||
.sommaire-lat, .actions, .chrono, #zone-frappe { display: none; }
|
||||
.feuille { box-shadow: none; border: 0; }
|
||||
.wrap { display: block; padding: 0; }
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/* ==================================================================
|
||||
Outils communs aux cours de traitement de texte (3e TQ, 4e TQ)
|
||||
------------------------------------------------------------------
|
||||
Trois briques réutilisables d'un module à l'autre :
|
||||
quiz(element, questions) questionnaire à choix, correction immédiate
|
||||
chasse(...) chasse aux fautes dans un texte
|
||||
suivreSommaire() surligne l'entrée courante du sommaire
|
||||
|
||||
Chaque page de module charge ce fichier, puis déclare ses propres
|
||||
données dans un <script> qui lui est propre.
|
||||
================================================================== */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* ---------- questionnaire à choix multiples ----------
|
||||
questions : [{q: énoncé, r: [réponses], b: index de la bonne, e: explication}] */
|
||||
function quiz(el, questions){
|
||||
if (!el) return;
|
||||
el.innerHTML = questions.map(function(q, i){
|
||||
return '<div class="q" data-i="' + i + '"><p>' + (i + 1) + '. ' + q.q + '</p>' +
|
||||
q.r.map(function(r, j){
|
||||
return '<label><input type="radio" name="' + el.id + '-' + i + '" value="' + j + '">' + r + '</label>';
|
||||
}).join('') +
|
||||
'<div class="verdict" role="status" aria-live="polite"></div></div>';
|
||||
}).join('');
|
||||
|
||||
el.addEventListener('change', function(e){
|
||||
var bloc = e.target.closest('.q');
|
||||
var i = +bloc.dataset.i, q = questions[i];
|
||||
bloc.querySelectorAll('label').forEach(function(l, j){
|
||||
l.className = (j === q.b) ? 'bon' : (l.querySelector('input').checked ? 'mauvais' : '');
|
||||
});
|
||||
bloc.querySelector('.verdict').textContent =
|
||||
(+e.target.value === q.b ? 'Exact. ' : 'Non. ') + q.e;
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- chasse aux fautes ----------
|
||||
jetons : [{t: mot, f: true si c'est une faute}] */
|
||||
function chasse(conteneur, scoreEl, resetBtn, solBtn, jetons, total, motFinal){
|
||||
if (!conteneur) return;
|
||||
var trouves = new Set(), rates = new Set();
|
||||
|
||||
function maj(){
|
||||
conteneur.querySelectorAll('span').forEach(function(s){
|
||||
var i = +s.dataset.i;
|
||||
s.className = trouves.has(i) ? 'trouve' : (rates.has(i) ? 'rate' : '');
|
||||
});
|
||||
scoreEl.textContent = trouves.size + ' sur ' + total + ' trouvées' +
|
||||
(rates.size ? ', ' + rates.size + ' clic' + (rates.size > 1 ? 's' : '') + ' à côté' : '') +
|
||||
(trouves.size === total ? '. ' + motFinal : '');
|
||||
}
|
||||
|
||||
conteneur.innerHTML = jetons.map(function(j, i){
|
||||
return '<span data-i="' + i + '">' + j.t + '</span>';
|
||||
}).join(' ');
|
||||
|
||||
conteneur.addEventListener('click', function(e){
|
||||
var s = e.target.closest('span');
|
||||
if (!s) return;
|
||||
var i = +s.dataset.i;
|
||||
if (jetons[i].f) trouves.add(i); else rates.add(i);
|
||||
maj();
|
||||
});
|
||||
resetBtn.addEventListener('click', function(){
|
||||
trouves = new Set(); rates = new Set(); maj();
|
||||
});
|
||||
solBtn.addEventListener('click', function(){
|
||||
jetons.forEach(function(j, i){ if (j.f) trouves.add(i); });
|
||||
rates = new Set(); maj();
|
||||
});
|
||||
|
||||
maj();
|
||||
}
|
||||
|
||||
/* ---------- surlignage de l'entrée courante du sommaire ---------- */
|
||||
function suivreSommaire(){
|
||||
var liens = [].slice.call(document.querySelectorAll('.sommaire-lat a[href^="#"]'));
|
||||
var cibles = liens
|
||||
.map(function(a){ return document.getElementById(a.getAttribute('href').slice(1)); })
|
||||
.filter(Boolean);
|
||||
if (!cibles.length || !window.IntersectionObserver) return;
|
||||
|
||||
var obs = new IntersectionObserver(function(entrees){
|
||||
entrees.forEach(function(en){
|
||||
if (!en.isIntersecting) return;
|
||||
liens.forEach(function(a){
|
||||
a.classList.toggle('on', a.getAttribute('href') === '#' + en.target.id);
|
||||
});
|
||||
});
|
||||
}, { rootMargin: '-10% 0px -80% 0px' });
|
||||
|
||||
cibles.forEach(function(c){ obs.observe(c); });
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', suivreSommaire);
|
||||
@@ -0,0 +1,184 @@
|
||||
/* ==================================================================
|
||||
Composants du moteur d'exercices de la 2e commune.
|
||||
Chargé après assets/theme.css, dont il reprend toutes les couleurs.
|
||||
================================================================== */
|
||||
|
||||
/* ---------- bandeau de score ---------- */
|
||||
|
||||
.score {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 5;
|
||||
background: var(--blanc);
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .5rem;
|
||||
padding: .8rem 1.1rem 1rem;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
.score__txt { font-size: .95rem; }
|
||||
.score strong { color: var(--accent-encre); }
|
||||
.score .action { margin-top: .7rem; }
|
||||
|
||||
.jauge {
|
||||
height: .7rem;
|
||||
background: var(--accent-fond);
|
||||
border-radius: .35rem;
|
||||
overflow: hidden;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
.jauge span {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background: var(--juste);
|
||||
transition: width .3s;
|
||||
}
|
||||
|
||||
/* ---------- carte d'exercice ---------- */
|
||||
|
||||
.ex {
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .5rem;
|
||||
padding: 1.1rem 1.2rem 1.2rem;
|
||||
margin: 1.2rem 0;
|
||||
background: var(--blanc);
|
||||
}
|
||||
.ex .consigne {
|
||||
font-family: var(--police-titre);
|
||||
font-weight: 700;
|
||||
font-size: .95rem;
|
||||
color: var(--accent-encre);
|
||||
margin: 0 0 .3rem;
|
||||
max-width: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .3rem 1rem;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.ex .enonce { margin: 0 0 .9rem; }
|
||||
.ex h4 { margin: 0 0 .5rem; color: var(--encre-douce); font-size: .85rem; }
|
||||
|
||||
.minuteur {
|
||||
font-family: var(--police-titre);
|
||||
font-weight: 700;
|
||||
color: var(--erreur);
|
||||
}
|
||||
|
||||
/* ---------- boutons de réponse ---------- */
|
||||
|
||||
.opt, .jeton, .item {
|
||||
font: inherit;
|
||||
font-size: .97rem;
|
||||
display: inline-block;
|
||||
margin: .25rem .35rem .25rem 0;
|
||||
padding: .5rem .8rem;
|
||||
border: 1px solid var(--trait-fort);
|
||||
border-radius: .4rem;
|
||||
background: var(--blanc);
|
||||
color: var(--encre);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
.opt { display: block; width: 100%; }
|
||||
.jeton--bloc { display: block; width: 100%; }
|
||||
.jeton--mini { font-size: .8rem; padding: .2rem .55rem; margin-left: .4rem; }
|
||||
|
||||
.opt:hover:not([disabled]),
|
||||
.jeton:hover:not([disabled]),
|
||||
.item:hover:not([disabled]) { border-color: var(--encre); }
|
||||
|
||||
.opt.choisi, .jeton.choisi, .item.choisi {
|
||||
background: var(--encre);
|
||||
color: var(--papier);
|
||||
border-color: var(--encre);
|
||||
}
|
||||
|
||||
.opt.juste, .jeton.juste, .item.juste {
|
||||
background: var(--juste-fond);
|
||||
border-color: var(--juste);
|
||||
}
|
||||
.opt.faux, .jeton.faux, .item.faux {
|
||||
background: var(--erreur-fond);
|
||||
border-color: var(--erreur);
|
||||
}
|
||||
.opt[disabled], .jeton[disabled], .item[disabled] { cursor: default; }
|
||||
|
||||
/* ---------- tri en paniers ---------- */
|
||||
|
||||
.reserve { margin-bottom: .6rem; }
|
||||
|
||||
.paniers {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .8rem;
|
||||
margin-top: .8rem;
|
||||
}
|
||||
.panier {
|
||||
flex: 1 1 11rem;
|
||||
min-height: 6rem;
|
||||
border: 2px dashed var(--trait-fort);
|
||||
border-radius: .5rem;
|
||||
padding: .6rem;
|
||||
background: var(--papier);
|
||||
cursor: pointer;
|
||||
}
|
||||
.panier:hover { border-color: var(--accent); }
|
||||
.panier.vise { border-color: var(--accent); background: var(--accent-fond); }
|
||||
.panier h4 {
|
||||
margin: 0 0 .4rem;
|
||||
font-family: var(--police-titre);
|
||||
font-size: .85rem;
|
||||
color: var(--accent-encre);
|
||||
}
|
||||
|
||||
/* ---------- association en deux colonnes ---------- */
|
||||
|
||||
.deux-col { display: flex; gap: 1.2rem; flex-wrap: wrap; }
|
||||
.deux-col > div { flex: 1 1 14rem; }
|
||||
|
||||
/* ---------- remise en ordre ---------- */
|
||||
|
||||
.liste-ordre { margin-bottom: .6rem; }
|
||||
.item--bloc { display: block; width: 100%; }
|
||||
|
||||
/* ---------- saisie ---------- */
|
||||
|
||||
.court {
|
||||
font: inherit;
|
||||
padding: .5rem .6rem;
|
||||
border: 1px solid var(--trait-fort);
|
||||
border-radius: .4rem;
|
||||
width: 11rem;
|
||||
}
|
||||
|
||||
/* ---------- schéma à zones cliquables ---------- */
|
||||
|
||||
.schema { margin: .4rem 0 .8rem; }
|
||||
.schema svg { max-width: 100%; height: auto; }
|
||||
svg .zone {
|
||||
fill: transparent;
|
||||
stroke: var(--accent-encre);
|
||||
stroke-width: 2;
|
||||
cursor: pointer;
|
||||
}
|
||||
svg .zone:hover { fill: var(--accent-fond); fill-opacity: .55; }
|
||||
svg .zone.juste { fill: var(--juste); fill-opacity: .3; stroke: var(--juste); }
|
||||
svg .zone.faux { fill: var(--erreur); fill-opacity: .3; stroke: var(--erreur); }
|
||||
svg text { font-family: inherit; font-size: 13px; fill: var(--encre); pointer-events: none; }
|
||||
|
||||
/* ---------- verdict ---------- */
|
||||
|
||||
.retour {
|
||||
margin-top: .8rem;
|
||||
font-size: .93rem;
|
||||
padding: .55rem .7rem;
|
||||
border-radius: .4rem;
|
||||
display: none;
|
||||
}
|
||||
.retour--ok { display: block; background: var(--juste-fond); border: 1px solid var(--juste); }
|
||||
.retour--ko { display: block; background: var(--erreur-fond); border: 1px solid var(--erreur); }
|
||||
|
||||
@media print {
|
||||
.score, .ex .action, .panier { display: none; }
|
||||
}
|
||||
@@ -0,0 +1,557 @@
|
||||
/* ==================================================================
|
||||
Moteur d'exercices hors ligne — 2e commune
|
||||
------------------------------------------------------------------
|
||||
Aucune dépendance externe. Chaque page de bloc déclare ses exercices
|
||||
dans window.DATA, un tableau d'objets. Types reconnus :
|
||||
qcm, vf, assoc, tri, ordre, hotspot, calcul, texte, intrus, chrono
|
||||
|
||||
Règle de comptage, la même pour tous les types :
|
||||
un exercice compte pour un point, une seule fois, au moment où il
|
||||
est terminé, et il est réussi s'il a été terminé sans erreur.
|
||||
Recommencer une série chronométrée ne réajoute donc pas de point.
|
||||
================================================================== */
|
||||
|
||||
"use strict";
|
||||
|
||||
var TOTAL = 0, REUSSIS = 0, TERMINES = 0;
|
||||
|
||||
/* ---------- petits utilitaires ---------- */
|
||||
|
||||
function norm(s){
|
||||
return (s || "").toString().toLowerCase()
|
||||
.normalize("NFD").replace(/[̀-ͯ]/g, "")
|
||||
.replace(/[^a-z0-9]/g, "");
|
||||
}
|
||||
|
||||
function el(tag, cls, txt){
|
||||
var e = document.createElement(tag);
|
||||
if (cls) e.className = cls;
|
||||
if (txt !== undefined) e.textContent = txt;
|
||||
return e;
|
||||
}
|
||||
|
||||
function melange(t){
|
||||
var a = t.slice();
|
||||
for (var i = a.length - 1; i > 0; i--){
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var x = a[i]; a[i] = a[j]; a[j] = x;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/* ---------- score ---------- */
|
||||
|
||||
function majScore(){
|
||||
var s = document.getElementById("score");
|
||||
if (!s) return;
|
||||
var pct = TOTAL ? Math.round(REUSSIS / TOTAL * 100) : 0;
|
||||
s.querySelector(".score__txt").innerHTML =
|
||||
"Exercices réussis : <strong>" + REUSSIS + " / " + TOTAL + "</strong> (" + pct + " %)" +
|
||||
(TERMINES ? " — " + TERMINES + " terminé" + (TERMINES > 1 ? "s" : "") : "");
|
||||
s.querySelector(".jauge span").style.width = pct + "%";
|
||||
}
|
||||
|
||||
/* Clôture un exercice : affiche le verdict et le compte, une seule fois.
|
||||
Un exercice déjà clos peut encore être rejoué (série chronométrée),
|
||||
mais il ne change plus le score. */
|
||||
function clore(box, reussi, msg){
|
||||
var r = box.querySelector(".retour");
|
||||
r.className = "retour " + (reussi ? "retour--ok" : "retour--ko");
|
||||
r.textContent = (reussi ? "Réussi. " : "Terminé, mais avec des erreurs. ") + (msg || "");
|
||||
if (box.dataset.compte === "1") return;
|
||||
box.dataset.compte = "1";
|
||||
TERMINES++;
|
||||
if (reussi) REUSSIS++;
|
||||
majScore();
|
||||
}
|
||||
|
||||
/* Message intermédiaire : ne clôt pas l'exercice, ne compte pas. */
|
||||
function signaler(box, ok, msg){
|
||||
var r = box.querySelector(".retour");
|
||||
r.className = "retour " + (ok ? "retour--ok" : "retour--ko");
|
||||
r.textContent = msg;
|
||||
}
|
||||
|
||||
/* ---------- cadre commun ---------- */
|
||||
|
||||
function cadre(d){
|
||||
var box = el("article", "ex");
|
||||
box.appendChild(el("p", "consigne", d.consigne || "Exercice"));
|
||||
if (d.enonce) box.appendChild(el("p", "enonce", d.enonce));
|
||||
return box;
|
||||
}
|
||||
|
||||
function finir(box){
|
||||
/* role="status" : le verdict est annoncé aux lecteurs d'écran
|
||||
sans déplacer le focus de l'élève. */
|
||||
var r = el("div", "retour");
|
||||
r.setAttribute("role", "status");
|
||||
r.setAttribute("aria-live", "polite");
|
||||
box.appendChild(r);
|
||||
return box;
|
||||
}
|
||||
|
||||
/* ---------- QCM ---------- */
|
||||
|
||||
function faireQcm(d){
|
||||
var box = cadre(d), fini = false;
|
||||
d.options.forEach(function(txt, i){
|
||||
var b = el("button", "opt", txt);
|
||||
b.type = "button";
|
||||
b.onclick = function(){
|
||||
if (fini) return;
|
||||
fini = true;
|
||||
var ok = (i === d.reponse);
|
||||
b.classList.add(ok ? "juste" : "faux");
|
||||
if (!ok) box.querySelectorAll(".opt")[d.reponse].classList.add("juste");
|
||||
box.querySelectorAll(".opt").forEach(function(o){ o.disabled = true; });
|
||||
clore(box, ok, d.explication || "");
|
||||
};
|
||||
box.appendChild(b);
|
||||
});
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Vrai / Faux ---------- */
|
||||
|
||||
function faireVf(d){
|
||||
var box = cadre(d), fini = false;
|
||||
["Vrai", "Faux"].forEach(function(txt, i){
|
||||
var b = el("button", "jeton", txt);
|
||||
b.type = "button";
|
||||
b.onclick = function(){
|
||||
if (fini) return;
|
||||
fini = true;
|
||||
var ok = ((i === 0) === d.reponse);
|
||||
b.classList.add(ok ? "juste" : "faux");
|
||||
box.querySelectorAll(".jeton").forEach(function(o){ o.disabled = true; });
|
||||
clore(box, ok, d.explication || "");
|
||||
};
|
||||
box.appendChild(b);
|
||||
});
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Association : un clic à gauche, un clic à droite ---------- */
|
||||
|
||||
function faireAssoc(d){
|
||||
var box = cadre(d);
|
||||
var zone = el("div", "deux-col");
|
||||
var g = el("div"), dr = el("div");
|
||||
g.appendChild(el("h4", null, "Colonne A"));
|
||||
dr.appendChild(el("h4", null, "Colonne B"));
|
||||
var choisi = null, trouves = 0, erreurs = 0;
|
||||
var droite = melange(d.paires.map(function(p, i){ return { t: p[1], i: i }; }));
|
||||
|
||||
d.paires.forEach(function(p, i){
|
||||
var b = el("button", "jeton jeton--bloc", p[0]);
|
||||
b.type = "button";
|
||||
b.dataset.i = i;
|
||||
b.onclick = function(){
|
||||
if (b.disabled) return;
|
||||
if (choisi) choisi.classList.remove("choisi");
|
||||
choisi = b; b.classList.add("choisi");
|
||||
};
|
||||
g.appendChild(b);
|
||||
});
|
||||
|
||||
droite.forEach(function(o){
|
||||
var b = el("button", "jeton jeton--bloc", o.t);
|
||||
b.type = "button";
|
||||
b.onclick = function(){
|
||||
if (b.disabled) return;
|
||||
if (!choisi){
|
||||
signaler(box, false, "Choisis d'abord une étiquette dans la colonne A.");
|
||||
return;
|
||||
}
|
||||
var ok = (parseInt(choisi.dataset.i, 10) === o.i);
|
||||
if (ok){
|
||||
choisi.classList.remove("choisi");
|
||||
choisi.classList.add("juste"); b.classList.add("juste");
|
||||
choisi.disabled = true; b.disabled = true;
|
||||
choisi = null; trouves++;
|
||||
if (trouves === d.paires.length){
|
||||
clore(box, erreurs === 0, (d.explication || "") +
|
||||
(erreurs ? " Erreurs : " + erreurs + "." : ""));
|
||||
} else {
|
||||
signaler(box, true, "Bonne association. Il en reste " +
|
||||
(d.paires.length - trouves) + ".");
|
||||
}
|
||||
} else {
|
||||
erreurs++;
|
||||
b.classList.add("faux");
|
||||
setTimeout(function(){ b.classList.remove("faux"); }, 600);
|
||||
signaler(box, false, "Ce n'est pas la bonne correspondance, essaie autre chose.");
|
||||
}
|
||||
};
|
||||
dr.appendChild(b);
|
||||
});
|
||||
|
||||
zone.appendChild(g); zone.appendChild(dr);
|
||||
box.appendChild(zone);
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Tri dans des paniers ----------
|
||||
Les paniers sont des div : un bouton ne peut pas contenir les
|
||||
étiquettes déposées, qui sont elles-mêmes des boutons. On leur
|
||||
donne donc explicitement le rôle, la tabulation et les touches
|
||||
Entrée et Espace, pour qu'ils soient utilisables au clavier. */
|
||||
|
||||
function faireTri(d){
|
||||
var box = cadre(d);
|
||||
var reserve = el("div", "reserve");
|
||||
var choisi = null, places = 0, erreurs = 0;
|
||||
|
||||
melange(d.items).forEach(function(it){
|
||||
var b = el("button", "item", it[0]);
|
||||
b.type = "button";
|
||||
b.dataset.p = it[1];
|
||||
b.onclick = function(){
|
||||
if (b.disabled) return;
|
||||
if (choisi) choisi.classList.remove("choisi");
|
||||
choisi = b; b.classList.add("choisi");
|
||||
signaler(box, true, "« " + it[0] + " » est sélectionné. Choisis maintenant son panier.");
|
||||
};
|
||||
reserve.appendChild(b);
|
||||
});
|
||||
box.appendChild(reserve);
|
||||
|
||||
var paniers = el("div", "paniers");
|
||||
d.paniers.forEach(function(nom, pi){
|
||||
var p = el("div", "panier");
|
||||
p.tabIndex = 0;
|
||||
p.setAttribute("role", "button");
|
||||
p.setAttribute("aria-label", "Panier " + nom);
|
||||
p.appendChild(el("h4", null, nom));
|
||||
|
||||
function deposer(){
|
||||
if (!choisi){
|
||||
signaler(box, false, "Choisis d'abord une étiquette dans la réserve.");
|
||||
return;
|
||||
}
|
||||
var ok = (parseInt(choisi.dataset.p, 10) === pi);
|
||||
if (ok){
|
||||
choisi.classList.remove("choisi");
|
||||
choisi.classList.add("juste");
|
||||
choisi.disabled = true;
|
||||
p.appendChild(choisi);
|
||||
choisi = null; places++;
|
||||
if (places === d.items.length){
|
||||
clore(box, erreurs === 0, (d.explication || "") +
|
||||
(erreurs ? " Erreurs : " + erreurs + "." : ""));
|
||||
} else {
|
||||
signaler(box, true, "Bien classé. Il en reste " + (d.items.length - places) + ".");
|
||||
}
|
||||
} else {
|
||||
erreurs++;
|
||||
p.classList.add("vise");
|
||||
setTimeout(function(){ p.classList.remove("vise"); }, 500);
|
||||
signaler(box, false, "Ce n'est pas le bon panier.");
|
||||
}
|
||||
}
|
||||
|
||||
p.onclick = deposer;
|
||||
p.onkeydown = function(e){
|
||||
if (e.key === "Enter" || e.key === " " || e.key === "Spacebar"){
|
||||
e.preventDefault();
|
||||
deposer();
|
||||
}
|
||||
};
|
||||
paniers.appendChild(p);
|
||||
});
|
||||
box.appendChild(paniers);
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Remise en ordre ---------- */
|
||||
|
||||
function faireOrdre(d){
|
||||
var box = cadre(d);
|
||||
var liste = el("div", "liste-ordre");
|
||||
var ordre = melange(d.etapes.map(function(t, i){ return { t: t, i: i }; }));
|
||||
var fini = false, essais = 0;
|
||||
|
||||
function dessiner(){
|
||||
liste.innerHTML = "";
|
||||
ordre.forEach(function(o, pos){
|
||||
var ligne = el("div", "item item--bloc");
|
||||
ligne.appendChild(document.createTextNode((pos + 1) + ". " + o.t + " "));
|
||||
var up = el("button", "jeton jeton--mini", "monter");
|
||||
var dn = el("button", "jeton jeton--mini", "descendre");
|
||||
up.type = dn.type = "button";
|
||||
up.setAttribute("aria-label", "Monter : " + o.t);
|
||||
dn.setAttribute("aria-label", "Descendre : " + o.t);
|
||||
up.disabled = (pos === 0);
|
||||
dn.disabled = (pos === ordre.length - 1);
|
||||
up.onclick = function(){
|
||||
var x = ordre[pos - 1]; ordre[pos - 1] = ordre[pos]; ordre[pos] = x; dessiner();
|
||||
};
|
||||
dn.onclick = function(){
|
||||
var x = ordre[pos + 1]; ordre[pos + 1] = ordre[pos]; ordre[pos] = x; dessiner();
|
||||
};
|
||||
ligne.appendChild(up); ligne.appendChild(dn);
|
||||
liste.appendChild(ligne);
|
||||
});
|
||||
}
|
||||
dessiner();
|
||||
box.appendChild(liste);
|
||||
|
||||
var v = el("button", "action", "Vérifier l'ordre");
|
||||
v.type = "button";
|
||||
v.onclick = function(){
|
||||
if (fini) return;
|
||||
var ok = ordre.every(function(o, pos){ return o.i === pos; });
|
||||
if (ok){
|
||||
fini = true; v.disabled = true;
|
||||
liste.querySelectorAll(".item").forEach(function(i){ i.classList.add("juste"); });
|
||||
clore(box, essais === 0, (d.explication || "") +
|
||||
(essais ? " Vérifications ratées : " + essais + "." : ""));
|
||||
} else {
|
||||
essais++;
|
||||
signaler(box, false, "L'ordre n'est pas encore correct, déplace encore des lignes.");
|
||||
}
|
||||
};
|
||||
box.appendChild(v);
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Zones cliquables sur schéma ----------
|
||||
Les zones SVG reçoivent tabindex et role pour être atteignables
|
||||
au clavier, comme les boutons du reste de la page. */
|
||||
|
||||
function faireHotspot(d){
|
||||
var box = cadre(d);
|
||||
var wrap = el("div", "schema");
|
||||
wrap.innerHTML = d.svg;
|
||||
box.appendChild(wrap);
|
||||
|
||||
var question = el("p", "enonce");
|
||||
question.setAttribute("role", "status");
|
||||
question.setAttribute("aria-live", "polite");
|
||||
box.appendChild(question);
|
||||
|
||||
var restants = melange(d.zones.slice());
|
||||
var erreurs = 0;
|
||||
|
||||
function demander(){
|
||||
if (!restants.length){
|
||||
question.textContent = "Terminé.";
|
||||
clore(box, erreurs === 0, (d.explication || "") +
|
||||
(erreurs ? " Erreurs : " + erreurs + "." : ""));
|
||||
return;
|
||||
}
|
||||
question.innerHTML = "Clique sur : <strong>" + restants[0] + "</strong>";
|
||||
}
|
||||
|
||||
wrap.querySelectorAll(".zone").forEach(function(z){
|
||||
z.setAttribute("tabindex", "0");
|
||||
z.setAttribute("role", "button");
|
||||
z.setAttribute("aria-label", z.dataset.zone || "zone");
|
||||
function essayer(){
|
||||
if (!restants.length) return;
|
||||
if (z.dataset.zone === restants[0]){
|
||||
z.classList.add("juste");
|
||||
restants.shift();
|
||||
demander();
|
||||
} else {
|
||||
erreurs++;
|
||||
z.classList.add("faux");
|
||||
setTimeout(function(){ z.classList.remove("faux"); }, 500);
|
||||
signaler(box, false, "Ce n'est pas cet élément.");
|
||||
}
|
||||
}
|
||||
z.addEventListener("click", essayer);
|
||||
z.addEventListener("keydown", function(e){
|
||||
if (e.key === "Enter" || e.key === " " || e.key === "Spacebar"){
|
||||
e.preventDefault();
|
||||
essayer();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
demander();
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Calcul ou réponse courte ---------- */
|
||||
|
||||
function faireSaisie(d){
|
||||
var box = cadre(d);
|
||||
var champ = el("input", "court");
|
||||
champ.type = "text";
|
||||
champ.setAttribute("aria-label", d.enonce || d.consigne || "Réponse");
|
||||
var v = el("button", "action", "Vérifier");
|
||||
v.type = "button";
|
||||
var fini = false, essais = 0;
|
||||
|
||||
function verifier(){
|
||||
if (fini) return;
|
||||
var ok;
|
||||
if (d.type === "calcul"){
|
||||
var n = parseFloat(champ.value.replace(",", ".").replace(/[^0-9.\-]/g, ""));
|
||||
ok = !isNaN(n) && Math.abs(n - d.reponse) <= (d.tolerance || 0);
|
||||
} else {
|
||||
ok = d.acceptees.some(function(a){ return norm(a) === norm(champ.value); });
|
||||
}
|
||||
if (ok){
|
||||
fini = true; v.disabled = true; champ.disabled = true;
|
||||
clore(box, essais === 0, (d.explication || "") +
|
||||
(essais ? " Essais ratés : " + essais + "." : ""));
|
||||
} else {
|
||||
essais++;
|
||||
signaler(box, false, d.indice || "Relis la théorie du chapitre et réessaie.");
|
||||
}
|
||||
}
|
||||
|
||||
v.onclick = verifier;
|
||||
champ.onkeydown = function(e){ if (e.key === "Enter"){ e.preventDefault(); verifier(); } };
|
||||
|
||||
box.appendChild(champ);
|
||||
box.appendChild(document.createTextNode(" "));
|
||||
box.appendChild(v);
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Chasse aux affirmations fausses ---------- */
|
||||
|
||||
function faireIntrus(d){
|
||||
var box = cadre(d);
|
||||
var restants = d.items.filter(function(i){ return i[1]; }).length;
|
||||
var erreurs = 0;
|
||||
d.items.forEach(function(it){
|
||||
var b = el("button", "opt", it[0]);
|
||||
b.type = "button";
|
||||
b.onclick = function(){
|
||||
if (b.disabled) return;
|
||||
b.disabled = true;
|
||||
if (it[1]){
|
||||
b.classList.add("juste");
|
||||
restants--;
|
||||
if (restants === 0){
|
||||
clore(box, erreurs === 0, (d.explication || "") +
|
||||
(erreurs ? " Affirmations correctes cliquées par erreur : " + erreurs + "." : ""));
|
||||
} else {
|
||||
signaler(box, true, "Bien vu. Il reste " + restants + " affirmation" +
|
||||
(restants > 1 ? "s" : "") + " fausse" + (restants > 1 ? "s" : "") + ".");
|
||||
}
|
||||
} else {
|
||||
b.classList.add("faux");
|
||||
erreurs++;
|
||||
signaler(box, false, "Cette affirmation est correcte, ce n'est pas un intrus.");
|
||||
}
|
||||
};
|
||||
box.appendChild(b);
|
||||
});
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Série chronométrée ----------
|
||||
Le premier passage fixe le score de l'exercice. Les suivants
|
||||
servent à s'entraîner : ils affichent un résultat mais ne
|
||||
touchent plus au compteur de la page. */
|
||||
|
||||
function faireChrono(d){
|
||||
var box = cadre(d);
|
||||
var minuteur = el("span", "minuteur", "");
|
||||
minuteur.setAttribute("role", "timer");
|
||||
box.querySelector(".consigne").appendChild(minuteur);
|
||||
|
||||
var zone = el("div"); box.appendChild(zone);
|
||||
var idx = 0, bons = 0, temps = d.secondes || 60, timer = null, encours = false;
|
||||
|
||||
var demarrer = el("button", "action", "Démarrer la série");
|
||||
demarrer.type = "button";
|
||||
box.appendChild(demarrer);
|
||||
|
||||
demarrer.onclick = function(){
|
||||
if (encours) return;
|
||||
encours = true;
|
||||
demarrer.hidden = true;
|
||||
idx = 0; bons = 0; temps = d.secondes || 60;
|
||||
minuteur.textContent = temps + " s";
|
||||
timer = setInterval(function(){
|
||||
temps--;
|
||||
minuteur.textContent = temps + " s";
|
||||
if (temps <= 0) terminer();
|
||||
}, 1000);
|
||||
poser();
|
||||
};
|
||||
|
||||
function poser(){
|
||||
zone.innerHTML = "";
|
||||
if (idx >= d.questions.length){ terminer(); return; }
|
||||
var q = d.questions[idx];
|
||||
zone.appendChild(el("p", "enonce", (idx + 1) + ". " + q.enonce));
|
||||
q.options.forEach(function(t, i){
|
||||
var b = el("button", "jeton", t);
|
||||
b.type = "button";
|
||||
b.onclick = function(){
|
||||
if (!encours) return;
|
||||
if (i === q.reponse) bons++;
|
||||
idx++;
|
||||
poser();
|
||||
};
|
||||
zone.appendChild(b);
|
||||
});
|
||||
}
|
||||
|
||||
function terminer(){
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
encours = false;
|
||||
zone.innerHTML = "";
|
||||
var seuil = Math.ceil(d.questions.length * 0.7);
|
||||
var ok = bons >= seuil;
|
||||
var deja = (box.dataset.compte === "1");
|
||||
var detail = "Score : " + bons + " / " + d.questions.length +
|
||||
". Seuil de réussite : " + seuil + ".";
|
||||
if (deja){
|
||||
/* Déjà compté au premier passage : on informe sans toucher au score. */
|
||||
signaler(box, ok, detail + " Ce nouvel essai ne change plus le compteur de la page.");
|
||||
} else {
|
||||
clore(box, ok, detail);
|
||||
}
|
||||
demarrer.textContent = "Recommencer la série";
|
||||
demarrer.hidden = false;
|
||||
}
|
||||
|
||||
return finir(box);
|
||||
}
|
||||
|
||||
/* ---------- Construction de la page ---------- */
|
||||
|
||||
var FABRIQUES = {
|
||||
qcm: faireQcm, vf: faireVf, assoc: faireAssoc, tri: faireTri,
|
||||
ordre: faireOrdre, hotspot: faireHotspot, calcul: faireSaisie,
|
||||
texte: faireSaisie, intrus: faireIntrus, chrono: faireChrono
|
||||
};
|
||||
|
||||
function construire(data){
|
||||
var cible = document.getElementById("exercices");
|
||||
if (!cible) return;
|
||||
|
||||
TOTAL = data.length; REUSSIS = 0; TERMINES = 0;
|
||||
|
||||
var s = el("div", "score");
|
||||
s.id = "score";
|
||||
s.appendChild(el("div", "score__txt"));
|
||||
var jauge = el("div", "jauge");
|
||||
jauge.appendChild(el("span"));
|
||||
s.appendChild(jauge);
|
||||
var rz = el("button", "action action--secondaire", "Tout recommencer");
|
||||
rz.type = "button";
|
||||
rz.onclick = function(){ location.reload(); };
|
||||
s.appendChild(rz);
|
||||
cible.parentNode.insertBefore(s, cible);
|
||||
|
||||
data.forEach(function(d){
|
||||
var f = FABRIQUES[d.type];
|
||||
if (f) cible.appendChild(f(d));
|
||||
});
|
||||
majScore();
|
||||
}
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function(){
|
||||
if (window.DATA) construire(window.DATA);
|
||||
});
|
||||
@@ -0,0 +1,297 @@
|
||||
/* ==================================================================
|
||||
Jeux du module A — 2e différenciée
|
||||
Chargé après assets/theme.css, dont il reprend toutes les couleurs.
|
||||
Les jeux sont conçus pour la projection au TBI : cibles larges,
|
||||
contrastes francs, aucun texte sous 0,85 rem.
|
||||
================================================================== */
|
||||
|
||||
/* ---------- séances affichées une par une ---------- */
|
||||
|
||||
section[hidden] { display: none; }
|
||||
|
||||
/* ---------- plan et objectifs de la séance ---------- */
|
||||
|
||||
ol.plan {
|
||||
counter-reset: s;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
ol.plan li {
|
||||
counter-increment: s;
|
||||
position: relative;
|
||||
padding: .45rem 0 .45rem 3rem;
|
||||
border-bottom: 1px solid var(--trait);
|
||||
}
|
||||
ol.plan li::before {
|
||||
content: counter(s);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: .45rem;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
text-align: center;
|
||||
background: var(--encre);
|
||||
color: var(--papier);
|
||||
font-size: .9rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
ul.but { list-style: none; padding: 0; max-width: var(--lecture); }
|
||||
ul.but li { padding: .35rem 0 .35rem 1.6rem; position: relative; }
|
||||
ul.but li::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: .95rem;
|
||||
width: .7rem;
|
||||
height: .7rem;
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
/* ---------- carte d'un jeu ---------- */
|
||||
|
||||
.atelier {
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .5rem;
|
||||
margin: 1.2rem 0;
|
||||
background: var(--blanc);
|
||||
overflow: hidden;
|
||||
}
|
||||
.atelier > h4 {
|
||||
margin: 0;
|
||||
padding: .6rem 1rem;
|
||||
background: var(--encre);
|
||||
color: var(--papier);
|
||||
font-family: var(--police-titre);
|
||||
font-size: .95rem;
|
||||
font-weight: 700;
|
||||
display: flex;
|
||||
gap: .6rem;
|
||||
align-items: baseline;
|
||||
}
|
||||
.atelier > h4 .num {
|
||||
background: var(--accent);
|
||||
color: var(--encre);
|
||||
font-size: .78rem;
|
||||
padding: .05rem .45rem;
|
||||
border-radius: .2rem;
|
||||
}
|
||||
.atelier .corps { padding: 1rem; }
|
||||
.consigne { margin: 0 0 .9rem; font-size: .95rem; max-width: var(--lecture); }
|
||||
|
||||
/* ---------- barre d'état d'un jeu ---------- */
|
||||
|
||||
.barre {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .7rem 1.4rem;
|
||||
align-items: center;
|
||||
margin: .2rem 0 .9rem;
|
||||
font-size: .95rem;
|
||||
}
|
||||
.cible-txt { font-weight: 700; font-size: 1.05rem; }
|
||||
.score { color: var(--encre-douce); font-size: .9rem; }
|
||||
|
||||
/* ---------- boutons de jeu ---------- */
|
||||
|
||||
.vf button,
|
||||
.qcm .choix button,
|
||||
.paires button,
|
||||
.liste button,
|
||||
.etape {
|
||||
font: inherit;
|
||||
background: var(--blanc);
|
||||
color: var(--encre);
|
||||
border: 2px solid var(--encre);
|
||||
border-radius: .3rem;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* ---------- aire de pions (jeu des nombres) ---------- */
|
||||
|
||||
.aire {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 22rem;
|
||||
background: var(--papier);
|
||||
border: 2px solid var(--trait-fort);
|
||||
border-radius: .4rem;
|
||||
overflow: hidden;
|
||||
touch-action: none;
|
||||
}
|
||||
.pion {
|
||||
position: absolute;
|
||||
width: 3.2rem;
|
||||
height: 3.2rem;
|
||||
line-height: 3.2rem;
|
||||
text-align: center;
|
||||
font-family: var(--police-titre);
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
background: var(--blanc);
|
||||
color: var(--encre);
|
||||
border: 2px solid var(--encre);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
padding: 0;
|
||||
}
|
||||
.pion.fait { background: var(--juste); border-color: var(--juste); color: #fff; }
|
||||
.pion.actif { background: var(--cible); border-color: var(--cible); }
|
||||
|
||||
.rate { animation: secousse .25s; }
|
||||
@keyframes secousse { 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
|
||||
|
||||
/* ---------- double-clic : les douze boîtes ---------- */
|
||||
|
||||
.boites {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: .7rem;
|
||||
max-width: 34rem;
|
||||
}
|
||||
.boite {
|
||||
aspect-ratio: 1 / 1;
|
||||
border: 2px solid var(--encre);
|
||||
border-radius: .3rem;
|
||||
background: var(--blanc);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.boite.ouverte { background: var(--juste); border-color: var(--juste); }
|
||||
.boite .forme { width: 52%; height: 52%; opacity: 0; }
|
||||
.boite.ouverte .forme { background: #fff; opacity: 1; border-radius: 50%; }
|
||||
|
||||
/* ---------- glisser-déposer dans des bacs ---------- */
|
||||
|
||||
.tri { display: flex; flex-wrap: wrap; gap: 1.2rem; }
|
||||
.reserve {
|
||||
flex: 1 1 16rem;
|
||||
min-height: 8rem;
|
||||
padding: .6rem;
|
||||
border: 2px dashed var(--trait-fort);
|
||||
border-radius: .4rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .5rem;
|
||||
align-content: flex-start;
|
||||
}
|
||||
.bacs { flex: 2 1 22rem; display: flex; gap: .8rem; flex-wrap: wrap; }
|
||||
.bac {
|
||||
flex: 1 1 7rem;
|
||||
min-height: 8rem;
|
||||
border: 2px solid var(--encre);
|
||||
border-radius: .4rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .5rem;
|
||||
align-content: flex-start;
|
||||
padding: .5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bac .titre {
|
||||
flex: 1 0 100%;
|
||||
font-size: .85rem;
|
||||
text-align: center;
|
||||
color: var(--encre-douce);
|
||||
}
|
||||
.bac.vise { background: var(--cible-fond); border-color: var(--cible); }
|
||||
|
||||
.jeton {
|
||||
font: inherit;
|
||||
padding: .4rem .65rem;
|
||||
background: var(--blanc);
|
||||
border: 2px solid var(--encre);
|
||||
border-radius: .3rem;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
font-size: .88rem;
|
||||
touch-action: none;
|
||||
}
|
||||
/* Sélection au clic : alternative au glisser pour qui ne maîtrise pas
|
||||
encore le maintien du bouton, et seul moyen au clavier. */
|
||||
.jeton.choisi { background: var(--cible); border-color: var(--cible); }
|
||||
.jeton.pris {
|
||||
position: fixed;
|
||||
z-index: 99;
|
||||
pointer-events: none;
|
||||
cursor: grabbing;
|
||||
box-shadow: 0 6px 14px rgba(22, 48, 43, .3);
|
||||
}
|
||||
.jeton .glyphe { display: block; width: 2rem; height: 2rem; }
|
||||
|
||||
/* ---------- remise en ordre ---------- */
|
||||
|
||||
.etapes { display: flex; flex-direction: column; gap: .5rem; max-width: 42rem; }
|
||||
.etape { padding: .5rem .75rem; }
|
||||
.etape.placee { background: var(--juste); border-color: var(--juste); color: #fff; cursor: default; }
|
||||
.rang { display: inline-block; min-width: 1.6rem; font-weight: 700; }
|
||||
|
||||
/* ---------- vrai ou faux ---------- */
|
||||
|
||||
.vf { max-width: var(--lecture); }
|
||||
.vf .ligne {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .5rem;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
border-bottom: 1px solid var(--trait);
|
||||
}
|
||||
.vf .txt { flex: 1 1 18rem; }
|
||||
.vf .verdict { font-size: .85rem; flex: 1 1 100%; }
|
||||
.vf button { padding: .25rem .8rem; }
|
||||
.vf button.choisi { background: var(--encre); color: var(--papier); }
|
||||
|
||||
.juste { color: var(--juste); }
|
||||
.faux { color: var(--erreur); }
|
||||
|
||||
/* ---------- questions à choix ---------- */
|
||||
|
||||
.qcm { max-width: var(--lecture); }
|
||||
.qcm .q { font-weight: 700; margin: .2rem 0 .6rem; }
|
||||
.qcm .choix { display: flex; flex-wrap: wrap; gap: .5rem; }
|
||||
.qcm .choix button { padding: .4rem .85rem; }
|
||||
.qcm .choix button.bon { background: var(--juste); border-color: var(--juste); color: #fff; }
|
||||
.qcm .choix button.mauvais { background: var(--erreur); border-color: var(--erreur); color: #fff; }
|
||||
.qcm .retour { margin-top: .7rem; font-size: .9rem; min-height: 1.4rem; }
|
||||
|
||||
/* ---------- paires à relier ---------- */
|
||||
|
||||
.paires { display: flex; gap: 1rem; flex-wrap: wrap; max-width: var(--lecture); }
|
||||
.paires .col { flex: 1 1 13rem; display: flex; flex-direction: column; gap: .45rem; }
|
||||
.paires button { font-size: .88rem; padding: .45rem .7rem; }
|
||||
.paires button.choisi { background: var(--cible); border-color: var(--cible); }
|
||||
.paires button.liee { background: var(--juste); border-color: var(--juste); color: #fff; cursor: default; }
|
||||
|
||||
/* ---------- parcours de dossiers ---------- */
|
||||
|
||||
.chemin { max-width: 40rem; }
|
||||
.chemin .fil {
|
||||
font-size: .9rem;
|
||||
color: var(--encre-douce);
|
||||
margin-bottom: .6rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
.liste { display: flex; flex-direction: column; gap: .4rem; }
|
||||
.liste button { padding: .45rem .7rem; }
|
||||
.liste button.dossier::before { content: "[dossier] "; color: var(--encre-douce); font-size: .8rem; }
|
||||
.liste button.fichier::before { content: "[fichier] "; color: var(--encre-douce); font-size: .8rem; }
|
||||
|
||||
/* ---------- schémas à zones ---------- */
|
||||
|
||||
figure.schema { margin: 0; max-width: 30rem; }
|
||||
.zone { fill: var(--blanc); stroke: var(--encre); stroke-width: 2; cursor: pointer; }
|
||||
.zone:hover { fill: var(--cible-fond); }
|
||||
.zone.trouve { fill: var(--juste-fond); stroke: var(--juste); }
|
||||
svg text { font-family: inherit; font-size: 11px; fill: var(--encre); pointer-events: none; }
|
||||
|
||||
@media print {
|
||||
section[hidden] { display: block; }
|
||||
.aire, .boites { display: none; }
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
/* ==================================================================
|
||||
Thème commun de la plateforme « Mes cours » — M. Courcelle
|
||||
------------------------------------------------------------------
|
||||
Une seule feuille pour toute la plateforme : la page d'aiguillage,
|
||||
les index de classe et les pages de module partagent ces jetons,
|
||||
cette typographie et ces composants. Les feuilles spécialisées
|
||||
(exercices-commune.css, jeux-differenciee.css, atelier-texte.css)
|
||||
ne redéfinissent jamais une couleur en dur : elles consomment les
|
||||
variables déclarées ici.
|
||||
|
||||
Pour ajouter une classe :
|
||||
1. un couple --xxx-fond / --xxx-trait / --xxx-encre dans :root ;
|
||||
2. une règle .classe-xxx plus bas ;
|
||||
3. les règles de la tuile (.classe--xxx) dans index.html.
|
||||
================================================================== */
|
||||
|
||||
:root {
|
||||
/* --- encres et papiers ------------------------------------------ */
|
||||
--encre: #16302B; /* texte principal, vert très sombre */
|
||||
--encre-douce: #3E5751; /* texte secondaire, AA sur tous les fonds */
|
||||
--papier: #FBFCFB; /* fond de page */
|
||||
--blanc: #FFFFFF; /* fond des cartes et des champs */
|
||||
--trait: #D5DEDA; /* bordures neutres */
|
||||
--trait-fort: #B3C2BC;
|
||||
|
||||
/* --- couleurs par classe ---------------------------------------- */
|
||||
/* -fond : aplat pâle ; -trait : filet vif, jamais du texte ;
|
||||
-encre : variante sombre du filet, contraste AA pour du texte. */
|
||||
--tc-fond: #FBE1E7; --tc-trait: #D6336C; --tc-encre: #B82A59;
|
||||
--diff-fond: #DDF5EC; --diff-trait: #05BC8A; --diff-encre: #036F51;
|
||||
--comm-fond: #FDF0CF; --comm-trait: #E0A100; --comm-encre: #7F5B00;
|
||||
--ts-fond: #DFEAFB; --ts-trait: #2F6FDB; --ts-encre: #215FC2;
|
||||
--ae-fond: #F1E3F7; --ae-trait: #9B4DCA; --ae-encre: #8840B4;
|
||||
|
||||
/* --- couleurs de verdict ---------------------------------------- */
|
||||
--juste: #1E7A4C;
|
||||
--juste-fond: #E3F3EA;
|
||||
--erreur: #B0322A;
|
||||
--erreur-fond: #F9E5E3;
|
||||
--cible: #F5C542; /* surlignage, marqueur */
|
||||
--cible-fond: #FDF6E1;
|
||||
|
||||
/* --- accent courant --------------------------------------------- */
|
||||
/* Neutre par défaut ; chaque page de classe le remplace en posant
|
||||
une classe .classe-xxx sur <body>. Tout le reste de la plateforme
|
||||
ne connaît que --accent, --accent-fond et --accent-encre. */
|
||||
--accent: var(--encre);
|
||||
--accent-fond: #EDF2F0;
|
||||
--accent-encre: var(--encre);
|
||||
|
||||
/* --- typographie ------------------------------------------------- */
|
||||
--police-titre: "JetBrains Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
|
||||
--police-texte: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||||
--police-doc: Cambria, Georgia, "Times New Roman", serif; /* specimens de traitement de texte */
|
||||
|
||||
/* --- mesures ------------------------------------------------------ */
|
||||
--lecture: 64ch; /* largeur de confort d'un paragraphe */
|
||||
--page: 58rem; /* largeur de la colonne de contenu */
|
||||
--gouttiere: 1.5rem; /* marge latérale, identique partout */
|
||||
--base: 17px;
|
||||
}
|
||||
|
||||
/* Identité de classe : posée sur <body>. */
|
||||
.classe-tc { --accent: var(--tc-trait); --accent-fond: var(--tc-fond); --accent-encre: var(--tc-encre); }
|
||||
.classe-diff { --accent: var(--diff-trait); --accent-fond: var(--diff-fond); --accent-encre: var(--diff-encre); }
|
||||
.classe-comm { --accent: var(--comm-trait); --accent-fond: var(--comm-fond); --accent-encre: var(--comm-encre); }
|
||||
.classe-ts { --accent: var(--ts-trait); --accent-fond: var(--ts-fond); --accent-encre: var(--ts-encre); }
|
||||
.classe-ae { --accent: var(--ae-trait); --accent-fond: var(--ae-fond); --accent-encre: var(--ae-encre); }
|
||||
|
||||
/* ==================================================================
|
||||
Base
|
||||
================================================================== */
|
||||
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
|
||||
html {
|
||||
font-size: var(--base);
|
||||
scroll-behavior: smooth;
|
||||
scroll-padding-top: 1rem;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--papier);
|
||||
color: var(--encre);
|
||||
font-family: var(--police-texte);
|
||||
font-size: 1rem;
|
||||
line-height: 1.55;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
/* Mode projection : agrandit toute la page d'un coup pour le TBI.
|
||||
Le jeton doit être posé sur <html> et non sur <body> : c'est <html>
|
||||
qui porte font-size, et donc la valeur du rem pour toute la page. */
|
||||
html.projection { --base: 25px; }
|
||||
|
||||
p, ul, ol { max-width: var(--lecture); }
|
||||
p { margin: 0 0 .9rem; }
|
||||
li { margin-bottom: .35rem; }
|
||||
|
||||
a { color: var(--accent-encre); }
|
||||
a:hover { text-decoration-thickness: 2px; }
|
||||
|
||||
strong { font-weight: 600; }
|
||||
|
||||
code, kbd {
|
||||
font-family: ui-monospace, "JetBrains Mono", Consolas, "Courier New", monospace;
|
||||
font-size: .92em;
|
||||
background: var(--accent-fond);
|
||||
padding: .05rem .3rem;
|
||||
border-radius: .2rem;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 3px solid var(--accent-encre);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html { scroll-behavior: auto; }
|
||||
*, *::before, *::after { animation: none !important; transition: none !important; }
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
En-tête de page
|
||||
Fil d'Ariane, titre, sous-titre, et le filet de couleur de la
|
||||
classe — le même motif que les tuiles de la page d'accueil.
|
||||
================================================================== */
|
||||
|
||||
.entete {
|
||||
background: var(--blanc);
|
||||
border-bottom: .5rem solid var(--accent);
|
||||
}
|
||||
|
||||
.entete__interieur {
|
||||
max-width: calc(var(--page) + 2 * var(--gouttiere));
|
||||
margin: 0 auto;
|
||||
padding: 1rem var(--gouttiere) 1.1rem;
|
||||
}
|
||||
|
||||
.ariane {
|
||||
font-size: .85rem;
|
||||
color: var(--encre-douce);
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
.ariane a { color: var(--encre-douce); }
|
||||
.ariane a:hover { color: var(--accent-encre); }
|
||||
.ariane span[aria-hidden] { padding: 0 .35rem; color: var(--trait-fort); }
|
||||
.ariane strong { color: var(--encre); font-weight: 600; }
|
||||
|
||||
.entete h1 {
|
||||
margin: 0;
|
||||
font-family: var(--police-titre);
|
||||
font-size: clamp(1.35rem, 3.2vw, 1.9rem);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.entete__meta {
|
||||
margin: .35rem 0 0;
|
||||
max-width: none;
|
||||
color: var(--encre-douce);
|
||||
font-size: .95rem;
|
||||
}
|
||||
|
||||
/* Outils à droite du titre (bouton « Agrandir », par exemple) */
|
||||
.entete__barre {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .6rem 1.2rem;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Corps de page
|
||||
================================================================== */
|
||||
|
||||
.contenu {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
max-width: calc(var(--page) + 2 * var(--gouttiere));
|
||||
margin: 0 auto;
|
||||
padding: 2rem var(--gouttiere) 4rem;
|
||||
}
|
||||
|
||||
.chapeau {
|
||||
font-size: 1.08rem;
|
||||
color: var(--encre-douce);
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: var(--police-titre);
|
||||
font-size: clamp(1.15rem, 2.6vw, 1.45rem);
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 1.25;
|
||||
margin: 2.8rem 0 .8rem;
|
||||
padding-top: .8rem;
|
||||
border-top: 2px solid var(--accent);
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
|
||||
.contenu > h2:first-child,
|
||||
section > h2:first-child,
|
||||
.inner > h2:first-child {
|
||||
border-top: 0;
|
||||
padding-top: 0;
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: var(--police-titre);
|
||||
font-size: 1.02rem;
|
||||
font-weight: 700;
|
||||
margin: 1.8rem 0 .5rem;
|
||||
color: var(--accent-encre);
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: .95rem;
|
||||
font-weight: 600;
|
||||
margin: 1.2rem 0 .4rem;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Encadrés
|
||||
.encadre rappel neutre
|
||||
.encadre--theorie ce qu'il faut savoir avant de jouer
|
||||
.encadre--cle la règle à retenir
|
||||
.encadre--attention piège fréquent
|
||||
================================================================== */
|
||||
|
||||
.encadre {
|
||||
background: var(--accent-fond);
|
||||
border-left: .4rem solid var(--accent);
|
||||
border-radius: 0 .4rem .4rem 0;
|
||||
padding: .9rem 1.1rem;
|
||||
margin: 1.4rem 0;
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
.encadre > :first-child { margin-top: 0; }
|
||||
.encadre > :last-child { margin-bottom: 0; }
|
||||
.encadre h3 { margin-top: 0; color: var(--encre); }
|
||||
|
||||
.encadre--theorie { background: var(--accent-fond); }
|
||||
.encadre--cle { background: var(--cible-fond); border-left-color: var(--cible); }
|
||||
.encadre--attention { background: var(--erreur-fond); border-left-color: var(--erreur); }
|
||||
|
||||
/* ==================================================================
|
||||
Boutons
|
||||
================================================================== */
|
||||
|
||||
.action {
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
font-size: .95rem;
|
||||
background: var(--encre);
|
||||
color: var(--papier);
|
||||
border: 2px solid var(--encre);
|
||||
border-radius: .4rem;
|
||||
padding: .5rem 1.05rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.action:hover { background: var(--accent-encre); border-color: var(--accent-encre); }
|
||||
|
||||
.action--secondaire {
|
||||
background: var(--blanc);
|
||||
color: var(--encre);
|
||||
}
|
||||
.action--secondaire:hover { background: var(--encre); color: var(--papier); border-color: var(--encre); }
|
||||
|
||||
.action[disabled] { opacity: .5; cursor: default; }
|
||||
.action[disabled]:hover { background: var(--encre); border-color: var(--encre); }
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: .5rem;
|
||||
flex-wrap: wrap;
|
||||
margin: .9rem 0;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Sommaire d'un module (bandeau de blocs / de séances)
|
||||
================================================================== */
|
||||
|
||||
.sommaire {
|
||||
background: var(--accent-fond);
|
||||
border-bottom: 1px solid var(--trait);
|
||||
}
|
||||
|
||||
.sommaire__interieur {
|
||||
max-width: calc(var(--page) + 2 * var(--gouttiere));
|
||||
margin: 0 auto;
|
||||
padding: .7rem var(--gouttiere);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .4rem;
|
||||
}
|
||||
|
||||
.sommaire a,
|
||||
.sommaire button {
|
||||
font: inherit;
|
||||
font-size: .9rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
color: var(--encre);
|
||||
background: var(--blanc);
|
||||
border: 1px solid var(--trait-fort);
|
||||
border-radius: .35rem;
|
||||
padding: .35rem .8rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.sommaire a:hover,
|
||||
.sommaire button:hover { border-color: var(--encre); }
|
||||
|
||||
.sommaire a[aria-current="page"],
|
||||
.sommaire button[aria-current="true"] {
|
||||
background: var(--encre);
|
||||
border-color: var(--encre);
|
||||
color: var(--papier);
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Index de classe : la liste des modules
|
||||
Un <li class="module"> par module. Voir le gabarit en commentaire
|
||||
dans chaque index de classe.
|
||||
================================================================== */
|
||||
|
||||
.modules {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 1.2rem 0 0;
|
||||
max-width: none;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.module { margin: 0; }
|
||||
|
||||
.module__lien {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
gap: .3rem;
|
||||
background: var(--blanc);
|
||||
border: 1px solid var(--trait);
|
||||
border-top: .4rem solid var(--accent);
|
||||
border-radius: .5rem;
|
||||
padding: 1.1rem 1.2rem 1.2rem;
|
||||
color: var(--encre);
|
||||
text-decoration: none;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.module__lien:hover { border-color: var(--accent); border-top-color: var(--accent); }
|
||||
.module__lien:hover .module__titre { text-decoration: underline; text-decoration-thickness: 2px; }
|
||||
}
|
||||
|
||||
.module__num {
|
||||
font-family: var(--police-titre);
|
||||
font-size: .78rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: .04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent-encre);
|
||||
}
|
||||
|
||||
.module__titre {
|
||||
font-family: var(--police-titre);
|
||||
font-size: 1.12rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.module__resume {
|
||||
color: var(--encre-douce);
|
||||
font-size: .95rem;
|
||||
margin-top: .2rem;
|
||||
}
|
||||
|
||||
.module__meta {
|
||||
margin-top: auto;
|
||||
padding-top: .8rem;
|
||||
color: var(--encre-douce);
|
||||
font-size: .85rem;
|
||||
}
|
||||
|
||||
/* Module annoncé mais pas encore en ligne : même carte, sans lien. */
|
||||
.module--bientot .module__lien {
|
||||
border-top-color: var(--trait-fort);
|
||||
background: var(--papier);
|
||||
color: var(--encre-douce);
|
||||
cursor: default;
|
||||
}
|
||||
.module--bientot .module__num { color: var(--encre-douce); }
|
||||
|
||||
/* Classe sans aucun module publié */
|
||||
.vide {
|
||||
background: var(--blanc);
|
||||
border: 2px dashed var(--trait-fort);
|
||||
border-radius: .5rem;
|
||||
padding: 2rem 1.5rem;
|
||||
text-align: center;
|
||||
color: var(--encre-douce);
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Tableaux, figures, captures
|
||||
================================================================== */
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
max-width: var(--lecture);
|
||||
margin: 1.2rem 0;
|
||||
font-size: .95rem;
|
||||
}
|
||||
th, td {
|
||||
border-bottom: 1px solid var(--trait);
|
||||
padding: .45rem .6rem;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
th {
|
||||
background: var(--accent-fond);
|
||||
border-bottom: 2px solid var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 1.4rem 0;
|
||||
max-width: var(--lecture);
|
||||
}
|
||||
figure img {
|
||||
width: 100%;
|
||||
display: block;
|
||||
border: 1px solid var(--trait);
|
||||
border-radius: .3rem;
|
||||
}
|
||||
figcaption {
|
||||
font-size: .86rem;
|
||||
color: var(--encre-douce);
|
||||
margin-top: .4rem;
|
||||
}
|
||||
|
||||
/* Capture pas encore déposée : la page reste lisible et dit quoi ajouter. */
|
||||
.manque {
|
||||
border: 2px dashed var(--trait-fort);
|
||||
background: var(--papier);
|
||||
border-radius: .3rem;
|
||||
padding: 2rem 1rem;
|
||||
text-align: center;
|
||||
color: var(--encre-douce);
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Pied de page
|
||||
================================================================== */
|
||||
|
||||
.pied {
|
||||
border-top: 1px solid var(--trait);
|
||||
background: var(--blanc);
|
||||
color: var(--encre-douce);
|
||||
font-size: .88rem;
|
||||
}
|
||||
.pied__interieur {
|
||||
max-width: calc(var(--page) + 2 * var(--gouttiere));
|
||||
margin: 0 auto;
|
||||
padding: 1.2rem var(--gouttiere) 2rem;
|
||||
}
|
||||
.pied a { color: var(--encre-douce); }
|
||||
|
||||
/* ==================================================================
|
||||
Impression
|
||||
================================================================== */
|
||||
|
||||
@media print {
|
||||
body { background: #fff; }
|
||||
.sommaire, .action, .actions, .entete__barre button { display: none; }
|
||||
.entete { border-bottom-width: 2px; }
|
||||
.contenu { max-width: none; padding: 0; }
|
||||
}
|
||||
Reference in New Issue
Block a user