/* Quatre — feuille unique, mobile d'abord.
 *
 * LE SOCLE EST COPIÉ DE DOUZE (décision 16), avec ses leçons : les jetons
 * neutres, la grille 4 pt, Inter et Space Grotesk, 640 px au plus, la zone sûre
 * du haut, et le texte posé SUR l'accent qui est un jeton et non `#fff` — en
 * sombre, Douze l'avait vu tomber à 1,48 : 1.
 *
 * DEUX ÉCARTS, et par règle :
 *   · les POLICES sont servies d'ici, pas chez Google. Douze les charge sur
 *     fonts.googleapis.com, ce qui envoie l'adresse de l'élève à Google à la
 *     première ouverture. Quatre promet « pas de traceur » (décision 7) ;
 *   · l'ACCENT n'est pas le vert de Douze : c'est le bleu des FIGURES de Quatre
 *     (`#0369A1`, la famille sky des traits `#0284C7`). Tranché par Marc le
 *     20.09.2026 — décision 18. Contrastes MESURÉS : voir le CLAUDE.md.
 *
 * Les contrastes ne sont PAS recopiés d'un document : Douze a payé cher un
 * « 5,1 : 1 » recopié qui mesurait 3,19. Ils se mesurent au rendu.
 */
@font-face { font-family: "Inter"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("fontes/inter-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("fontes/inter-latin-600-normal.woff2") format("woff2"); }
/* π (U+03C0), décision de Marc D1 (24.09.2026) : un sous-ensemble d'inter-greek-400 et -600 de
   @fontsource/inter 5.3.0 (Inter 4.001, la version du texte), refait par fontTools, qui ne porte
   que π ; 744 et 760 octets. Le navigateur ne le charge que pour ce caractère. */
@font-face { font-family: "Inter"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("fontes/inter-pi-400-normal.woff2") format("woff2"); unicode-range: U+03C0; }
@font-face { font-family: "Inter"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("fontes/inter-pi-600-normal.woff2") format("woff2"); unicode-range: U+03C0; }
/* ≈ (U+2248), question 1 de Marc (25.09.2026) : aucun sous-ensemble d'@fontsource ne le porte ; tiré d'Inter 4.001
   complète (google/fonts, _polices_sources/), instanciée en 400 et 600, qui ne porte que ≈ ; 992 octets chacun. */
@font-face { font-family: "Inter"; font-weight: 400; font-style: normal; font-display: swap;
  src: url("fontes/inter-approx-400-normal.woff2") format("woff2"); unicode-range: U+2248; }
@font-face { font-family: "Inter"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("fontes/inter-approx-600-normal.woff2") format("woff2"); unicode-range: U+2248; }
@font-face { font-family: "Space Grotesk"; font-weight: 500; font-style: normal; font-display: swap;
  src: url("fontes/space-grotesk-latin-500-normal.woff2") format("woff2"); }
@font-face { font-family: "Space Grotesk"; font-weight: 600; font-style: normal; font-display: swap;
  src: url("fontes/space-grotesk-latin-600-normal.woff2") format("woff2"); }

:root {
  --encre: #0F172A; --encre-forte: #334155; --encre-douce: #64748B;
  --papier: #F8FAFC; --carte: #FFFFFF; --trait: #E2E8F0; --trait-doux: #F1F5F9;
  --accent: #0369A1; --accent-fort: #075985; --accent-doux: #E0F2FE;
  --sur-accent: #FFFFFF;
  --e1: 4px; --e2: 8px; --e3: 12px; --e4: 16px; --e6: 24px; --e8: 32px; --e12: 48px;
  --rayon: 8px; --rayon-lg: 12px; --rayon-xl: 16px;
  --ombre-sm: 0 1px 2px rgba(15, 23, 42, .04);
  --corps: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --titre: "Space Grotesk", "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  --sat: env(safe-area-inset-top, 0px);
}
@media (prefers-color-scheme: dark) {
  :root {
    --encre: #F1F5F9; --encre-forte: #CBD5E1; --encre-douce: #94A3B8;
    --papier: #0F172A; --carte: #1E293B; --trait: #334155; --trait-doux: #1E293B;
    --accent: #7DD3FC; --accent-fort: #BAE6FD; --accent-doux: #0C4A6E;
    --sur-accent: #0F172A;
  }
  /* les figures sont dessinées pour un fond clair : on leur donne le leur */
  .figure img { background: #FFFFFF; border-radius: var(--rayon); }
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--papier); color: var(--encre-forte);
  font-family: var(--corps); font-size: 17px; line-height: 1.5;
  -webkit-text-size-adjust: 100%; -webkit-font-smoothing: antialiased; }
main { max-width: 640px; margin: 0 auto; min-height: 100svh; display: flex; flex-direction: column;
  padding: calc(var(--sat) + var(--e4)) var(--e4) calc(var(--e8) + env(safe-area-inset-bottom, 0px)); }

/* ── la coquille commune aux applis MathVaud (décision de Marc du 04.11.2026) : une barre de retour hors de l'accueil,
 *    le nom de l'app et qui la fait, un pied. CACHÉS PAR DÉFAUT, montrés sur les vues que app.js a nommées
 *    (body[data-vue]) : une fiche ouverte à froid ne montre rien de MathVaud (V1-POR-02). */
.chev { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }
/* la barre de retour : la même partout, 44 px de cible, encre forte, sans soulignement */
.barre-retour { display: none; align-items: center; gap: 2px; align-self: flex-start; min-height: 44px;
  margin: calc(-1 * var(--e2)) 0 var(--e2) -4px; padding-right: var(--e2); font-size: 16px; font-weight: 600;
  color: var(--encre-forte); text-decoration: none; }
body[data-vue="fiche"] .barre-retour, body[data-vue="theme"] .barre-retour,
body[data-vue="nouveautes"] .barre-retour, body[data-vue="a-propos"] .barre-retour { display: inline-flex; }
/* le nom de l'app : en grand avec l'icône sur l'accueil ; en une ligne sur les nouveautés et l'à-propos */
.tete { display: none; margin-bottom: var(--e4); }
body[data-vue="index"] .tete, body[data-vue="nouveautes"] .tete, body[data-vue="a-propos"] .tete { display: block; }
body[data-vue="index"] .tete { padding-top: var(--e4); margin-bottom: var(--e2); }
.icone-app { display: none; width: 56px; height: 56px; border-radius: var(--rayon-lg); margin: 0 0 var(--e3); }
body[data-vue="index"] .icone-app { display: block; }
.marque-ligne { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--e3); margin: 0; }
.marque { font-family: var(--titre); font-weight: 600; font-size: 22px; letter-spacing: -.01em; color: var(--encre); }
body[data-vue="index"] .marque { font-size: 32px; line-height: 1.2; }

/* Le focus posé PAR PROGRAMME sur le titre, à chaque changement de page, sert
 * au lecteur d'écran — il annonce la nouvelle page. Un titre n'est pas un
 * contrôle : aucun utilisateur de clavier n'y arrive par Tab (tabindex="-1"),
 * donc son contour n'aide personne. Vu au rendu : un cadre noir sur les quatre
 * vues. Les VRAIS contrôles gardent le leur. */
#vue:focus, #vue [tabindex="-1"]:focus { outline: none; }
h1 { font-family: var(--titre); font-weight: 600; color: var(--encre);
  font-size: 26px; line-height: 1.2; letter-spacing: -.01em; margin: 0 0 var(--e6); }

/* ── l'accueil : la phrase qui nomme le champ, le champ, puis une carte par thème */
.intro { color: var(--encre-douce); margin: 0 0 var(--e4); }
.intro h1 { display: inline; font-family: var(--corps); font-size: inherit; font-weight: 600; line-height: inherit;
  letter-spacing: normal; color: var(--encre); margin: 0; }
.cherche { width: 100%; font: inherit; font-size: 17px; color: var(--encre);
  background: var(--carte); border: 1px solid var(--trait); border-radius: var(--rayon-lg);
  padding: var(--e3) var(--e4); min-height: 48px; margin-bottom: var(--e4); }
.cherche:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
/* une colonne qui peut descendre sous le plus long mot : sans elle, « parallélogramme » élargissait la grille au-delà de
 * l'écran à 195 px, les cartes étant en flex (mesuré au banc de rendu le 04.11.2026) */
.liste { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--e2); }
.liste a, a.porte { display: flex; align-items: center; justify-content: space-between; gap: var(--e3);
  background: var(--carte); border: 1px solid var(--trait);
  border-radius: var(--rayon-lg); padding: var(--e4); min-height: 44px;
  color: var(--encre); text-decoration: none; font-weight: 600; line-height: 1.35;
  box-shadow: var(--ombre-sm); }
.liste a > span { min-width: 0; }
.liste a .chev, a.porte .chev { color: var(--encre-douce); }
.liste a:active, a.porte:active { background: var(--accent-doux); }
/* une carte par thème (décision 23, amendée le 04.11.2026) : son nom, et dessous ce que sa page porte, compté */
.titre-portes { font-family: var(--titre); font-weight: 500; font-size: 17px; color: var(--encre-douce);
  margin: var(--e6) 0 var(--e3); }
.portes { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--e3); }
a.porte { min-height: 64px; padding: var(--e3) var(--e4); font-family: var(--titre); font-size: 18px; line-height: 1.3; }
a.porte .txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
a.porte .compte { font-family: var(--corps); font-weight: 400; font-size: 15px; color: var(--encre-douce); }
.vide { color: var(--encre-douce); margin: var(--e4) 0; }
/* une fiche À VENIR (décision 25) : la place d'une carte, pas une carte. Ni lien ni ombre, un trait tireté, le titre
 * en gris, puis « , à venir » en plus petit, dans la même ligne de texte : ce qui se voit est ce qui se lit.
 * Le contraste se MESURE au rendu, sur cette surface (`_verifie_rendu_app.py`), dans les deux thèmes. */
.liste .a-venir { background: var(--carte); border: 1px dashed var(--trait); border-radius: var(--rayon-lg);
  padding: var(--e4); min-height: 44px; color: var(--encre-douce); line-height: 1.35; }
.liste .a-venir .mention { font-size: 14px; }

/* ── une fiche : quatre blocs, numérotés — le nom du produit, en discret */
.bloc { margin: 0 0 var(--e8); }
.bloc h2 { display: flex; align-items: baseline; gap: var(--e3); margin: 0 0 var(--e3);
  font-family: var(--titre); font-weight: 500; font-size: 19px; line-height: 1.3; color: var(--encre); }
.bloc h2 .n { flex: none; font-size: 13px; font-weight: 600; color: var(--accent);
  border: 1.5px solid currentColor; border-radius: 999px; width: 24px; height: 24px;
  display: inline-grid; place-items: center; transform: translateY(-2px); }
.texte-fiche p { margin: 0 0 var(--e3); }
.texte-fiche ol, .texte-fiche ul { margin: 0 0 var(--e3); padding-left: 1.4em; }
.texte-fiche li { margin-bottom: var(--e2); }
.texte-fiche strong { color: var(--encre); font-weight: 600; }
.figure { margin: var(--e4) 0; position: relative; }
.figure img { display: block; width: 100%; height: auto; }

/* ── la figure s'agrandit (décision 27, Marc, 15.10.2026). Un bouton transparent posé sur la figure : la toucher
 * l'ouvre ; une petite icône dans le coin le dit, sans un mot dans le bloc. */
.figure .agrandir { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0;
  background: transparent; border: 0; border-radius: var(--rayon); cursor: zoom-in; color: #0369A1; }
.figure .agrandir:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* L'icône vit sous la figure, dans une bande à elle : posée DESSUS, elle cachait de l'encre (« 2 cm » de F10). */
.texte-fiche .figure.agrandissable { padding-bottom: 40px; }
.figure .agrandir .icone { position: absolute; right: 0; bottom: 0; width: 32px; height: 32px;
  display: grid; place-items: center; background: #FFFFFF; border: 1px solid #CBD5E1; border-radius: 999px; }
/* Ouverte : la figure seule, sur toute la place, sur le fond clair des figures, dans les deux thèmes. Le fond ne
 * défile pas. Rien n'y interdit le zoom à deux doigts (aucun `touch-action`). */
html.loupe-ouverte { overflow: hidden; }
html.loupe-ouverte body { position: fixed; left: 0; right: 0; }
.loupe { position: fixed; inset: 0; z-index: 10; background: #FFFFFF; display: flex; flex-direction: column;
  overscroll-behavior: contain;
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px)
           env(safe-area-inset-left, 0px); }
.loupe-barre { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: var(--e2) var(--e3);
  padding: var(--e2) var(--e2) var(--e2) var(--e4); }
/* sur un écran étroit, la ligne d'aide prend sa propre ligne, pleine largeur, sous Fermer */
.loupe-aide { flex: 1 1 14em; margin: 0; font-size: 14px; line-height: 1.35; color: #475569; }
.loupe .fermer { margin-left: auto; }
.loupe .fermer { flex: none; white-space: nowrap;
  font: inherit; font-size: 17px; font-weight: 600; color: #0F172A; background: #FFFFFF;
  border: 1px solid #CBD5E1; border-radius: var(--rayon-lg); min-height: 44px; min-width: 44px;
  padding: 0 var(--e4); cursor: pointer; }
.loupe .fermer:focus-visible { outline: 2px solid #0369A1; outline-offset: 2px; }
.loupe img { flex: 1 1 auto; min-height: 0; width: 100%; height: 100%; object-fit: contain; display: block; }
.loupe img:focus { outline: none; }

/* ── copier le lien d'une fiche (décision 28, Marc, 15.10.2026) : sous les quatre blocs, discret */
.partage { margin: 0 0 var(--e6); }
.partage .copier { font: inherit; font-size: 15px; color: var(--accent); background: transparent;
  border: 1px solid var(--trait); border-radius: var(--rayon-lg); min-height: 44px; padding: 0 var(--e4);
  cursor: pointer; }
.partage .copier:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.partage .etat { font-size: 15px; color: var(--encre-douce); margin: var(--e2) 0 0; min-height: 1.5em; }
.partage .lien { display: block; width: 100%; margin-top: var(--e1); font: inherit; font-size: 15px;
  color: var(--encre); background: var(--carte); border: 1px solid var(--trait); border-radius: var(--rayon);
  padding: var(--e2) var(--e3); resize: none; overflow-wrap: anywhere; }

/* ── l'à-propos */
.a-propos h2 { font-family: var(--titre); font-weight: 500; font-size: 19px; color: var(--encre);
  margin: var(--e6) 0 var(--e2); }
.a-propos p, .a-propos li { margin: 0 0 var(--e3); }
.a-propos a { color: var(--accent); }
.version { font-size: 13px; color: var(--encre-douce); margin-top: var(--e8); }

/* ── les nouveautés (décision 26) : le chapeau, une entrée par date, puis les fiches à venir */
.nouveautes > p { margin: 0 0 var(--e6); }
.nouveautes h2 { font-family: var(--titre); font-weight: 500; font-size: 15px; color: var(--encre-douce);
  margin: var(--e6) 0 var(--e1); }
.nouveautes .entree p { margin: 0; }
.nouveautes .prevues h2 { font-size: 19px; color: var(--encre); margin-top: var(--e8); }
.nouveautes .prevues ul { margin: var(--e2) 0 0; padding-left: 1.4em; }
.nouveautes .prevues li { margin-bottom: var(--e2); }

/* ── la porte MathVaud, visible et sobre (décision 29, Marc, 18 octobre 2026, qui amende la 12 ; amendée le
 *    04.11.2026) : « par MathVaud » à côté du nom, sur l'accueil, les nouveautés et l'à-propos, et un encadré en bas
 *    de l'accueil, des pages de thème, des nouveautés et de l'à-propos. JAMAIS sur une fiche : une fiche répond à une
 *    question, elle ne vend rien. Un bouton BORDÉ, pas plein : l'accent plein ne sert rien ici. Les zones de toucher
 *    font 44 px au moins ; les contrastes sont mesurés au rendu, dans les deux thèmes. */
.tete .par-mathvaud { font-size: 15px; color: var(--accent); text-decoration: underline; text-underline-offset: 3px;
  min-height: 44px; display: inline-flex; align-items: center; }
.pied { margin-top: auto; padding-top: var(--e8); display: none; }
.pont-mathvaud { padding: var(--e4); border: 1px solid var(--trait); border-radius: var(--rayon-lg);
  background: var(--carte); }
.pont-mathvaud h2 { font-family: var(--titre); font-weight: 600; font-size: 17px; color: var(--encre);
  margin: 0 0 var(--e2); }
.pont-mathvaud p { margin: 0 0 var(--e3); font-size: 15px; color: var(--encre-forte); }
.bouton-mathvaud { display: flex; align-items: center; justify-content: center; min-height: 44px;
  padding: var(--e2) var(--e4); border: 1px solid var(--accent); border-radius: var(--rayon);
  font-size: 15px; font-weight: 500; color: var(--accent); background: var(--carte); text-decoration: none; }
/* le pied commun : un filet, « Un outil MathVaud » en texte à gauche, les deux pages à droite, même rang, même
 * discrétion (décision 26) ; à 195 px, elles passent à la ligne */
.pied-commun { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 var(--e4);
  margin-top: var(--e6); padding-top: var(--e2); border-top: 1px solid var(--trait); font-size: 15px;
  color: var(--encre-douce); }
.pages { display: flex; flex-wrap: wrap; column-gap: var(--e4); }
.pages a { font-size: 15px; color: var(--accent); text-decoration: underline; text-underline-offset: 3px;
  min-height: 44px; display: inline-flex; align-items: center; }
/* Cachée PAR DÉFAUT, montrée sur les quatre vues seulement : une fiche ouverte à froid, avant que app.js ait nommé
 * la vue, ne la montre pas (V1-POR-02). */
body[data-vue="index"] .pied, body[data-vue="theme"] .pied, body[data-vue="nouveautes"] .pied,
body[data-vue="a-propos"] .pied { display: block; }

/* ── les fractions : PAS ICI. Leurs deux valeurs sont MESURÉES et vivent dans
 *    `moteur/fraction.css`, que `build.py` copie dans `app/`. Une copie écrite à
 *    la main ici aurait dérivé à la première re-mesure. */

/* Une relation ne se coupe pas — voir build.py, relations_insecables (21.09.2026). */
.rel { white-space: nowrap; }

/* Un mot plus long que la ligne se coupe plutôt que de faire déborder la page (24.09.2026) :
 * vu au banc de rendu, à 195 px (390 px zoomé à 200 %), « parallélogramme » dans le titre
 * de F12 dépassait de 27 px. Ne joue qu'au-delà de la ligne : à 390 px, aucun mot n'y
 * arrive. Une relation (.rel, nowrap) n'est pas concernée, et le banc la mesure toujours. */
body { overflow-wrap: break-word; }
/* Le titre d'un bloc est un élément flex : sans min-width, il ne descend pas sous son plus long
 * mot, et « Sur un parallélogramme de base 6 cm » débordait encore de 9 px. */
.bloc h2 > span:not(.n) { min-width: 0; }
