/* Thème « base » — la disposition.
 *
 * Chargée entre `tokens.css` et `jeu.css` : elle consomme les jetons, et
 * elle ne peut rien dire de la surface de jeu, qui vient après et que rien
 * ne surcharge. Règle 22.
 *
 * AUCUNE VALEUR HEXADÉCIMALE ICI. Toute couleur vient d'un jeton, sans
 * exception : c'est ce qui permet à un thème saisonnier de tout reteinter en
 * redéfinissant une poignée de variables, et c'est ce qui rend le contrôle
 * de contraste possible — `bin/verifier-contraste.php` valide des paires de
 * jetons, pas des couleurs éparpillées dans des règles.
 *
 * La direction est celle de la maquette B, « la table de jeu » : le feutre
 * encadre, le carton porte. Ce n'est pas une image, c'est la règle 19 — les
 * annonces AdSense sont dessinées pour du fond clair et jurent sur du foncé,
 * donc elles ne peuvent vivre que sur les surfaces de carton.
 */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* ---------------------------------------------------------------------------
   Le feutre : le fond de la table.
   Le grain croisé remplace une texture en image — deux dégradés répétés
   coûtent zéro requête et ne pixellisent jamais. Ses deux valeurs sont des
   jetons : un thème peut vouloir un feutre plus ou moins marqué sans
   recopier cette feuille.
   --------------------------------------------------------------------------- */
body {
  background-color: var(--feutre);
  background-image:
    repeating-linear-gradient(45deg, var(--grain-clair) 0 2px, transparent 2px 4px),
    repeating-linear-gradient(-45deg, var(--grain-fonce) 0 2px, transparent 2px 4px);
  color: var(--creme);
  font: 400 var(--taille-m) / var(--interligne) var(--police-texte);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

main {
  flex: 1;
}

h1,
h2,
h3 {
  font-family: var(--police-titre);
  line-height: 1.1;
  letter-spacing: var(--suivi-titre);
  text-transform: uppercase;
}

a {
  color: var(--kraft);
}

img {
  max-width: 100%;
  display: block;
}

/* Le passage au contenu, pour qui navigue au clavier. */
.saut {
  position: absolute;
  left: -9999px;
  background: var(--carton);
  color: var(--encre);
  padding: var(--e-2) var(--e-3);
  border-radius: var(--rayon);
}

.saut:focus {
  left: var(--e-3);
  top: var(--e-3);
  z-index: 10;
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* Sur le carton, l'anneau change de couleur parce que le fond a changé. Une
   redéclaration du jeton, pas une seconde règle de focus : tout ce qui est
   posé sur du carton en hérite, y compris ce qui sera écrit demain. */
.boite,
.mini,
.fin,
.page-legale,
.consentement,
.saut {
  --focus: var(--focus-sur-carton);
}

.enveloppe {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 var(--e-4);
  width: 100%;
}

/* ---------------------------------------------------------------------------
   En-tête et pied : du feutre, donc jamais d'annonce.
   --------------------------------------------------------------------------- */
.bandeau {
  border-bottom: 1px solid var(--feutre-bord);
}

.bandeau .enveloppe {
  display: flex;
  align-items: center;
  gap: var(--e-5);
  padding-block: var(--e-4);
  flex-wrap: wrap;
}

.marque {
  font: 700 var(--taille-l) var(--police-titre);
  letter-spacing: var(--suivi-titre);
  text-transform: uppercase;
  color: var(--creme);
  text-decoration: none;
}

.marque span {
  color: var(--accent-lisible);
}

.menu {
  display: flex;
  gap: var(--e-4);
  margin-left: auto;
  flex-wrap: wrap;
}

.menu a {
  color: var(--creme-douce);
  text-decoration: none;
  font-size: var(--taille-s);
  letter-spacing: 0.02em;
}

.menu a:hover,
.menu a[aria-current="page"] {
  color: var(--accent-lisible);
}

.pied {
  border-top: 1px solid var(--feutre-bord);
  padding: var(--e-5) 0 var(--e-4);
  font-size: var(--taille-s);
  color: var(--creme-douce);
}

.pied .rangee {
  display: flex;
  gap: var(--e-5);
  flex-wrap: wrap;
  margin-bottom: var(--e-3);
}

.pied a {
  text-decoration: none;
}

.pied .credit {
  font-size: var(--taille-xs);
  color: var(--creme-douce);
  opacity: 0.7;
}

/* ---------------------------------------------------------------------------
   Le couvercle de boîte : l'accroche de l'accueil.
   --------------------------------------------------------------------------- */
.heros {
  padding: var(--e-6) 0;
}

.heros .enveloppe {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e-6);
  align-items: center;
}

.jour {
  font: 500 var(--taille-xs) var(--police-chiffre);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--kraft);
  margin-bottom: var(--e-3);
}

.heros h1 {
  font-size: clamp(2.25rem, 5.4vw, var(--taille-xxl));
  font-weight: 700;
  margin-bottom: var(--e-2);
}

.heros h1 em {
  font-style: normal;
  color: var(--accent-lisible);
  display: block;
}

.heros p {
  color: var(--creme-douce);
  font-size: 1.125rem;
  max-width: 44ch;
  margin-bottom: var(--e-4);
}

.actions {
  display: flex;
  gap: var(--e-3);
  flex-wrap: wrap;
  align-items: center;
}

/* Le fond vient de `--accent`, le texte de `--sur-accent`, et c'est la SEULE
   combinaison permise : un thème qui change l'accent doit dire ce qui se pose
   dessus, et `bin/verifier-contraste.php` vérifie la paire. L'accent employé
   comme texte, lui, a son propre jeton — ce n'est pas le même métier. */
.bouton {
  background: var(--accent);
  color: var(--sur-accent);
  font: 600 1rem var(--police-texte);
  border: none;
  padding: var(--e-3) var(--e-5);
  border-radius: var(--rayon);
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}

.bouton:hover {
  background: var(--accent-vif);
}

.bouton-2 {
  background: transparent;
  color: var(--creme);
  border: 1px solid var(--feutre-bord);
  padding: var(--e-3) var(--e-4);
  border-radius: var(--rayon);
  font: 600 1rem var(--police-texte);
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}

/* ---------------------------------------------------------------------------
   Le carton : tout le contenu, et tous les emplacements publicitaires.
   L'épaisseur vient du liseré bas, pas d'une ombre floue — une boîte de
   carton a des coins vifs.
   --------------------------------------------------------------------------- */
.boite {
  background: var(--carton);
  border-radius: var(--rayon-boite);
  padding: var(--e-3) var(--e-3) var(--e-2);
  color: var(--encre);
  box-shadow: var(--epaisseur), var(--ombre-table);
  position: relative;
}

.boite .etiquette-pieces {
  position: absolute;
  top: -11px;
  right: var(--e-4);
  background: var(--vert);
  color: var(--creme);
  font: 600 0.75rem var(--police-chiffre);
  letter-spacing: 0.1em;
  padding: 5px var(--e-2);
  border-radius: 3px;
}

.boite .photo {
  aspect-ratio: 4 / 3;
  border-radius: 3px;
  overflow: hidden;
  background: var(--carton-bord);
}

.boite .photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.etiq {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  padding: var(--e-3) var(--e-1) 2px;
  gap: var(--e-3);
}

.etiq h2,
.etiq h3 {
  font-size: 1.1875rem;
  font-weight: 600;
  letter-spacing: 0;
}

.etiq small {
  display: block;
  font: 400 var(--taille-xs) var(--police-texte);
  color: var(--encre-douce);
  text-transform: none;
  letter-spacing: 0;
  margin-top: 2px;
}

.chrono {
  font: 600 var(--taille-l) var(--police-chiffre);
  color: var(--vert);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.chrono small {
  display: block;
  font: 400 0.75rem var(--police-texte);
  color: var(--encre-douce);
}

/* ---------------------------------------------------------------------------
   L'étagère : les catégories.
   --------------------------------------------------------------------------- */
.section {
  padding: var(--e-6) 0;
}

.section + .section {
  padding-top: 0;
}

.entete {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: var(--e-5);
  gap: var(--e-4);
  flex-wrap: wrap;
}

.entete h2 {
  font-size: var(--taille-xl);
  font-weight: 600;
}

.entete a {
  font-size: var(--taille-s);
  color: var(--kraft);
  text-decoration: none;
  border-bottom: 1px solid var(--feutre-bord);
  padding-bottom: 2px;
}

.grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--e-4);
}

.mini {
  background: var(--carton);
  border-radius: 5px;
  padding: var(--e-2);
  color: var(--encre);
  text-decoration: none;
  display: block;
  box-shadow: 0 2px 0 var(--carton-ombre);
  transition: transform 0.16s;
}

.mini:hover {
  transform: translateY(-4px);
}

.mini .vignette {
  height: 104px;
  border-radius: 3px;
  margin-bottom: var(--e-2);
  background: var(--carton-bord);
  overflow: hidden;
}

.mini h2,
.mini h3 {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0;
}

.mini span {
  font: 400 0.8125rem var(--police-chiffre);
  color: var(--encre-douce);
}

/* ---------------------------------------------------------------------------
   Le tableau des records : du feutre clair, donc sans annonce lui non plus.
   --------------------------------------------------------------------------- */
.tableau {
  background: var(--feutre-clair);
  border-radius: 8px;
  padding: var(--e-4) var(--e-5);
}

.tableau h2 {
  font-size: var(--taille-l);
  margin-bottom: var(--e-3);
  font-weight: 600;
}

.tableau table {
  width: 100%;
  border-collapse: collapse;
  font-size: 1rem;
}

.tableau th {
  text-align: left;
  font: 600 0.75rem var(--police-chiffre);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--kraft);
  padding-bottom: var(--e-2);
  border-bottom: 1px solid var(--feutre-bord);
}

.tableau td {
  padding: var(--e-2) 0;
  border-bottom: 1px solid var(--feutre-bord);
  color: var(--creme);
}

.tableau .temps {
  font-family: var(--police-chiffre);
  font-variant-numeric: tabular-nums;
  color: var(--accent-lisible);
  text-align: right;
}

.tableau .rang {
  font-family: var(--police-chiffre);
  color: var(--creme-douce);
  width: 34px;
}

/* ---------------------------------------------------------------------------
   La page de jeu.

   AUCUNE PUBLICITÉ ICI — règle 3, le canvas est sacré. Le seul emplacement
   de cette page est sur l'écran de fin, une fois la partie terminée : c'est
   le meilleur du site, attention maximale et pause naturelle.

   Le plateau se dimensionne en unités de fenêtre : sur un téléphone tenu à
   la verticale, il doit rester jouable sans qu'on défile.
   --------------------------------------------------------------------------- */
.barre-jeu {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  margin-bottom: var(--e-3);
  flex-wrap: wrap;
}

.barre-jeu .chrono {
  font-size: var(--taille-xl);
  color: var(--kraft);
  text-align: left;
}

.barre-jeu .progression {
  font-family: var(--police-chiffre);
  color: var(--creme-douce);
  margin-right: auto;
}

.plateau {
  position: relative;
  height: min(70vh, 720px);
  background: var(--feutre-clair);
  border: 1px solid var(--feutre-bord);
  border-radius: var(--rayon-boite);
  overflow: hidden;
  outline-offset: -3px;
}

.plateau:focus-visible {
  outline: 3px solid var(--focus);
}

.fin {
  background: var(--carton);
  color: var(--encre);
  border-radius: var(--rayon-boite);
  box-shadow: var(--epaisseur);
  padding: var(--e-4);
  margin-top: var(--e-4);
  display: grid;
  gap: var(--e-3);
  justify-items: start;
}

.fin .chrono,
.fin p {
  color: var(--encre);
}

.fin .serie {
  font: 500 var(--taille-s) var(--police-chiffre);
  color: var(--vert);
}

.fin .actions-fin {
  display: flex;
  gap: var(--e-2);
  flex-wrap: wrap;
  align-items: center;
}

.fin .texte-partage {
  width: 100%;
  max-width: 34rem;
  padding: var(--e-2);
  font: inherit;
  font-size: var(--taille-s);
  border: 1px solid var(--carton-bord);
  border-radius: var(--rayon);
  background: var(--creme);
  color: var(--encre);
  resize: vertical;
}

/* ---------------------------------------------------------------------------
   Le formulaire de record — LOI 25.

   Il est posé sur du carton comme le reste de l'écran de fin, et il porte sa
   phrase de consentement à côté de la case : pas un lien, pas une astérisque.
   Le bloc de courriel est `hidden` tant que la case n'est pas cochée — c'est
   le gabarit qui le pose, et le JS qui le révèle.
   --------------------------------------------------------------------------- */
.record {
  display: grid;
  gap: var(--e-3);
  justify-items: start;
  width: 100%;
  max-width: 34rem;
  padding: var(--e-3);
  border: 1px solid var(--carton-bord);
  border-radius: var(--rayon);
}

.record p {
  margin: 0;
  width: 100%;
}

.record .record-titre {
  font-weight: 600;
  color: var(--vert);
}

.record label {
  display: block;
  font-size: var(--taille-s);
  color: var(--encre-douce);
  margin-bottom: var(--e-1);
}

.record label.case {
  display: flex;
  align-items: flex-start;
  gap: var(--e-2);
  color: var(--encre);
  margin-bottom: 0;
  line-height: 1.45;
}

/* La case ne rétrécit pas quand la phrase à côté fait deux lignes. */
.record label.case input {
  flex: 0 0 auto;
  margin-top: 0.2em;
}

.record input[type="text"],
.record input[type="email"] {
  width: 100%;
  padding: var(--e-2);
  font: inherit;
  font-size: var(--taille-s);
  border: 1px solid var(--carton-bord);
  border-radius: var(--rayon);
  background: var(--creme);
  color: var(--encre);
}

.record small {
  display: block;
  margin-top: var(--e-1);
  font-size: var(--taille-xs);
  color: var(--encre-douce);
}

.record .record-etat {
  font-size: var(--taille-s);
  color: var(--alerte);
}

/* ---------------------------------------------------------------------------
   Pagination des catégories.
   --------------------------------------------------------------------------- */
.pagination {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  margin-top: var(--e-5);
  flex-wrap: wrap;
}

.pagination span {
  color: var(--creme-douce);
  font-family: var(--police-chiffre);
  font-size: var(--taille-s);
}

/* ---------------------------------------------------------------------------
   La navigation de l'administration.

   Elle n'a aucune raison d'être thématisée — un décor de Noël sur un écran
   de révision n'aide personne — mais elle vit ici plutôt que dans un fichier
   à part : c'est le même squelette, les mêmes jetons, et une deuxième
   feuille serait une deuxième chose à tenir à jour.
   --------------------------------------------------------------------------- */
.menu-admin {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  flex-wrap: wrap;
  margin-bottom: var(--e-4);
  padding-bottom: var(--e-3);
  border-bottom: 1px solid var(--feutre-bord);
}

.menu-admin a {
  color: var(--creme-douce);
  text-decoration: none;
  font-size: var(--taille-s);
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}

.menu-admin a:hover {
  color: var(--creme);
}

/* L'écran courant se marque par `aria-current`, et le style s'accroche
   dessus. Une classe « active » en plus serait une deuxième vérité à tenir
   d'accord avec la première — et c'est celle du lecteur d'écran qui compte. */
.menu-admin a[aria-current="page"] {
  color: var(--creme);
  border-bottom-color: var(--accent-lisible);
}

.menu-admin form {
  margin: 0 0 0 auto;
}

/* Les formulaires d'administration : deux colonnes sur large, une seule sur
   étroit. Les champs qui prennent toute la largeur le disent eux-mêmes avec
   `grid-column: 1 / -1` — c'est le seul style en ligne qu'ils portent. */
.formulaire-admin {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--e-3);
  align-items: end;
}

.formulaire-admin p {
  margin: 0;
}

.formulaire-admin label {
  display: block;
  font-size: var(--taille-s);
  color: var(--encre-douce);
  margin-bottom: var(--e-1);
}

.formulaire-admin label.case {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  color: var(--encre);
  margin-right: var(--e-4);
}

.formulaire-admin input[type="text"],
.formulaire-admin input[type="number"],
.formulaire-admin input[type="date"],
.formulaire-admin select,
.formulaire-admin textarea {
  width: 100%;
  padding: var(--e-2);
  font: inherit;
  font-size: var(--taille-s);
  border: 1px solid var(--carton-bord);
  border-radius: var(--rayon);
  background: var(--creme);
  color: var(--encre);
}

.formulaire-admin textarea {
  resize: vertical;
  line-height: var(--interligne);
}

.tableau-admin {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--taille-s);
  color: var(--encre);
}

.tableau-admin th,
.tableau-admin td {
  text-align: left;
  padding: var(--e-2);
  border-bottom: 1px solid var(--carton-bord);
}

.tableau-admin th {
  color: var(--encre-douce);
  font-weight: 600;
}

/* Le calendrier : sept colonnes ne tiennent pas sur un téléphone, et un
   écran d'administration se consulte aussi depuis un fauteuil. La grille
   s'adapte au lieu d'imposer la semaine. */
.calendrier {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--e-3);
}

.calendrier .jour {
  background: var(--carton);
  border-radius: var(--rayon-boite);
  box-shadow: 0 2px 0 var(--carton-ombre);
  padding: var(--e-3);
  color: var(--encre);
  display: grid;
  gap: var(--e-2);
  align-content: start;
}

/* Un jour vide se voit. C'est le seul état qui demande une action, et une
   grille de vingt-huit cartes identiques ne le dirait pas. */
.calendrier .jour-vide {
  background: var(--carton-bord);
}

.calendrier .jour h2 {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e-2);
}

.calendrier .jour h2 small {
  font: 400 0.75rem var(--police-chiffre);
  color: var(--encre-douce);
}

.calendrier .jour select {
  width: 100%;
  padding: var(--e-1) var(--e-2);
  font: inherit;
  font-size: var(--taille-xs);
  border: 1px solid var(--carton-bord);
  border-radius: var(--rayon);
  background: var(--creme);
  color: var(--encre);
}

.calendrier .jour .actions {
  display: flex;
  gap: var(--e-2);
  flex-wrap: wrap;
}

/* Une étiquette que seul un lecteur d'écran entend. Vingt-huit `<select>`
   étiquetés visuellement noieraient la grille ; sans étiquette du tout, ils
   ne s'annoncent pas. */
.invisible {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   Les pages légales. Du carton, du texte, et rien d'autre : ce sont des
   pages qu'on lit une fois, souvent parce qu'on cherche à qui écrire. Aucune
   annonce n'y est posée — pas parce que c'est interdit, parce que ce serait
   absurde.

   La mesure de lecture est bornée : au-delà de 70 caractères par ligne, l'œil
   perd le début de la ligne suivante. Une politique de confidentialité est
   déjà assez pénible à lire.
   --------------------------------------------------------------------------- */
.page-legale {
  background: var(--carton);
  color: var(--encre);
  border-radius: var(--rayon-boite);
  box-shadow: var(--epaisseur);
  padding: var(--e-5);
  max-width: 44rem;
}

.page-legale h1 {
  font-size: var(--taille-xl);
  margin-bottom: var(--e-4);
}

.page-legale h2 {
  font-size: var(--taille-l);
  margin: var(--e-5) 0 var(--e-2);
}

.page-legale p,
.page-legale li {
  line-height: var(--interligne);
  margin-bottom: var(--e-3);
}

.page-legale ul {
  margin: 0 0 var(--e-3) 1.2em;
}

/* --kraft sur --carton donne 1,8:1 — jamais. Voir la note de tokens.css. */
.page-legale a {
  color: var(--kraft-fonce);
}

/* ---------------------------------------------------------------------------
   La bannière de consentement — RÈGLE 7, LOI 25.

   Posée en bas, en travers, au-dessus du reste. Elle ne bloque rien : le site
   se lit et se joue sans y répondre. Un mur qui empêche de lire transforme un
   consentement libre en péage.

   Les deux boutons ont EXACTEMENT le même style. Refuser doit être aussi
   facile qu'accepter, et un « refuser » en gris pâle à côté d'un « accepter »
   orange est un refus rendu difficile — ce que la Loi 25 n'admet pas. C'est
   pour ça que les deux portent `.bouton` et qu'aucune règle ne les
   différencie ici.
   --------------------------------------------------------------------------- */
.consentement {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 50;
  background: var(--carton);
  color: var(--encre);
  border-top: 3px solid var(--carton-ombre);
  padding: var(--e-3) 0;
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.25);
}

.consentement p {
  margin: 0 0 var(--e-2);
  max-width: 44rem;
  font-size: var(--taille-s);
  line-height: var(--interligne);
}

.consentement-actions {
  display: flex;
  gap: var(--e-3);
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 0;
}

.consentement-actions a {
  color: var(--kraft-fonce);
  font-size: var(--taille-s);
}

/* ---------------------------------------------------------------------------
   Emplacement publicitaire — RÈGLE 19.
   Toujours sur du carton, jamais sur du feutre, et à hauteur réservée : un
   conteneur qui grandit à l'arrivée de l'annonce décale la page et dégrade
   les Core Web Vitals, ce qui pénalise à la fois le référencement et le
   revenu.
   Aucune annonce n'est posée avant l'approbation AdSense ; cette règle
   attend son contenu.
   --------------------------------------------------------------------------- */
.publicite {
  background: var(--pub-fond);
  border-radius: var(--rayon);
  min-height: var(--pub-hauteur-mobile);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

@media (min-width: 52rem) {
  .publicite {
    min-height: var(--pub-hauteur-bureau);
  }
}

/* --------------------------------------------------------------------------- */
@media (max-width: 52rem) {
  .heros {
    padding: var(--e-5) 0;
  }

  .heros .enveloppe {
    grid-template-columns: 1fr;
    gap: var(--e-5);
  }

  .bandeau .enveloppe {
    gap: var(--e-3);
  }

  .menu {
    margin-left: 0;
    width: 100%;
  }
}
