/* polices servies depuis notre origine — aucune requête tierce (2026-08-24) */
@font-face{font-family:"Luciole";src:url("/polices/luciole-400.woff2") format("woff2");font-weight:100 550;font-style:normal;font-display:swap}
@font-face{font-family:"Luciole";src:url("/polices/luciole-700.woff2") format("woff2");font-weight:551 900;font-style:normal;font-display:swap}
@font-face{font-family:"Luciole";src:url("/polices/luciole-400i.woff2") format("woff2");font-weight:100 550;font-style:italic;font-display:swap}
@font-face{font-family:"Luciole";src:url("/polices/luciole-700i.woff2") format("woff2");font-weight:551 900;font-style:italic;font-display:swap}

:root{
  /* --- socle maison : papier crème, encre chaude, or constant --- */
  --papier:#FAF5EB;
  --carte:#FFFDF8;
  --encre:#241C17;
  --encre-2:#5A4E45;
  /* 2026-08-25 : #8A7C70 rendait 3,72:1 sur le papier — sous le seuil de 4,5:1,
     et c'est la couleur du CODE a dechiffrer des cryptogrammes. Releve : 4,76. */
  --encre-3:#776B60;
  --filet:#E3D8C6;
  /* 2,26:1 sur la case : les lignes qui separent les cases d'un sudoku sont un
     objet graphique necessaire (WCAG 1.4.11, seuil 3:1). Releve : 3,90. */
  --filet-grille:#8C7E68;
  --filet-fin:#EFE7D9;
  --or:#D4A852;
  --or-d:#A87F33;
  /* --- collection courante (surchargée par [data-coll]) --- */
  --coll:#241C17;
  --coll-d:#000000;
  --coll-lt:#F1EADC;
  --coll-soft:#E6DCC9;
  --ombre:0 1px 2px rgba(36,28,23,.05), 0 10px 30px -20px rgba(36,28,23,.45);
  /* --- grilles --- */
  --case:#FFFDF8;
  --case-fixe:#E7DAC0;   /* releve : 1,21:1 sur la case vide, trop proche ; le GRAS porte la distinction */
  --case-pleine:#2A2119;
  --erreur:#A32718;
  --juste:#1C6B4C;
  /* La trace du labyrinthe se lisait a 1,41:1 sur la case — la seule memoire du
     parcours, invisible. Jeton propre, mesure a 3,08:1. --coll-soft reste ce qu'il
     etait : d'autres jeux s'en servent pour un fond de selection, pas pour un trace. */
  /* l'anneau de focus a son jeton : --or-d sert aussi au trait du logo, et le
     durcir la aurait noirci la signature. Releve : 4,63:1 sur le papier. */
  --focus:#8A6520;
  --trace:#8E7038;   /* mesure 2,83:1 en rendu avec l'ancienne teinte + opacite 0,92 */
  /* LE STABILO A SON JETON, POUR LA MEME RAISON QUE --trace.
     Le trait de mot trouve etait peint avec --coll-soft, un creme a 1,21:1 sur le
     papier : la ou le lecteur cherche justement d'un coup d'oeil ce qu'il a deja
     trouve, il ne voyait presque rien. Contre-lecture du 2026-08-28 — et l'ancien
     carre par lettre ne valait pas mieux, a 1,28:1.
     Releve : surligne/papier 2,42:1, et la LETTRE reste a 6,38:1 par-dessus. Le
     seuil de 3:1 (WCAG 1.4.11) n'est pas atteint et c'est un choix mesure : le
     mot trouve est AUSSI barre dans la liste des mots, donc le surlignage n'est
     pas le seul porteur de l'information, et monter a 3:1 ferait tomber la lettre
     a 4,94:1 dans un produit gros caracteres. Le tenir ou le pousser est un
     arbitrage d'editeur, pas une decision de feuille de style. */
  --stabilo:#C09B3C;
  --faux-fond:#F6E4E0;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --papier:#16130F;
    --carte:#1E1A15;
    --encre:#F2EBDE;
    --encre-2:#C0B4A3;
    --encre-3:#8F8375;
    --filet:#332C24;
    /* 2,14:1 sur la case en sombre : la correction du 25/08 n'avait ete portee
       qu'a la palette claire. Releve : 3,26:1. */
    --filet-grille:#7A6B57;
    --filet-fin:#28221C;
    --or:#D9B369;
    --or-d:#EFCE8E;
    --coll:#F2EBDE;
    --coll-d:#FFFFFF;
    --coll-lt:#241F19;
    --coll-soft:#2E2820;
    --stabilo:#665429;   /* releve : 2,53:1 sur le papier sombre, lettre 6,18:1 */
    --ombre:0 1px 2px rgba(0,0,0,.5), 0 10px 30px -20px rgba(0,0,0,.9);
    --case:#1E1A15;
    --case-fixe:#2A241D;
    --case-pleine:#EDE3D2;
    --erreur:#E88A7C;
    --juste:#78C9A2;
    --focus:#EFCE8E;
    --trace:#7A653E;
    --faux-fond:#3A211C;
  }
}
:root[data-theme="dark"]{
  --papier:#16130F; --carte:#1E1A15; --encre:#F2EBDE; --encre-2:#C0B4A3;
  --encre-3:#8F8375; --filet:#332C24; --filet-grille:#7A6B57; --filet-fin:#28221C; --or:#D9B369; --or-d:#EFCE8E;
  --coll:#F2EBDE; --coll-d:#FFFFFF; --coll-lt:#241F19; --coll-soft:#2E2820;
  --ombre:0 1px 2px rgba(0,0,0,.5), 0 10px 30px -20px rgba(0,0,0,.9);
  --case:#1E1A15; --case-fixe:#2A241D; --case-pleine:#EDE3D2;
  --erreur:#E88A7C; --juste:#78C9A2; --focus:#EFCE8E; --trace:#7A653E; --faux-fond:#3A211C;
  --stabilo:#665429;
}

/* PLUS AUCUN STYLE EN LIGNE.
   `style-src 'unsafe-inline'` etait le seul trou d'une politique de contenu par
   ailleurs hermetique. Mesure de l'audit de securite du 2026-08-25 : le retrait de
   `'unsafe-inline'` ne coutait que neuf empreintes, toutes dues a vingt attributs
   `style=` decoratifs et a un bloc `<style>` dans le `<noscript>` — les quinze appels
   a `style.setProperty()` du moteur de jeu, eux, ne sont PAS soumis a `style-src`
   (le CSSOM n'y est pas soumis), donc le durcissement est gratuit pour les jeux.
   Deux de ces filets portaient d'ailleurs `#946E29`, une teinte rejetee le 2026-08-25
   pour cause de contraste insuffisant : un style en dur ne suit ni le theme sombre ni
   le contraste renforce, et survit aux corrections. */
.carte .trait[data-coll]{background:var(--coll)}
.carte .trait[data-coll="or"]{background:var(--or)}
.note-jeu{font-size:.92rem;color:var(--encre-2)}
.note-grille{text-align:center;font-size:.95rem;color:var(--encre-2)}

/* couleurs de collection — relevées dans moteurs/common.py PALETTES */
[data-coll="nonogramme"]{ --coll:#335473; --coll-d:#213B54; --coll-lt:#E8EDF2; --coll-soft:#D1DBE3; }
[data-coll="sudoku"]  { --coll:#9E3D2E; --coll-d:#73291F; --coll-lt:#F5E8D4; --coll-soft:#E6D1BD; }
[data-coll="motsmeles"]{ --coll:#576F4A; --coll-d:#3E5234; --coll-lt:#E9EEE3; --coll-soft:#D4DECA; }
[data-coll="crypto"]  { --coll:#296370; --coll-d:#1B4A55; --coll-lt:#E2EDEF; --coll-soft:#CBDFE3; }
/* #946E29 rendait 4,27:1 : le lien du pied de page et le bouton de grille actif
   passaient sous le seuil sur la seule page des labyrinthes. Releve : 5,21:1. */
[data-coll="dedale"]  { --coll:#7E5D23; --coll-d:#6E511C; --coll-lt:#F3EBDC; --coll-soft:#E4D6BB; }
/* 2026-08-25 : la sixieme collection n'existait que dans le style en dur d'une carte
   d'accueil. Sa page retombait sur le noir d'encre : six cartes annoncaient six
   couleurs, le site en tenait cinq. */
[data-coll="fleches"] { --coll:#6B3D5C; --coll-d:#4F2C44; --coll-lt:#F1E8EE; --coll-soft:#DFCFD9; }
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) [data-coll="nonogramme"]{ --coll:#8FB3D4; --coll-d:#B7D0E6; --coll-lt:#1B2530; --coll-soft:#26333F; }
  :root:not([data-theme="light"]) [data-coll="sudoku"]  { --coll:#E09383; --coll-d:#EFB4A6; --coll-lt:#2B1D18; --coll-soft:#3A2620; }
  :root:not([data-theme="light"]) [data-coll="motsmeles"]{ --coll:#A8C494; --coll-d:#C3D9B2; --coll-lt:#1C2318; --coll-soft:#27301F; }
  :root:not([data-theme="light"]) [data-coll="crypto"]  { --coll:#8AC0CC; --coll-d:#AFD6DE; --coll-lt:#16262A; --coll-soft:#1F3438; }
  :root:not([data-theme="light"]) [data-coll="dedale"]  { --coll:#D9B87A; --coll-d:#E8CE9C; --coll-lt:#231C11; --coll-soft:#332818; }
  :root:not([data-theme="light"]) [data-coll="fleches"] { --coll:#CFA3BE; --coll-d:#E3C2D6; --coll-lt:#241A21; --coll-soft:#33242E; }
}
:root[data-theme="dark"] [data-coll="nonogramme"]{ --coll:#8FB3D4; --coll-d:#B7D0E6; --coll-lt:#1B2530; --coll-soft:#26333F; }
:root[data-theme="dark"] [data-coll="sudoku"]  { --coll:#E09383; --coll-d:#EFB4A6; --coll-lt:#2B1D18; --coll-soft:#3A2620; }
:root[data-theme="dark"] [data-coll="motsmeles"]{ --coll:#A8C494; --coll-d:#C3D9B2; --coll-lt:#1C2318; --coll-soft:#27301F; }
:root[data-theme="dark"] [data-coll="crypto"]  { --coll:#8AC0CC; --coll-d:#AFD6DE; --coll-lt:#16262A; --coll-soft:#1F3438; }
:root[data-theme="dark"] [data-coll="dedale"]  { --coll:#D9B87A; --coll-d:#E8CE9C; --coll-lt:#231C11; --coll-soft:#332818; }
:root[data-theme="dark"] [data-coll="fleches"] { --coll:#CFA3BE; --coll-d:#E3C2D6; --coll-lt:#241A21; --coll-soft:#33242E; }

/* contraste renforcé, à la demande du visiteur */
:root[data-contraste="fort"]{ --filet-grille:#000000; --encre:#000000; --encre-2:#1A1A1A; --encre-3:#333333; --papier:#FFFFFF; --carte:#FFFFFF; --filet:#666666; --filet-fin:#999999; --coll:#000000; --coll-d:#000000; }
:root[data-contraste="fort"][data-theme="dark"]{ --filet-grille:#FFFFFF; --encre:#FFFFFF; --encre-2:#FFFFFF; --encre-3:#E8E8E8; --papier:#000000; --carte:#000000; --filet:#AAAAAA; --filet-fin:#777777; --coll:#FFFFFF; --coll-d:#FFFFFF; --focus:#FFFFFF; --faux-fond:#2A2A2A; }
/* Les variables de collection sont posees sur le BODY, donc plus pres de l'element
   que :root : elles gagnaient toujours, et « contraste renforce » ne changeait ni la
   barre de reglages, ni les cases indices, ni l'onglet actif. Mesure du 25/08 :
   1,2:1 entre case fixe et case vide EN MODE CONTRASTE RENFORCE. On les rattrape ici. */
:root[data-contraste="fort"] [data-coll]{ --coll:#000000; --coll-d:#000000; --coll-lt:#FFFFFF;
  --coll-soft:#D9D9D9; --case:#FFFFFF; --case-fixe:#E0E0E0; --trace:#767676; --faux-fond:#F0F0F0; --focus:#000000; --or-d:#6B4E12; }
:root[data-contraste="fort"]{ --case:#FFFFFF; --case-fixe:#E0E0E0; --trace:#767676; --faux-fond:#F0F0F0; --focus:#000000; --or-d:#6B4E12; }
:root[data-contraste="fort"][data-theme="dark"] [data-coll]{ --coll:#FFFFFF; --coll-d:#FFFFFF; --coll-lt:#000000;
  --coll-soft:#3A3A3A; --case:#000000; --case-fixe:#2A2A2A; --trace:#B0B0B0; --faux-fond:#2A2A2A; --focus:#FFFFFF; --or-d:#FFD98A;
  --encre-2:#FFFFFF; --encre-3:#E8E8E8; }
:root[data-contraste="fort"][data-theme="dark"]{ --case:#000000; --case-fixe:#2A2A2A; --trace:#B0B0B0; --faux-fond:#000000; --or-d:#FFD98A; }

*{box-sizing:border-box}
/* 17 px = 12,8 pt. Sur le site d'une maison de grands caracteres, l'audit du 25/08
   l'a note : la page parlait de 16 pt en composant plus petit que le web ordinaire.
   20 px = 15 pt au repos, et le reglage de confort monte de la. */
html{font-size:20px}
body{
  margin:0; padding:0;
  background:var(--papier); color:var(--encre);
  font-family:"Luciole", system-ui, sans-serif;
  font-size:1rem; line-height:1.65;
  -webkit-font-smoothing:antialiased;
}
/* LES MARGES NE DOIVENT PAS GRANDIR AVEC LE TEXTE.
   Mesure de la contre-lecture du 2026-08-26, sur un ecran de 320 px au confort
   maximal : 37,5 px de marge d'enveloppe et 42 px de marge de bloc de chaque cote, il
   ne restait que 159 px pour la grille. Le cryptogramme n'y montrait plus que deux
   lettres a la fois, et la premiere case libre etait litteralement inatteignable au
   doigt — le geste expirait. Le lecteur qui agrandit le texte est celui qui a le plus
   besoin de place ; les marges en `rem` la lui prenaient. `min()` les borne a une part
   de l'ecran. */
.enveloppe{max-width:60rem;margin:0 auto;padding:0 min(1.25rem,4vw) 6rem;overflow-wrap:break-word}
h1,h2,h3{font-family:"Luciole",Georgia,serif;font-weight:600;line-height:1.15;margin:0;text-wrap:balance}
/* titres et paragraphes sur UNE seule mesure : les filets de section couraient sur
   978 px quand le texte s'arretait a 646 — 332 px de vide a droite de chaque page. */
h1,h2,h3{max-width:38rem}
h1{font-size:clamp(2rem,5vw,2.9rem);letter-spacing:-.01em}
h2{font-size:clamp(1.35rem,3vw,1.75rem)}
h3{font-size:1.12rem;font-weight:500}
p{margin:0;max-width:38rem}
a{color:var(--coll);text-underline-offset:.18em}
/* --or-d est redefini sous [data-contraste="fort"] : sinon l'anneau restait a 3,65:1
   dans une page passee a 21:1, donc relativement invisible. */
:focus-visible{outline:3px solid var(--focus);outline-offset:3px;border-radius:6px}
.page:focus,.page:focus-visible{outline:none}
.etiquette{font-family:"Luciole",system-ui,sans-serif;font-size:.72rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:var(--encre-3)}

/* ---------- bandeau ---------- */
/* Le bandeau est collant : tout defilement programme doit lui laisser sa hauteur,
   sinon il masque le haut de la grille. Mesure du 2026-08-24 : un clic sur un bouton
   d'outil faisait defiler la page de 715 px et posait l'entree du labyrinthe SOUS le
   bandeau. */
html{scroll-padding-top:5rem}
.jeu .plateau{scroll-margin-top:5rem}
.bandeau{position:sticky;top:0;z-index:40;background:var(--papier);border-bottom:1px solid var(--filet-fin)}
/* A 320 px et au reglage maximal, le bandeau montait a 576 px sur une fenetre de 760 :
   76 % de l'ecran, en permanence, chez exactement le lecteur qu'on vise. Sous 700 px
   de hauteur utile, il cesse de coller — on defile, on ne se fait pas confisquer la page. */
/* Une requete sur la HAUTEUR seule ne suffisait pas : a 320x760 et au reglage
   maximal, le bandeau montait encore a 87 % de l'ecran. La largeur en REM, elle,
   suit la taille du texte : plus le lecteur agrandit, plus 30rem est large, et
   plus tot le bandeau cesse de coller. C'est exactement la regle qu'on veut. */
@media (max-height:820px), (max-width:30rem){ .bandeau{position:static} }
.bandeau-int{max-width:60rem;margin:0 auto;padding:.7rem 1.25rem;display:flex;flex-wrap:wrap;align-items:center;gap:.75rem 1.5rem}
.marque{display:flex;align-items:center;gap:.6rem;text-decoration:none;color:var(--encre);
  flex-wrap:wrap;min-width:0}
.marque .mot{overflow-wrap:anywhere}
.marque svg{width:4.2rem;height:auto;color:var(--or-d);flex:none}
.marque .mot{font-family:"Luciole",system-ui,sans-serif;font-weight:600;font-size:.95rem;letter-spacing:.28em;text-transform:uppercase}
nav.jeux{display:flex;gap:.2rem;flex-wrap:wrap;margin-inline-start:auto}
nav.jeux a{
  font-family:"Luciole",sans-serif;font-size:.87rem;font-weight:500;text-decoration:none;
  color:var(--encre-2);padding:.4rem .75rem;border-radius:999px;
  /* 44 px : la cible que demande une main qui tremble (WCAG 2.5.5). Les liens du
     bandeau faisaient 38 px de haut, les boutons de reglage 40,8. */
  display:inline-flex;align-items:center;min-height:44px;
}
nav.jeux a:hover{background:var(--filet-fin);color:var(--encre)}
nav.jeux a[aria-current="page"]{background:var(--coll-lt);color:var(--coll-d)}

/* ---------- réglages d'accessibilité ---------- */
.reglages{
  display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .9rem;
  background:var(--coll-lt);border:1px solid var(--filet-fin);border-radius:14px;
  padding:.7rem .9rem;margin:1.5rem 0 0;
}
.reglages .etiquette{color:var(--encre-2)}
/* sans flex-wrap, la paire « Contraste renforce / Fond sombre » ne pouvait pas se
   casser : a 320 px et au reglage maximal, elle poussait la page a 337 px de large. */
.reglages .groupe{display:flex;flex-wrap:wrap;gap:.3rem;min-width:0}
button.rg{
  font-family:"Luciole",sans-serif;font-size:.85rem;font-weight:500;
  background:var(--carte);color:var(--encre);border:1px solid var(--filet);
  border-radius:10px;padding:.4rem .8rem;cursor:pointer;min-height:44px;
  display:inline-flex;align-items:center;justify-content:center;
}
button.rg:hover{border-color:var(--coll)}
button.rg[aria-pressed="true"]{background:var(--coll);color:var(--papier);border-color:var(--coll)}

/* ---------- héros ---------- */
.heros{padding:3.5rem 0 0;display:flex;flex-direction:column;gap:1.1rem}
.mantra{font-family:"Luciole",Georgia,serif;font-style:italic;font-size:1.25rem;color:var(--encre-2);max-width:32rem}
.tagline{font-family:"Luciole",Georgia,serif;font-size:1.3rem;color:var(--coll-d);max-width:34rem}
.filet-or{height:2px;background:var(--or);opacity:.75;border-radius:2px;max-width:7rem}

section.bloc{display:flex;flex-direction:column;gap:1rem;padding-top:3rem}
.chapeau{border-bottom:1px solid var(--filet);padding-bottom:.6rem}

/* ---------- cartes de collection ---------- */
.grille-cartes{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(15rem,100%),1fr));gap:1rem}
.carte{
  background:var(--carte);border:1px solid var(--filet-fin);border-radius:16px;
  padding:1.1rem 1.2rem;display:flex;flex-direction:column;gap:.4rem;box-shadow:var(--ombre);
  text-decoration:none;color:inherit;
}
.carte .nom{font-family:"Luciole",serif;font-size:1.15rem;font-weight:600}
.carte .sous{font-family:"Luciole",serif;font-style:italic;color:var(--encre-2);font-size:.98rem}
.carte .trait{height:3px;width:2.6rem;border-radius:2px;margin-top:.35rem;margin-top:auto}
a.carte:hover{border-color:var(--coll)}
.carte.muette{opacity:.72}
.carte .bientot{font-family:"Luciole",sans-serif;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--encre-3)}

/* ---------- preuves ---------- */
/* `minmax(13rem, …)` : 13 rem valent 390 px des que le lecteur porte la racine a 30 px
   avec « A+ ». L'accueil debordait alors horizontalement — a 375 px comme a 320 px — et
   le bloc qui depassait etait precisement celui qui porte « Ce que nous mesurons ».
   `min()` borne la colonne a la largeur disponible : la grille retombe a une colonne au
   lieu de pousser la page. Contre-lecture du 2026-08-26. */
.preuves{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(13rem,100%),1fr));gap:1rem}
.preuve{background:var(--carte);border:1px solid var(--filet-fin);border-left:3px solid var(--or);border-radius:0 14px 14px 0;padding:.9rem 1.1rem;display:flex;flex-direction:column;gap:.3rem}
.preuve .chiffre{font-family:"Luciole",serif;font-size:1.5rem;font-weight:600;color:var(--coll-d)}
.preuve .quoi{font-size:.94rem;color:var(--encre-2)}

/* ---------- jeu ---------- */
.jeu{background:var(--carte);border:1px solid var(--filet);border-radius:20px;
     padding:1.4rem min(1.4rem,4.5vw);display:flex;flex-direction:column;gap:1.1rem}
.choix{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center}
.outils{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center}
.plateau{overflow-x:auto;padding-bottom:.4rem}
.message{font-size:.98rem;min-height:1.6rem;font-weight:700}
.message.ok{color:var(--juste)}
.message.non{color:var(--erreur)}

/* sudoku */
table.sud{border-collapse:collapse;margin:0 auto;font-variant-numeric:tabular-nums}
table.sud td{padding:0}
.sud button{
  width:2.9rem;height:2.9rem;font-size:1.35rem;
  font-family:"Luciole",sans-serif;font-weight:700;
  background:var(--case);color:var(--encre);border:1px solid var(--filet-grille);
  cursor:pointer;display:block;
}
/* L'INDICE DE DEPART ET LE CHIFFRE POSE. Ils ne differaient que par un fond mesure a
   1,21:1 — et a 1,32:1 en « contraste renforce », c'est-a-dire moins encore que ce que
   le nom du reglage promet. Le lecteur ne distinguait pas les chiffres du probleme des
   siens. On ajoute donc ce qui se voit sans couleur : l'indice de depart est en GRAS,
   le chiffre pose est en maigre — la convention meme des grilles imprimees. Releve par
   l'audit adverse du 2026-08-25. */
.sud button.fixe{background:var(--case-fixe);cursor:default;color:var(--encre);
  font-weight:700}
.sud button:not(.fixe){font-weight:400}
/* SELECTION ET FOCUS SONT DEUX CHOSES. Les quatre jeux dessinaient la case
   selectionnee avec l'anneau `--focus`, celui-la meme du focus clavier : apres un clic
   sur « Verifier », la case gardait son anneau alors que le focus etait sur le bouton,
   et le joueur qui tapait un chiffre ne voyait rien se passer — la machine mentait sur
   son etat. Les mots fleches faisaient deja la distinction ; on aligne les autres
   dessus. Releve par l'audit adverse du 2026-08-25. */
.sud button.sel{background:var(--coll-soft);box-shadow:inset 0 0 0 3px var(--coll-d);z-index:2;position:relative}
.sud button:focus-visible{outline:3px solid var(--focus);outline-offset:-3px;z-index:3;position:relative}
/* L'ERREUR NE SE DIT PAS PAR LA SEULE COULEUR (WCAG 1.4.1). Le sudoku et les
   cryptogrammes ne changeaient que l'encre : un lecteur daltonien — 8 % des hommes de
   plus de 65 ans — apprenait qu'une case etait fausse et ne pouvait pas la trouver.
   Les mots fleches posaient deja un fond ; on aligne, et on ajoute un souligne, qui
   se voit meme en niveaux de gris. Releve par l'audit adverse du 2026-08-25. */
.sud button.faux{color:var(--erreur);background:var(--faux-fond);
  text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:2px}
.sud td.br{border-right:2px solid var(--encre-2)}
.sud td.bb{border-bottom:2px solid var(--encre-2)}
.sud tr:first-child td{border-top:2px solid var(--encre-2)}
.sud tr:last-child td{border-bottom:2px solid var(--encre-2)}
.sud td:last-child{border-right:2px solid var(--encre-2)}
.sud td:first-child{border-left:2px solid var(--encre-2)}
.pave{display:flex;flex-wrap:wrap;gap:.35rem;justify-content:center}
.pave button{
  width:2.9rem;height:2.9rem;font-size:1.25rem;font-weight:700;
  font-family:"Luciole",sans-serif;
  background:var(--carte);border:1px solid var(--filet);border-radius:12px;
  color:var(--encre);cursor:pointer;
}
.pave button:hover{border-color:var(--coll)}

/* nonogramme */
.nono{display:inline-grid;gap:0;margin:0 auto}
.nono .coin{background:transparent}
/* display:contents : la rangee existe pour le lecteur d'ecran, et disparait
   pour la grille CSS — la mise en page ne bouge pas d'un pixel. */
.nono .rang{display:contents}
.nono .ind-c,.nono .ind-l{
  font-family:"Luciole",sans-serif;font-size:.92rem;font-weight:700;
  color:var(--encre);display:flex;gap:.1rem;line-height:1.15;
}
.nono .ind-c span,.nono .ind-l span{
  min-width:1.25em;min-height:1.25em;display:flex;align-items:center;justify-content:center;
  font-variant-numeric:tabular-nums;
}
.nono .ind-c{flex-direction:column;align-items:center;justify-content:flex-end;padding-bottom:.35rem}
.nono .ind-l{flex-direction:row;align-items:center;justify-content:flex-end;padding-right:.45rem}
/* Le conteneur `role="gridcell"` : une boite neutre, qui ne bouge rien a la grille.
   Elle existe pour que le BOUTON reste un bouton dans l'arbre d'accessibilite. */
/* SANS `avec-js` : pas de commandes mortes, et l'avis se lit. */
html:not(.avec-js) .outils,
html:not(.avec-js) .choix,
html:not(.avec-js) .plateau,
html:not(.avec-js) .reglages{display:none !important}
html.avec-js #avis-js{display:none}
.nono .case-nono{display:block;line-height:0}
.nono button.c{
  width:2.2rem;height:2.2rem;padding:0;border:1px solid var(--filet-grille);
  background:var(--case);cursor:pointer;position:relative;
}
/* LE COIN LEGEREMENT ARRONDI DE LA CASE ENCREE (demande de l'editeur, 2026-08-28).
   3 px sur une case de 35 px : l'encre garde son aire, mais l'angle cesse d'etre
   coupe au rasoir — c'est le geste du feutre, pas celui du massicot. La mesure qui
   compte est la SOUDURE : deux cases noires voisines laissent entre elles une
   lentille de papier de 2 x 3 px, soit 1,7 px au plus large. En dessous de ce
   rayon on ne voit plus rien ; au-dela de 5 px la masse noire se defait en
   pastilles, et un nonogramme se lit par masses.
   L'ombre portee de 1 px, de la couleur de l'encre, SOUDE les voisines : sans elle
   le rendu laissait un point blanc a chaque croisement de quatre cases noires —
   vu a l'ecran, pas devine. */
.nono button.c.plein{background:var(--case-pleine);border-color:var(--case-pleine);
  border-radius:3px;box-shadow:0 0 0 1px var(--case-pleine)}
.nono button.c.vide::after{content:"×";color:var(--encre-3);font-size:1rem;line-height:1;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}
.nono button.c.sel{box-shadow:inset 0 0 0 3px var(--coll-d);z-index:2}
.nono button.c:focus-visible{outline:3px solid var(--focus);outline-offset:-3px;z-index:3}
.nono button.c.b5r{border-right-width:2px;border-right-color:var(--encre-2)}
.nono button.c.b5b{border-bottom-width:2px;border-bottom-color:var(--encre-2)}


/* ---------- mots meles ---------- */
/* PAS DE QUADRILLAGE. Le livre n'en pose aucun : son heros ne trace que le cadre
   exterieur, arrondi au rayon canonique, et laisse les lettres respirer. Le site
   dessinait un filet autour de chaque case — ce n'etait pas la grille du livre. */
/* LE SURLIGNEUR — un trait, pas des carres.

   Chaque lettre trouvee portait son propre rectangle arrondi : la grille se lisait
   comme une mosaique de cases, et le mot n'apparaissait plus comme un mot.

   D'OU VIENT LA COTE, exactement. Le trait fait `case x 0,74`, bout rond : ce sont
   les nombres de `build_ws.overlay`, le surlignage des PAGES DE SOLUTIONS du
   volume. Ce n'est PAS celui de la couverture — verifie : la couverture raye les
   mots trouves d'un trait a la main de `case x 0,12`, en sepia
   (`build_cover_generic.hero_wordsearch`). On garde la largeur des solutions parce
   que c'est un SURLIGNEUR qui a ete demande, pas une rature ; on ne pretend pas
   qu'elle vienne de la couverture.

   LA COULEUR, elle, n'est pas celle des solutions, et c'est MESURE. Le trait a
   d'abord ete pose en `--coll` a 55 % : la lettre tombait a 3,71:1 dessus, et a
   2,35:1 la ou deux mots se croisent — dix cases sur soixante-huit dans « Bord de
   mer ». Sous le plancher de 4,5:1, dans une gamme vendue en gros caracteres, a un
   lectorat souvent au-dela de 65 ans. C'est la faute meme que la maison venait de
   corriger ailleurs, commise a l'endroit d'a cote.
   Le ton retenu est `--coll-soft`, celui que portaient les cases : lettre a
   6,46:1 sur un trait, 6,19:1 sur un croisement — au-dessus des 6,14:1 d'avant.
   On change la FORME, on ne perd pas la lisibilite. */
.wsboite{position:relative;display:inline-block;margin:0 auto;
  background:var(--case);border:2px solid var(--filet-grille);border-radius:1.05rem;
  padding:.35rem}
.wsboite .surligne{position:absolute;inset:.35rem;pointer-events:none;z-index:0;
  overflow:visible}
/* OPACITE 1 : sans quoi la couleur RENDUE n'est pas celle qu'on a mesuree — a
   0,85 le trait tombait a 2,08:1 quand le jeton en annonce 2,42. Un jeton mesure
   puis dilue est un chiffre faux. */
.wsboite .surligne line{stroke:var(--stabilo);stroke-linecap:round}
/* LE TRAIT EN COURS — celui qui suit le doigt pendant qu'on glisse le long d'un
   mot. Plus clair et cerne : il annonce, il n'affirme pas encore. */
/* L'APERCU pendant le glisse : le MEME feutre, pose plus leger — c'est ainsi
   qu'on distingue « je suis en train de tirer le trait » de « le mot est trouve ».
   Il etait peint en --coll a 28 %, un gris qui ne ressemblait a rien du trait
   final : deux couleurs pour un seul geste, et 1,46:1 sur le papier.
   Releve : apercu/papier 1,58:1, apercu/trait pose 1,53:1 — assez pour les
   distinguer l'un de l'autre, ce qui est tout ce qu'on lui demande. */
.wsboite .surligne line.encours{stroke:var(--stabilo);stroke-opacity:.55}
/* LE GLISSE N'EST OFFERT QU'AUX POINTEURS FINS. Sur un ecran tactile,
   `touch-action:none` est indispensable au glisse — et il interdit du meme coup
   de faire defiler la page en touchant la grille. Le lecteur qui vient jouer sur
   son telephone perdrait le defilement sur toute la largeur de l'ecran pour
   gagner un geste dont il dispose deja autrement : les deux clics marchent
   partout. On ne prend donc le doigt en otage nulle part. */
@media (pointer: fine){ table.ws{touch-action:none} }
table.ws{border-collapse:collapse;margin:0 auto;-webkit-user-select:none;user-select:none;
  background:transparent;border:0;border-radius:0;padding:0;position:relative;z-index:1}
.ws td{padding:0}
.ws button{
  width:2.35rem;height:2.35rem;padding:0;
  font-family:"Luciole",sans-serif;font-size:1.05rem;font-weight:700;
  background:transparent;color:var(--encre);border:0;border-radius:.45rem;
  cursor:pointer;display:block;
}
/* La lettre trouvee ne porte plus de fond : c'est le trait qui la designe. Elle
   s'assombrit legerement, ce qui la distingue au toucher du regard sans redecouper
   la grille en cases. */
.ws button.trouve{background:transparent;color:var(--coll-d)}
.ws button.encours{background:var(--coll);color:var(--papier);border-color:var(--coll)}
/* Le curseur clavier est un CADRE, plus un fond. Avec un fond, il ressemblait a
   une case trouvee — et depuis que les mots trouves n'ont plus de fond, il etait
   devenu le seul carre colore de la grille : l'oeil le prenait pour une reponse. */
.ws button.sel{background:transparent;box-shadow:inset 0 0 0 3px var(--coll-d);position:relative;z-index:2}
.ws button:focus-visible{outline:3px solid var(--focus);outline-offset:-3px;position:relative;z-index:3}
.motsliste{display:flex;flex-wrap:wrap;gap:.4rem .7rem;margin:0;padding:0;list-style:none}
.motsliste li{
  font-family:"Luciole",sans-serif;font-size:.95rem;font-weight:700;
  padding:.22rem .6rem;border:1px solid var(--filet);border-radius:999px;color:var(--encre-2);
}
.motsliste li.ok{background:var(--coll-soft);color:var(--coll-d);border-color:var(--coll-soft);text-decoration:line-through}

/* ---------- cryptogrammes ---------- */
.cry{display:flex;flex-wrap:wrap;gap:.55rem 1.1rem;justify-content:center}
.cry .mot{display:flex;gap:.2rem}
.cry .lettre{display:flex;flex-direction:column;align-items:center;gap:.12rem}
.cry .lettre button{
  width:2.1rem;height:2.5rem;padding:0;
  font-family:"Luciole",sans-serif;font-size:1.2rem;font-weight:700;
  background:var(--case);color:var(--encre);
  border:1px solid var(--filet-grille);border-bottom-width:3px;border-radius:4px 4px 0 0;cursor:pointer;
}
.cry .lettre button.offert{background:var(--coll-soft);color:var(--coll-d);cursor:default}
.cry .lettre button.faux{color:var(--erreur);background:var(--faux-fond);
  text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:2px}
.cry .lettre button.sel{background:var(--coll-soft);box-shadow:inset 0 0 0 3px var(--coll-d)}
.cry .lettre button:focus-visible{outline:3px solid var(--focus);outline-offset:-3px}
.cry .code{font-family:"Luciole",sans-serif;font-size:.72rem;font-weight:700;color:var(--encre-3);letter-spacing:.04em}
.cry .ponct{display:flex;align-items:flex-end;font-size:1.2rem;padding-bottom:.35rem;color:var(--encre-2)}
.alpha{display:flex;flex-wrap:wrap;gap:.22rem;justify-content:center}
.alpha span{
  font-family:"Luciole",sans-serif;font-size:.82rem;font-weight:700;
  width:1.5rem;height:1.5rem;display:flex;align-items:center;justify-content:center;
  border-radius:4px;color:var(--encre-3);border:1px solid var(--filet-fin);
}
.alpha span.pris{background:var(--coll-soft);color:var(--coll-d);border-color:var(--coll-soft)}


/* ---------- labyrinthes ---------- */
/* `touch-action:none` supprimait TOUS les gestes du navigateur sur la grille, le
   PINCER-ZOOMER compris : le lecteur malvoyant a qui l'on vend le confort visuel ne
   pouvait pas agrandir le seul objet du site trop petit pour lui. `pinch-zoom` garde
   ce qu'il faut — le glisse a un doigt ne fait plus defiler la page, donc le trace
   fonctionne — et rend le zoom a deux doigts. Releve par l'audit adverse du
   2026-08-25. */
table.lab{border-collapse:collapse;margin:0 auto;-webkit-user-select:none;user-select:none;touch-action:pinch-zoom}
.lab td{padding:0;border:2px solid transparent}
.lab td.mN{border-top-color:var(--encre)}
.lab td.mE{border-right-color:var(--encre)}
.lab td.mS{border-bottom-color:var(--encre)}
.lab td.mO{border-left-color:var(--encre)}
/* LA CASE S'ADAPTE A L'ECRAN.
   Depuis que les labyrinthes viennent du moteur du volume, ils font 19, 25 et 33
   colonnes — et non plus 11. A 1,8 rem la case, un 19 colonnes fait 547 px : il
   deborde d'un telephone de 375 px. Le conteneur defile, mais un GLISSE ne peut pas
   atteindre une case hors de l'ecran : `elementsFromPoint` ne rend rien hors du
   viewport. Mesure du 2026-08-25 : le glisse au doigt echouait des la deuxieme case.
   La case se calcule donc a la largeur disponible, avec un plancher de 14 px — en
   dessous, le doigt ne vise plus rien. Le 33 colonnes deborde encore et defile ; les
   deux autres tiennent en entier. */
.lab button.c{
  width:var(--lab-case,1.8rem);height:var(--lab-case,1.8rem);
  padding:0;margin:0;display:block;
  background:transparent;border:0;cursor:pointer;position:relative;
}
/* LE CHEMIN N'EST PLUS UN COLORIAGE DE CASES.
   « rendre le chemin comme un trace manuel plutot que comme des cases (voir hero du
   volume) ». Le heros du volume tire un TRAIT a main levee : chemin simplifie
   (Douglas-Peucker), coins coupes a grands rayons (Chaikin), derive de main levee —
   plus aucun virage a 90 degres. C'est ce trait-la, dessine par-dessus la grille.
   La case gardait une teinte tres legere : elle sert de repere tactile au doigt, que
   le trait seul ne donne pas sur un ecran de telephone. */
.lab button.c.suivi{background:color-mix(in srgb, var(--trace) 22%, transparent);border-radius:5px}
.lab-plateau{position:relative;display:inline-block}
.tracemain{position:absolute;left:0;top:0;pointer-events:none;overflow:visible}
/* L'OPACITE FAISAIT MENTIR LA MESURE. Le jeton `--trace` avait ete releve a 3,08:1
   — sur le JETON, pas sur le RENDU : `opacity:.92` ramenait le trait effectivement
   affiche a 2,83:1, sous le seuil de 3:1 de WCAG 1.4.11, au moment precis ou la mesure
   disait qu'il passait au-dessus. On mesure ce qui s'affiche : plus d'opacite, et une
   teinte reprise pour tenir le seuil. Releve par l'audit adverse du 2026-08-25. */
.tracemain path{fill:none;stroke:var(--trace);stroke-width:4.5;stroke-linecap:round;
  stroke-linejoin:round}
.lab button.c.tete::after{
  content:"";position:absolute;inset:22%;border-radius:50%;background:var(--coll-d);
}
/* Suivi verrouille : la grille le dit, sans clignoter ni crier. Un lecteur qui a
   verrouille sans le vouloir doit comprendre d'un coup d'oeil pourquoi le chemin
   le suit. */
table.lab.verrou{box-shadow:0 0 0 3px var(--or);border-radius:8px}
.lab.verrou button.c.tete::after{box-shadow:0 0 0 4px var(--or)}
/* UN HALO QUI RESPIRE, PAS UN POINT QUI SAUTE.
   L'ancien reglage faisait grossir le point de 28 % trois fois en 1,8 s — et il
   SAUTAIT : la keyframe appliquait `translate(-50%,-50%)` a un element pose en
   `inset:22%`, qui n'a pas ce decalage. A chaque battement le point quittait son
   centre d'un quart de case, puis y revenait. Ce n'etait pas une animation
   nerveuse, c'etait un defaut.
   Ici : aucune transformation, aucun changement de taille. Seule l'INTENSITE d'un
   halo varie, sur 4,2 s au lieu de 1,8 — un rythme de respiration, pas de sonnerie.
   WCAG 2.2.2 : le mouvement depasse cinq secondes, mais il est declenche par le
   lecteur (le verrouillage du suivi) et il s'arrete du meme geste — le mecanisme
   d'arret, c'est le verrou lui-meme. */
.lab button.c.tete::before{
  content:"";position:absolute;inset:-18%;border-radius:50%;pointer-events:none;
  background:radial-gradient(circle closest-side, var(--or) 0%, transparent 72%);
  opacity:0;
}
.lab.verrou button.c.tete::before{opacity:.30}
@media (prefers-reduced-motion: no-preference){
  .lab.verrou button.c.tete::before{animation:halo-lent 4.2s ease-in-out 3 forwards}
}
@keyframes halo-lent{0%,100%{opacity:.16}50%{opacity:.52}}
.lab button.c.indice{box-shadow:inset 0 0 0 3px var(--or)}
.lab button.c.borne{box-shadow:inset 0 0 0 3px var(--or-d)}
.lab button.c:focus-visible{outline:3px solid var(--focus);outline-offset:-3px}
.bornes{display:flex;justify-content:space-between;max-width:32rem;margin:0 auto;
  font-family:"Luciole",sans-serif;font-size:.78rem;letter-spacing:.1em;text-transform:uppercase;color:var(--encre-2)}

/* ---------- encadré provisoire ---------- */
.provisoire{
  border:1px dashed var(--erreur);border-radius:14px;padding:.9rem 1.1rem;
  display:flex;flex-direction:column;gap:.35rem;background:transparent;
}
.provisoire .etiquette{color:var(--erreur)}
.provisoire p{font-size:.94rem;color:var(--encre-2)}

ul.liste{margin:0;padding-left:1.15rem;display:flex;flex-direction:column;gap:.45rem;max-width:38rem}
/* OÙ TROUVER LE LIVRE. Le lien n'existe que si l'éditeur a collé une adresse dans
   `sources/donnees_ouvrages.json` ; sinon la page dit que le volume n'est pas
   encore en vente, et ne fabrique aucun lien. Un bouton qui mène à une recherche
   déguisée en fiche produit serait une indication fallacieuse. */
.ou-trouver{margin-top:1.4rem;padding-top:1.1rem;border-top:1px solid var(--filet);max-width:38rem}
.ou-trouver p{margin:0 0 .7rem}
.ou-trouver .liens{display:flex;flex-wrap:wrap;gap:.6rem}
.ou-trouver a.cmd{display:inline-block;padding:.7rem 1.15rem;border-radius:6px;
  background:var(--coll);color:var(--papier);text-decoration:none;font-weight:700;
  border:2px solid var(--coll)}
.ou-trouver a.cmd:hover{background:var(--papier);color:var(--coll)}
.ou-trouver a.cmd:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.ou-trouver .attente{color:var(--encre-2);font-style:normal}
ul.liste li::marker{color:var(--or-d)}

footer{margin-top:4rem;border-top:1px solid var(--filet);padding-top:1.2rem;display:flex;flex-direction:column;gap:.5rem}
footer .etiquette{color:var(--encre-3)}
footer p{font-size:.9rem;color:var(--encre-2)}


@media (prefers-reduced-motion: no-preference){
  .carte,button.rg,.pave button{transition:border-color .15s ease, background .15s ease}
}
@media (max-width:34rem){
  .sud button{width:2.4rem;height:2.4rem;font-size:1.15rem}
  .nono button.c{width:1.75rem;height:1.75rem}
  nav.jeux{margin-inline-start:0;width:100%}
}

/* ================= LA CÉLÉBRATION DE FIN DE GRILLE =================
   Arbitrages de l'editeur, 2026-08-24 :
     - la SIGNATURE de maison apparait a CHAQUE resolution, sur les six jeux ;
     - l'etoile TRACE la ligne, et le trait la SUIT ;
     - le nonogramme garde la vague qui monte du bas, les cases qui sautent ;
     - AUCUNE animation quand on demande « montrer la solution ». Une recompense
       qu'on obtient en abandonnant n'en est pas une — d'ou le drapeau `aTriche`
       cote script, qui survit au fait de cliquer « verifier » apres avoir vu la
       solution : la grille est alors juste, et il ne se passe rien.
   Tout MONTE. Aucun geste ne retombe.
   ================================================================== */
/* ---------- lien d'evitement ----------
   Au clavier, atteindre le jeu demandait de retraverser les six liens du bandeau et les
   trois reglages a chaque page. Le lien est le PREMIER element focalisable ; il ne se voit
   qu'au clavier, et il se voit alors franchement — le public de ce site lit en gros. */
/* Sans JavaScript, les six pages de jeu annoncaient des grilles et n'affichaient que
   des boutons morts : le visiteur croyait a une panne. On le lui dit. */
/* la date de mise a jour portait la classe des sur-titres : elle se lisait comme un
   titre de section sans contenu, et collait au paragraphe precedent. */
.datee{margin-top:2.5rem;padding-top:1rem;border-top:1px solid var(--filet);
  font-size:.9rem;color:var(--encre-3);font-style:italic}
/* le bouton des pages bonus : une cible franche, 44 px au moins */
.bouton{display:inline-flex;align-items:center;min-height:48px;padding:.6rem 1.4rem;
  background:var(--coll);color:var(--papier);text-decoration:none;border-radius:10px;
  font-weight:600;font-size:1.05rem}
.bouton:hover{background:var(--coll-d)}
.avis-noscript{margin:1.5rem 0 0;padding:.9rem 1.1rem;border-left:4px solid var(--or);
  background:var(--carte);border-radius:0 10px 10px 0;max-width:38rem}
/* `max-width` : au confort maximal, le lien d'evitement mesurait 324 px dans une
   fenetre de 320 et faisait deborder la page a lui seul. Contre-lecture du 2026-08-26. */
.evitement{position:fixed;left:.6rem;top:-5rem;z-index:60;padding:.7rem 1.1rem;
  max-width:calc(100vw - 1.2rem);
  background:var(--encre);color:var(--papier);border-radius:.4rem;font-size:1.05rem;
  text-decoration:none}
.evitement:focus{top:.6rem;outline:3px solid var(--or);outline-offset:2px}
/* position:fixed et NON absolute : un lien absolu se calerait sur le haut du document,
   donc hors de l'ecran des qu'on a defile. Et pas de transition : le controle mesurait
   la position pendant le fondu et la trouvait encore hors champ — un lien d'evitement
   doit etre la, pas en train d'arriver. */

.sacre{margin:1.1rem auto 0;display:flex;flex-direction:column;align-items:center}
.sacre svg{width:14rem;height:auto;color:var(--encre);overflow:visible;display:block}
.sacre .trait{stroke-dasharray:290;stroke-dashoffset:290}
/* Le chemin de l'etoile prolonge le trait JUSQU'A SA PLACE (290,30), alors que le
   trait s'arrete a 264 — c'est le blanc voulu du logo. Sans ce prolongement, l'etoile
   arrivait au bout du trait et une SECONDE etoile apparaissait 26 px plus loin : on
   voyait deux etoiles, puis un saut. Mesure faite sur capture a 2,6 s.
   MESURE : chemin de l'etoile 315,85 · trait 289,85 · ecart 26,00 (releve au
   getTotalLength du navigateur). Le stroke-dasharray valait 340 : le trait etait
   donc entierement tire des 85 % de sa course, et l'etoile tirait 0,3 s dans le vide. */
.sacre .filante{offset-path:path("M12,30 L108,30 C124,29 140,14 132,10 C125,7 120,21 134,28 C144,31 162,30 182,30 L264,30 L290,30");
                offset-distance:0%;offset-rotate:0deg}
.sacre .filante .etoile{transform-box:fill-box;transform-origin:center}
.sacre .halo{opacity:0}
/* l'etoile « de fin » ne sert plus qu'a un cas : celui du lecteur qui a demande des
   animations reduites, et a qui l'on doit l'etat final tout de suite. */
.sacre .etoile-fin{opacity:0}
.sacre .etincelles path{opacity:0;transform-box:fill-box;transform-origin:center}

/* ------------------------------------------------------------------
   LA VITESSE N'EST PAS LINEAIRE, ET CE N'EST PAS UN CAPRICE DE COURBE.
   Deux lois mesurees du geste humain, l'une dans l'espace, l'autre dans le temps :
   · loi de puissance deux tiers (Lacquaniti, Terzuolo & Viviani, Acta Psychologica
     54, 1983) : la vitesse du trace varie comme la racine cubique du rayon de
     courbure. La main RALENTIT dans la boucle et REPART sur les droites.
   · profil a secousse minimale (Flash & Hogan, Journal of Neuroscience 5, 1985),
     releve d'un elan d'entree et d'une pose finale non nuls : l'etoile ARRIVE
     lancee et se POSE — elle ne part pas de l'arret, elle ne s'arrete pas net.
   Les deux listes ci-dessous sont le resultat calcule de ces lois sur CE trace-la
   (sources/easing_signature.py). Releve : 46 a 196 px/s, rapport 4,3x, et jamais
   plus de 3,2 % d'ecart de vitesse d'une image a la suivante. L'ancienne courbe
   allait de 1 a 274 px/s — un rapport de 487x : elle partait comme une fleche et
   finissait en rampant.
   Le trait ne suit plus par un retard de temps mais par un ECART DE 5 px tenu tout
   du long : sa liste est celle de l'etoile, convertie en longueur dessinee. Il
   s'acheve donc a 264,30 quand l'etoile y passe, et l'etoile fait seule les 26 px
   qui la menent a sa place.
   cubic-bezier d'abord, linear() ensuite : un navigateur qui ignore linear() garde
   la bezier, ajustee a 2 % pres de la meme courbe. Rien ne casse.
   ------------------------------------------------------------------ */
.sacre .filante{animation:sc-court 2.5s cubic-bezier(0.525,0.445,0.775,1) .15s forwards}
.sacre .filante{animation-timing-function:linear(0,0.0061,0.0121,0.018,0.0239,0.0298,0.0357,0.0415,0.0474,0.0532,0.0591,0.0651,0.071,0.077,0.0831,0.0892,0.0954,0.1017,0.1081,0.1145,0.1211,0.1277,0.1344,0.1413,0.1483,0.1553,0.1626,0.1699,0.1773,0.1849,0.1925,0.2002,0.2079,0.2157,0.2234,0.2313,0.2391,0.247,0.2549,0.2628,0.2706,0.2785,0.2863,0.294,0.3017,0.3092,0.3166,0.324,0.3312,0.3384,0.3454,0.3523,0.3591,0.3658,0.3724,0.3789,0.3853,0.3916,0.3978,0.4039,0.4099,0.4159,0.422,0.4282,0.4344,0.4409,0.4474,0.4541,0.4609,0.4678,0.4748,0.4819,0.4892,0.4966,0.5041,0.5119,0.5198,0.528,0.5364,0.545,0.5538,0.5628,0.572,0.5814,0.5911,0.6009,0.6108,0.6209,0.6311,0.6415,0.6518,0.662,0.6722,0.6822,0.6921,0.7019,0.7115,0.721,0.7304,0.7396,0.7487,0.7577,0.7664,0.7751,0.7835,0.7918,0.8,0.8079,0.8157,0.8233,0.8308,0.8381,0.8452,0.8521,0.8588,0.8654,0.8717,0.8779,0.8839,0.8898,0.8954,0.9009,0.9062,0.9113,0.9163,0.9211,0.9257,0.9301,0.9344,0.9385,0.9425,0.9463,0.95,0.9536,0.957,0.9603,0.9635,0.9665,0.9695,0.9723,0.9751,0.9778,0.9804,0.9829,0.9854,0.9879,0.9903,0.9928,0.9952,0.9976,1)}
@keyframes sc-court{to{offset-distance:100%}}
.sacre .filante .etoile{animation:sc-taille 1.1s cubic-bezier(.2,.75,.3,1) .15s forwards}
@keyframes sc-taille{0%{transform:scale(.45) rotate(-18deg)}
                     60%{transform:scale(1.06) rotate(2deg)}
                     100%{transform:scale(1) rotate(0deg)}}
.sacre .trait{animation:sc-trace 2.5s cubic-bezier(0.59,0.49,0.67,1.04) .15s forwards}
.sacre .trait{animation-timing-function:linear(0,0,0,0.0024,0.0088,0.0152,0.0216,0.028,0.0344,0.0408,0.0472,0.0536,0.0601,0.0666,0.0733,0.0799,0.0867,0.0935,0.1004,0.1075,0.1146,0.1218,0.1292,0.1367,0.1442,0.152,0.1598,0.1678,0.1759,0.1841,0.1924,0.2008,0.2092,0.2176,0.2261,0.2346,0.2432,0.2517,0.2603,0.2689,0.2775,0.2861,0.2946,0.303,0.3113,0.3195,0.3276,0.3356,0.3435,0.3513,0.3589,0.3664,0.3739,0.3812,0.3883,0.3954,0.4024,0.4092,0.416,0.4226,0.4292,0.4357,0.4424,0.4491,0.4559,0.4629,0.47,0.4773,0.4847,0.4922,0.4999,0.5076,0.5155,0.5236,0.5318,0.5403,0.5489,0.5578,0.5669,0.5763,0.5859,0.5957,0.6058,0.616,0.6265,0.6372,0.648,0.659,0.6702,0.6814,0.6926,0.7038,0.7148,0.7258,0.7365,0.7472,0.7577,0.7681,0.7783,0.7883,0.7982,0.8079,0.8175,0.8269,0.8361,0.8452,0.854,0.8627,0.8712,0.8795,0.8876,0.8955,0.9032,0.9108,0.9181,0.9252,0.9322,0.9389,0.9455,0.9518,0.958,0.964,0.9697,0.9753,0.9807,0.9859,0.9909,0.9958,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)}
@keyframes sc-trace{to{stroke-dashoffset:0}}
/* elle se pose a sa place : la marque est entiere */
.sacre .halo{animation:sc-halo 1s ease-out 2.60s forwards}
@keyframes sc-halo{0%{opacity:0;transform:scale(.4)}30%{opacity:1;transform:scale(1)}
                   100%{opacity:0;transform:scale(1.6)}}
.sacre .etincelles .e1{animation:sc-etincelle 1.2s ease-out 2.74s forwards}
.sacre .etincelles .e2{animation:sc-etincelle 1.2s ease-out 2.90s forwards}
.sacre .etincelles .e3{animation:sc-etincelle 1.2s ease-out 3.06s forwards}
@keyframes sc-etincelle{0%{opacity:0;transform:translateY(2px) scale(.5)}
                        30%{opacity:.95;transform:translateY(-9px) scale(1)}
                        100%{opacity:0;transform:translateY(-28px) scale(.45)}}
/* et la marque entiere s'eleve, pour finir plus haut qu'elle n'a commence */
.sacre svg{animation:sc-monte .9s cubic-bezier(.2,.7,.3,1) 3.10s forwards}
@keyframes sc-monte{to{transform:translateY(-8px)}}

/* ---------- NONOGRAMME : la vague monte du bas, les cases sautent ---------- */
.sacre-on .nono button.c.plein{animation:sc-saute .75s cubic-bezier(.2,.75,.3,1) forwards;
                               animation-delay:calc(var(--r,0) * 90ms)}
@keyframes sc-saute{0%{transform:translateY(0)}45%{transform:translateY(-9px)}100%{transform:translateY(0)}}

/* ---------- SUDOKU : l'onde en diagonale ---------- */
.sacre-on table.sud button{animation:sc-souleve .5s ease-out forwards;
                           animation-delay:calc(var(--d,0) * var(--pas, 55ms))}
@keyframes sc-souleve{40%{transform:translateY(-3px)}100%{transform:translateY(0)}}
.sacre-on table.sud td{position:relative}
.sacre-on table.sud td::after{content:"";position:absolute;inset:0;background:var(--or);opacity:0;
  pointer-events:none;animation:sc-onde .55s ease-out forwards;animation-delay:calc(var(--d,0) * var(--pas, 55ms))}
@keyframes sc-onde{35%{opacity:.4}100%{opacity:0}}

/* ---------- MOTS MELES : chaque mot se decolle d'un seul tenant ---------- */
.sacre-on table.ws button:not(.trouve){color:var(--encre-3);transition:color .9s ease .5s}
.sacre-on table.ws button.trouve{animation:sc-ruban .8s cubic-bezier(.2,.75,.3,1) forwards;
  animation-delay:calc(var(--w,0) * 240ms + var(--l,0) * 45ms)}
@keyframes sc-ruban{0%{transform:translateY(0)}45%{transform:translateY(-9px)}100%{transform:translateY(0)}}
/* LE TRAIT SE SOULEVE AVEC SON MOT. Depuis que le surlignage a quitte le bouton
   pour un trait de SVG, la fete decollait les lettres de neuf pixels et laissait
   leur stabilo au sol : le mot se detachait de ce qui le designe, exactement au
   moment ou l'on veut montrer les deux ensemble. Meme animation, meme retard —
   celui du MOT, puisqu'un trait n'a pas de lettres. */
.sacre-on .wsboite .surligne line{animation:sc-ruban .8s cubic-bezier(.2,.75,.3,1) forwards;
  animation-delay:calc(var(--w,0) * 240ms)}

/* ---------- CRYPTOGRAMMES : le code s'evapore, la lettre monte ---------- */
.sacre-on .cry .code{animation:sc-evapore .7s ease-out forwards;animation-delay:calc(var(--d,0) * var(--pas, 45ms))}
@keyframes sc-evapore{to{opacity:0;transform:translateY(-20px) scale(.75)}}
.sacre-on .cry .lettre button{animation:sc-monte-clair .7s cubic-bezier(.2,.75,.3,1) forwards;
  animation-delay:calc(var(--d,0) * var(--pas, 45ms))}
@keyframes sc-monte-clair{45%{transform:translateY(-7px)}100%{transform:translateY(-4px)}}

/* ---------- LABYRINTHES : le chemin se relit ---------- */
.sacre-on .lab button.c.suivi{animation:sc-court-chemin .42s ease-out forwards;
  animation-delay:calc(var(--d,0) * var(--pas, 60ms))}
@keyframes sc-court-chemin{45%{background:var(--or);transform:scale(1.12) translateY(-3px)}
                           100%{background:var(--coll-soft);transform:scale(1) translateY(0)}}

/* ==================================================================
   IMPRESSION — le pont ecran vers papier.
   Un lecteur de 78 ans qui trouve une grille a l'ecran veut la faire au fauteuil.
   Sans cette feuille il obtenait le bandeau, les reglages, les boutons, et une
   grille coupee. On imprime la grille et ses consignes, rien d'autre.
   ================================================================== */
@media print{
  :root{ --papier:#FFFFFF; --carte:#FFFFFF; --encre:#000000; --encre-2:#000000;
         --encre-3:#333333; --filet:#999999; --filet-fin:#CCCCCC; --filet-grille:#000000;
         --coll:#000000; --coll-d:#000000; --coll-lt:#FFFFFF; --coll-soft:#EEEEEE;
         --case:#FFFFFF; --case-fixe:#EDEDED; --case-pleine:#000000; --trace:#DDDDDD; }
  @page{ margin:14mm }
  html{font-size:12pt}
  body{background:#FFF;color:#000}
  .bandeau, .reglages, .evitement, .actions, .choix, .sacre,
  nav.jeux, footer, .provisoire{ display:none !important }
  .enveloppe{max-width:none;padding:0}
  .plateau{overflow:visible !important}
  table{page-break-inside:avoid}
  .jeu{border:none;padding:0}
  a[href^="/"]::after{content:""}   /* pas d'URL entre parentheses : elles sont internes */
  h1{font-size:20pt;margin-bottom:.4em}
  h2{font-size:14pt}
  .aide, .motsliste{page-break-inside:avoid}
}

@media (prefers-reduced-motion: reduce){
  .sacre *{animation:none !important}
  .sacre .trait{stroke-dashoffset:0}
  .sacre .filante{opacity:0}
  .sacre .etoile-fin{opacity:1}
  .sacre-on *{animation:none !important;transition:none !important}
  /* Le selecteur * ne touche PAS les pseudo-elements : 81 animations sc-onde
     survivaient sur td::after apres un sudoku, 1,43 s d'onde doree chez quelqu'un
     qui avait demande moins de mouvement. Mesure du 2026-08-25. */
  .sacre *::before, .sacre *::after,
  .sacre-on *::before, .sacre-on *::after{animation:none !important;transition:none !important}
}

/* ---------------- MOTS FLECHES ----------------
   La grille porte deux textes de tailles tres differentes : la LETTRE, qui doit etre
   grosse, et la DEFINITION, qui est petite par nature. On ne peut pas grossir la
   seconde sans crever la case. La reponse de la maison n'est donc pas typographique
   mais de mise en page : la definition du mot en cours est RAPPELEE EN GRAND sous la
   grille. Le joueur ne plisse jamais les yeux sur la petite case — il y jette un oeil
   pour se reperer, et lit en dessous.
   ---------------------------------------------- */
.flc{border-collapse:collapse;table-layout:fixed;margin:0 auto;width:100%;
     /* 3rem = 51 px : la definition tombait a 8,4 pt et se coupait en plein mot.
        4.4rem laisse la place au texte ET porte la case a 88 px, bien au-dela des
        44 px que demande une main qui tremble (WCAG 2.5.5). */
     /* min-width ET NON width:100% : la table retrecissait dans son conteneur au
        lieu de le faire defiler comme les cinq autres jeux, et a 400 px les 33
        definitions etaient rognees d'un coup. Contre-lecture du 25/08. */
     /* EN MODE NUMEROTE, LA CASE N'A PLUS DE TEXTE A LOGER : elle tient a la largeur
        de l'ecran, et la grille entiere se voit d'un coup au lieu de defiler
        lateralement. Le plancher reste largement au-dessus des 44 px de WCAG 2.5.5.
        Contre-lecture du 2026-08-26 : sur un iPhone, la grille numerotee montrait
        quatre colonnes sur sept — un jeu qu'il fallait faire glisser pour voir. */
     min-width:calc(var(--flc-w,7) * 3.4rem);
     max-width:calc(var(--flc-w,7) * 4.4rem);
     border:2px solid var(--encre);-webkit-user-select:none;user-select:none}
table.flc.numerote{min-width:0;
     width:min(100%, calc(var(--flc-w,7) * 4.4rem));
     max-width:calc(var(--flc-w,7) * 4.4rem)}
.flc.numerote td{min-width:2.6rem}
.flc td{padding:0;border:1px solid var(--filet-grille);vertical-align:top}
/* Case carree par padding en pourcentage : il se calcule sur la LARGEUR, donc le carre
   reste exact dans une cellule de tableau, la ou aspect-ratio reste inegal d'un
   navigateur a l'autre. */
.flc .boite{position:relative;width:100%;padding-bottom:100%}
.flc .dedans{position:absolute;inset:0;overflow:hidden}
.flc td.def{background:var(--filet-fin)}
.flc .txtdef{display:flex;flex-direction:column;justify-content:center;gap:1px;
             padding:3px 4px;text-align:left}
.flc .txtdef.pd{padding-right:.7em}
.flc .txtdef.pb{padding-bottom:.7em}
/* Bornes en REM et non en vw : avec 2.1vw, six appuis sur A+ menaient 11,22 px a
   11,44 px sur telephone — le reglage de confort ne servait a rien la ou il fallait.
   Interligne 1.08 -> 1.3 : le canon maison demande 140 % au texte lu. */
.flc .d{font-size:.72rem;line-height:1.3;color:var(--encre-2);
        font-weight:700;overflow-wrap:break-word;hyphens:auto}
/* LA FLECHE DU VOLUME, PAS LE GLYPHE DE L'ANCIEN MOTEUR.
   `build_arrow_v4.py` posait le caractere U+2192 de Luciole dans la case. Ce moteur
   est mort le 2026-08-13 : « la fleche est dehors ». Le volume gros caracteres pose
   desormais un TRIANGLE PLEIN, base sur le bord de la case definition, pointe dans la
   premiere lettre — `fleche()` de BUILD_interieur_vol1_2026-08-13.py, BASE_FL 16,5 pt
   pour HAUT_FL 9,5 pt, soit un rapport base/longueur de 1,74. C'est ce rapport qui
   donne au triangle sa silhouette trapue ; on le respecte ici au pixel pres. */
/* LE MODE NUMEROTE. Le numero doit se lire d'un coup d'oeil : il est gros, il est
   centre, il est en encre pleine — c'est lui qui remplace la definition dans la case,
   et la definition, elle, est en toutes lettres sous la grille. */
.flc td.def .dnum{font-family:"Luciole",sans-serif;font-weight:700;font-size:1rem;
  line-height:1;color:var(--encre);text-align:center;align-self:center;width:100%;
  /* SANS RETOUR A LA LIGNE : dans une case de 44 px, « 16 » se cassait en « 1 » puis
     « 6 » l'un sous l'autre, et venait buter contre la fleche. */
  white-space:nowrap}
.flc.numerote .txtdef{justify-content:center;align-items:center;padding:2px}
/* le numero ne doit pas toucher la fleche : on lui laisse le bord */
.flc.numerote .txtdef.pd{padding-right:.72em;padding-left:0}
.flc.numerote .txtdef.pb{padding-bottom:.72em;padding-top:0}
.defs-liste{margin:1rem 0 0}
.defs-titre{font-weight:700;margin:0 0 .35rem}
.defs-liste ol{margin:0;padding:0;list-style:none}
.defs-liste li{margin:0 0 .2rem}
.defs-liste .defl{font:inherit;font-size:1rem;text-align:left;background:none;border:0;
  max-width:100%;
  padding:.45rem .35rem;color:var(--encre);cursor:pointer;min-height:44px;width:100%;
  border-radius:6px;display:flex;gap:.55rem;align-items:flex-start}
.defs-liste .defl-n{font-weight:700;min-width:2.1em;text-align:right;flex:0 0 auto}
.defs-liste .defl-t{flex:1 1 auto; min-width:0; overflow-wrap:anywhere}
.defs-liste .defl:hover{background:var(--coll-soft)}
.defs-liste .defl.encours{background:var(--coll-soft);box-shadow:inset 0 0 0 2px var(--coll-d)}
.defs-liste .defl-q{color:var(--encre-2);font-size:.92rem;font-weight:400}
.flc .fl{position:absolute;width:0;height:0;border-style:solid;border-color:transparent}
.flc .fl-droite{right:0;top:50%;transform:translateY(-50%);
         border-width:.44rem 0 .44rem .50rem;border-left-color:var(--coll-d)}
.flc .fl-bas{bottom:0;left:50%;transform:translateX(-50%);
         border-width:.50rem .44rem 0 .44rem;border-top-color:var(--coll-d)}
.flc button.c{
  display:flex;align-items:center;justify-content:center;width:100%;height:100%;
  margin:0;padding:0;border:0;background:var(--carte);color:var(--encre);
  font-family:inherit;font-weight:700;line-height:1;
  font-size:clamp(1rem,5vw,1.65rem);cursor:pointer;-webkit-appearance:none;appearance:none}
.flc button.c.motcourant{background:var(--coll-lt)}
.flc button.c.sel{background:var(--coll-soft);box-shadow:inset 0 0 0 3px var(--coll-d)}
/* Ces deux couleurs etaient ecrites en dur : en theme sombre la case fausse devenait
   un carre rose vif dans une grille d'encre — 14:1 d'ecart avec ses voisines. */
.flc button.c.faux{color:var(--erreur);background:var(--faux-fond)}
.flc button.c:focus-visible{outline:3px solid var(--focus);outline-offset:-4px}

/* Le rappel : hauteur RESERVEE, sinon la page monte et descend d'une ligne a chaque
   changement de mot et la grille saute sous le doigt. */
/* `max-width:34rem` vaut 1020 px des que la racine passe a 30 px avec « A+ », et le
   rappel, en element de boite flexible, ne se laissait pas retrecir : la page des mots
   fleches debordait a 320 px au confort maximal — c'est-a-dire pour le lecteur qui a
   le plus besoin du rappel. `min()` et `min-width:0` le bornent a la place reelle.
   Contre-lecture independante du 2026-08-26. */
.flc-rappel{max-width:min(34rem,100%);min-width:0;overflow-wrap:anywhere;
  margin:1rem auto 0;padding:.8rem 1rem;min-height:5.2rem;
  border-left:4px solid var(--or);background:var(--carte);border-radius:0 10px 10px 0}
.flc-rappel .sens{display:block;font-family:inherit;font-size:.74rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--encre-3);font-weight:700;margin-bottom:.15rem}
.flc-rappel .quoi{font-size:1.3rem;font-weight:700;line-height:1.3}
.flc-rappel .croix{display:block;margin-top:.35rem;font-size:.96rem;color:var(--encre-2)}

/* la fete : la lumiere remonte les mots, et s'attarde aux croisements */
.sacre-on .flc button.c{animation:sc-flc .55s ease-out forwards;
                        animation-delay:calc(var(--o,0) * 45ms)}
@keyframes sc-flc{0%{transform:translateY(0)}
                  40%{background:var(--or);transform:translateY(-5px)}
                  100%{transform:translateY(0)}}
.sacre-on .flc button.c.croise{animation-duration:.95s}
