/*
Theme Name:  Yukademia Soleil
Theme URI:   https://yukademia.com
Description: Style Template officiel n°5 de Yukademia, registre « objets posés dans la lumière ». Rien ne touche le bord : la page est un sol crème unique, les sections sont des objets à grand rayon séparés par une pénombre teintée, jamais par un changement d'aplat. La navigation est une pilule flottante qui ouvre un panneau unique : le menu du site, le sommaire de la page lue et les coordonnées. Requiert le plugin yukademia-core. Design figé à la livraison ; seule la personnalisation en base (branding, contenu) varie.
Author:      Yukademia
Version:     2.14.1
Requires PHP: 8.0
Text Domain: yukademia-theme-soleil
*/

/* ============================================================
   SOLEIL — système de design

   LA RÈGLE QUI TIENT TOUT : rien ne touche le bord, et deux
   surfaces voisines ne se distinguent presque pas. Le sol est le
   même partout — une seule valeur de fond, sans exception. Ce qui
   sépare deux sections, c'est l'OMBRE et l'AIR, jamais une rupture
   d'aplat. Relevé sur la référence : la carte blanche et le fond
   crème sont à moins de 2 % de luminance l'un de l'autre ; c'est
   la pénombre teintée qui découpe la carte, pas son remplissage.

   Conséquence directe, et c'est ce qui distingue ce thème :
   Bulletin structure par les filets, Marelle par les aplats,
   Herbier par le vide, Kermesse par un panneau blanc posé sur un
   CHAMP DE COULEUR. Soleil n'a pas de champ de couleur du tout.

   Palette : rôles --ecole-*, cinq couleurs pilotables. La sauge est
   une CONSTANTE du thème, comme le rose et le bleu de Marelle
   (DECISIONS.md, 19 août 2026) : elle couvre moins de 1 % de la
   page. Le plugin injecte le branding à wp_head prio 99 — son :root
   arrive après cette feuille et l'emporte.

   Typo : Lora 400 pour les titres, Outfit 400 pour le texte. Lora
   appartient à la liste fermée, Outfit non — c'est la seule police
   propre au thème (précédent Kermesse). Empattements légèrement
   incurvés contre géométrique à `a` d'un seul étage : le contraste
   entre les deux tient, sans reposer sur des déliés qui blanchissent.

   Espacement : 4 8 16 24 fixes, puis six crans fluides.
   Tailles de texte : six crans nommés, tous en clamp().
   Rayons : 999 / 18 / 24 / 32 / 40 / 48.
   Points de rupture : 560 / 768 / 1024 / 1440, et eux seuls
   (DECISIONS.md, 19 août 2026 — contrôlé par verifier-css.py).
   ============================================================ */

/* ---------- Polices auto-hébergées (OFL, fichiers dans le thème) ----------
   Les dix familles de la liste fermée sont embarquées, comme dans tous
   les Style Templates : une école peut choisir n'importe laquelle dans
   ses Réglages, et une famille absente retomberait en silence sur la
   pile de secours. Le navigateur ne télécharge que celle qui sert.

   S'y ajoute la seule famille PROPRE au thème, qui n'est dans aucun
   `select` de branding : Outfit. Les titres sont en Lora, qui est du
   catalogue — depuis le 10 septembre 2026, voir plus bas. */

@font-face {
  font-family: 'Outfit';
  src: url('assets/fonts/outfit-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Outfit';
  src: url('assets/fonts/outfit-latin-500-normal.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Outfit';
  src: url('assets/fonts/outfit-latin-600-normal.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}

@font-face {
  font-family: 'Libre Baskerville';
  src: url('assets/fonts/libre-baskerville-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Libre Baskerville';
  src: url('assets/fonts/libre-baskerville-latin-700-normal.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Libre Baskerville';
  src: url('assets/fonts/libre-baskerville-latin-400-italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Lora';
  src: url('assets/fonts/lora-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Lora';
  src: url('assets/fonts/lora-latin-400-italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Playfair Display';
  src: url('assets/fonts/playfair-display-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Playfair Display';
  src: url('assets/fonts/playfair-display-latin-400-italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('assets/fonts/eb-garamond-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'EB Garamond';
  src: url('assets/fonts/eb-garamond-latin-400-italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  src: url('assets/fonts/bricolage-grotesque-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  src: url('assets/fonts/bricolage-grotesque-latin-700-normal.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'DM Sans';
  src: url('assets/fonts/dm-sans-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'DM Sans';
  src: url('assets/fonts/dm-sans-latin-500-normal.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'DM Sans';
  src: url('assets/fonts/dm-sans-latin-600-normal.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'DM Sans';
  src: url('assets/fonts/dm-sans-latin-300-italic.woff2') format('woff2');
  font-weight: 300; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('assets/fonts/inter-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('assets/fonts/inter-latin-500-normal.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('assets/fonts/inter-latin-600-normal.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-latin-500-normal.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Nunito Sans';
  src: url('assets/fonts/nunito-sans-latin-600-normal.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Work Sans';
  src: url('assets/fonts/work-sans-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Work Sans';
  src: url('assets/fonts/work-sans-latin-500-normal.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Work Sans';
  src: url('assets/fonts/work-sans-latin-600-normal.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Figtree';
  src: url('assets/fonts/figtree-latin-400-normal.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Figtree';
  src: url('assets/fonts/figtree-latin-500-normal.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Figtree';
  src: url('assets/fonts/figtree-latin-600-normal.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}

/* ============================================================
   VARIABLES
   ============================================================ */

:root {
  /* ---- LES CINQ RÔLES PILOTABLES ----
     Valeurs pipetées sur la référence, pas approchées à l'œil :
     crème #FEFCF4 sur la totalité du sol, terracotta #DE6B4F sur
     les boutons et l'aplat d'appel, soleil #F7DD7D sur le bouton
     d'en-tête et le soulignement actif, azur #D8F5F5 sur les
     pilules de sur-titre.

     Ces cinq-là sont ÉCRASÉES par le branding de l'école, et c'est
     voulu (DECISIONS.md, 7 août 2026). L'identité du thème n'y
     repose pas : elle tient dans les rayons, l'objet flottant,
     l'anneau, l'ombre teintée et le contraste typographique. Une
     école au branding vert garde un Soleil reconnaissable. */
  --ecole-fond:       #FEFCF4;
  --ecole-texte:      #1F1A16;
  --ecole-primaire:   #DE6B4F;
  --ecole-secondaire: #F7DD7D;
  --ecole-accent:     #D8F5F5;

  /* ---- LA SAUGE — CONSTANTE DU THÈME ----
     Non pilotable, au même titre que les rayons et le couple
     typographique. Motif identique à celui du rose et du bleu de
     Marelle : elle ne porte qu'un objet, la forme décorative du
     héro, soit moins de 1 % de la page. Une couleur qui couvre si
     peu n'est pas une couleur de marque.

     LA VALEUR DE LA RÉFÉRENCE A ÉTÉ ASSOMBRIE. Relevé sur la
     capture : le texte sauge du médaillon tient autour de 2,4:1
     contre le crème — sous le seuil de 4,5:1. La teinte de l'aplat
     est conservée telle quelle ; celle du texte est descendue. */
  --s-sauge:        #4F6B54;
  --s-sauge-aplat:  #F1F3E8;

  /* ---- SURFACES ----
     `--s-carte` ne s'éloigne du sol que de 12 % vers le blanc, et
     c'est délibéré : sur la référence, la carte et le fond sont
     quasi indiscernables. Une carte plus contrastée redeviendrait
     une bande, c'est-à-dire le geste des trois premiers thèmes.
     C'est l'ombre qui découpe, pas le remplissage. */
  /* ---- LA PRIMAIRE LISIBLE ----
     MESURÉ, PAS SUPPOSÉ, sur le rendu du 25 août 2026 : le terracotta
     de la référence `#DE6B4F` donne **3,23:1** contre le crème, dans
     les deux sens — en texte comme en aplat sous du texte clair. Le
     seuil du texte courant est 4,5:1. La référence Lovable échoue donc
     sur ses propres boutons, son bouton d'appel et ses liens.

     Barème relevé au dixième : 88 % du terracotta donne 3,95 ; 82 %,
     4,39 ; **78 %, 4,7**. C'est la valeur retenue — la teinte reste
     franchement terracotta, elle descend d'un demi-ton.

     LA MÊME COULEUR EST JUSTE OU FAUSSE SELON LA TAILLE DU TEXTE
     QU'ELLE PORTE. Le terracotta PLEIN reste employé partout où le
     seuil est celui du grand texte ou du non-textuel — mot accentué du
     H1 à 58 px, chiffres à 42 px, pastille de marque, points de note,
     signe d'accordéon : tous tiennent au-dessus de 3:1. La version
     lisible ne sert qu'au texte courant et aux aplats qui en portent.

     La dérivation vise `--ecole-texte` et non un noir fixe, et c'est
     ce qui la rend SYMÉTRIQUE : sur une école à fond sombre et encre
     claire, elle éclaircit la primaire au lieu de l'assombrir — donc
     dans les deux polarités elle l'éloigne du fond. */
  --s-primaire-lisible: color-mix(in oklab, var(--ecole-primaire) 78%, var(--ecole-texte));

  --s-carte:   color-mix(in oklab, var(--ecole-fond) 88%, #fff);
  --s-voile:   color-mix(in oklab, var(--s-carte) 82%, transparent);
  --s-filet:   color-mix(in oklab, var(--ecole-primaire) 14%, transparent);
  --s-filet-fort: color-mix(in oklab, var(--ecole-primaire) 30%, transparent);
  --s-doux:    color-mix(in oklab, var(--ecole-texte) 62%, var(--ecole-fond));

  /* Teintes de tuile : trois dilutions, une par rôle de couleur.
     Elles ne portent JAMAIS de texte — mesuré sur la référence,
     l'azur donne 1,1:1 contre le crème. Elles portent une image
     d'icône ou rien. */
  --s-tuile-1: color-mix(in oklab, var(--ecole-accent) 62%, var(--ecole-fond));
  --s-tuile-2: color-mix(in oklab, var(--ecole-secondaire) 34%, var(--ecole-fond));
  --s-tuile-3: color-mix(in oklab, var(--ecole-primaire) 14%, var(--ecole-fond));

  /* Texte posé sur l'aplat de primaire. Le fond de page plutôt que
     du blanc en dur : une école au fond crème garde la chaleur, une
     école au fond blanc obtient du blanc. BORNE CONNUE ET NON
     MASQUÉE : si l'école saisit une primaire CLAIRE, ce couple
     tombe sous le seuil. Ni le thème ni l'app ne contrôlent la
     saisie — le contrôle de contraste à la livraison est le seul
     garde-fou, comme sur Marelle. */
  --s-sur-primaire: var(--ecole-fond);

  /* ---- OMBRES ----
     Teintées de la primaire, jamais noires. C'est le trait le plus
     reconnaissable de la référence après les rayons : une pénombre
     grise donnerait un thème d'administration. */
  --s-ombre-basse: 0 6px 16px -8px color-mix(in oklab, var(--ecole-primaire) 22%, transparent);
  --s-ombre:       0 20px 40px -15px color-mix(in oklab, var(--ecole-primaire) 26%, transparent);
  --s-ombre-haute: 0 34px 64px -24px color-mix(in oklab, var(--ecole-primaire) 34%, transparent);

  /* ---- RAYONS — CONSTANTES DU THÈME ---- */
  --s-r-pilule:    999px;
  --s-r-tuile:     18px;
  --s-r-photo:     24px;
  --s-r-carte:     32px;
  --s-r-medaillon: 40px;
  --s-r-panneau:   48px;

  /* ---- ESPACEMENT ----
     Crans 1 à 4 FIXES : ce sont des distances de contact — gouttière
     d'icône, retrait de liste — qui n'ont aucune raison de suivre
     l'écran. Crans 5 à 10 fluides, bornés aux deux bouts. */
  --s-s1: 4px;
  --s-s2: 8px;
  --s-s3: 16px;
  --s-s4: 24px;
  --s-s5: clamp(28px, 2.6vw + 20px, 40px);
  --s-s6: clamp(36px, 3.4vw + 25px, 60px);
  --s-s7: clamp(48px, 4.4vw + 34px, 88px);
  --s-s8: clamp(64px, 5.6vw + 46px, 120px);
  --s-s9: clamp(80px, 7vw + 58px, 160px);
  --s-s10: clamp(96px, 9vw + 68px, 208px);

  /* ---- TAILLES DE TEXTE — SIX CRANS, TOUS FLUIDES ---- */
  --s-fs-xs:  clamp(12px, 0.18vw + 11.4px, 14px);
  --s-fs-s:   clamp(14px, 0.18vw + 13.4px, 16px);
  --s-fs-m:   clamp(16px, 0.27vw + 15.1px, 19px);
  --s-fs-l:   clamp(20px, 0.54vw + 18.3px, 26px);
  --s-fs-xl:  clamp(26px, 2.34vw + 18.5px, 52px);
  --s-fs-2xl: clamp(34px, 3.42vw + 23.1px, 72px);

  /* ---- LARGEURS ----
     Deux conteneurs, et c'est un choix de composition : le contenu
     lu reste borné pour la longueur de ligne, le panneau du chariot
     va presque au bord — relevé à 14 px de marge sur la référence.
     Le troisième sert à l'appel à l'action, mesuré à 672 px, soit
     nettement plus étroit que le reste de la page. */
  /* LA COLONNE prend sa place dans le flux par un retrait du corps,
     pas par une superposition : rien ne passe dessous, et il n'y a
     donc aucune bande fixe à dégager en haut de page. */

  /* EN POURCENTAGE DU CONTENU, PAS EN `vw`. Le corps est retiré de la
     largeur de la colonne : une largeur exprimée en `vw` ignore ce
     retrait et déborde d'autant. Mesuré au premier rendu de la
     colonne — 233 px de débordement à 1440, dont 46 sur le conteneur
     de lecture et 248 sur le panneau large. `%` se résout sur le
     parent, donc sur la zone réellement disponible, et suit le
     retrait sans qu'on ait à le soustraire nulle part.

     *Une unité de fenêtre dans une mise en page qui n'occupe pas la
     fenêtre est une erreur qui ne se voit pas : `overflow-x: hidden`
     rogne avant de peindre.* */
  /* Hauteur de la pilule, telle qu'elle se rend : elle sert à poser
     le panneau juste en dessous, et lui seul en dépend. */
  /* Tracé Tabler Icons (MIT), encodé en URI de données : un masque
     prend la couleur du texte, donc le picto suit le survol du
     bouton sans qu'il faille une seconde règle. */
  --s-glyphe-doc: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-2'/%3E%3Cpath d='M7 11l5 5l5 -5'/%3E%3Cpath d='M12 4v12'/%3E%3C/svg%3E");

  --s-entete-h: 68px;

  /* RÉFÉRENCE DU PARC : Étoile (DECISIONS.md, 2 septembre 2026) —
     contenu borné à 71.25rem (1140 px), gouttière de 4 % de l'écran,
     20 px au plancher, 40 px au plafond, 48 px dès 1440 px. Elle ne vaut
     que pour le bord de la page ; les espacements internes restent ceux
     du thème. */
  --s-gouttiere: clamp(20px, 4vw, 40px);
  /* Les largeurs se déduisent de la gouttière au lieu d'un pourcentage
     propre à chacune : 92 / 96 / 88 % donnaient trois bords différents,
     dont un à 2 % pour les panneaux, et 15 px sur un téléphone. */
  --s-largeur:         min(100% - 2 * var(--s-gouttiere), 71.25rem);
  --s-largeur-panneau: min(100% - 2 * var(--s-gouttiere), 71.25rem);
  --s-largeur-etroite: min(100% - 2 * var(--s-gouttiere), 680px);
  --s-lisible: 68ch;

  /* ---- TYPOGRAPHIE ---- */
  --s-titre: var(--ecole-font-titre, 'Lora'), Georgia, 'Times New Roman', serif;
  --s-texte: var(--ecole-font-texte, 'Outfit'), system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* ---- MOUVEMENT ----
     Une seule courbe dans tout le thème, reprise de la référence.
     Un thème qui mélange trois courbes n'a pas de mouvement, il a
     des animations. */
  --s-courbe: cubic-bezier(0.16, 1, 0.3, 1);
  --s-duree:  0.5s;

  /* ---- TEINTES DE CARTE ----
     Sans prise en charge de la syntaxe relative, les cartes restent
     `--s-carte` : le thème d'avant, rien ne casse. Voir le bloc
     `@supports` juste en dessous. */
  --s-teinte-1: var(--s-carte);
  --s-teinte-2: var(--s-carte);
  --s-teinte-3: var(--s-carte);
  --s-texte-teinte: var(--s-doux);
}

/* LES CARTES D'UNE SÉRIE PORTENT LA COULEUR DE L'ÉCOLE (29 septembre
   2026). Le sol reste unique : ce sont les OBJETS posés dessus qui se
   colorent, jamais une bande — Soleil n'a toujours pas de champ de
   couleur.

   Le texte est posé sur une couleur SAISIE PAR L'ÉCOLE, la faute que
   Marelle porte encore en point ouvert. Parade : on ne dilue pas la
   couleur, on lui IMPOSE sa clarté. Chaque teinte garde la teinte et
   au plus 0,08 de chroma de la couleur saisie, à une luminosité OKLCH
   fixe de 0,92. Mesuré sur les défauts et sur noir, marine, rouge,
   vert, gris et jaune vif : encre de l'école ≥ 12,4:1, texte des
   cartes à 74 % d'encre ≥ 6,0:1. La primaire lisible, elle, tombe à
   3,5:1 — les liens des cartes teintées passent donc à l'encre.

   BORNE CONNUE : une école à fond sombre et encre claire aurait du
   texte clair sur un pastel clair. Ni le thème ni l'app ne le
   contrôlent — même garde-fou que la primaire : le contrôle de
   contraste à la livraison. */
@supports (color: oklch(from red l c h)) {
  :root {
    --s-teinte-1: oklch(from var(--ecole-primaire)   0.92 min(c, 0.08) h);
    --s-teinte-2: oklch(from var(--ecole-secondaire) 0.92 min(c, 0.08) h);
    --s-teinte-3: oklch(from var(--ecole-accent)     0.92 min(c, 0.08) h);
    --s-texte-teinte: color-mix(in oklab, var(--ecole-texte) 74%, var(--ecole-fond));
  }
}

/* ============================================================
   SOCLE
   ============================================================ */

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

html {
  scroll-behavior: smooth;
  /* Le fil d'ancres et les sous-menus visent des sections situées
     sous une barre FIXE : sans ce dégagement, l'ancre se cale
     derrière la barre et la section paraît absente. */
  scroll-padding-top: calc(var(--s-s8) + var(--s-s4));
}

@media (prefers-reduced-motion: reduce) {
  html, .s-chariot { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background-color: var(--ecole-fond);
  color: var(--ecole-texte);
  font-family: var(--s-texte);
  font-size: var(--s-fs-m);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  /* LA LUMIÈRE, et elle vient du sud-est comme sur la référence :
     un halo chaud en haut à droite, fixé, qui ne bouge pas au
     défilement. C'est ce qui empêche le sol uniforme de paraître
     plat. */
  background-image:
    radial-gradient(58vw 42vw at 88% -6%, color-mix(in oklab, var(--ecole-primaire) 9%, transparent), transparent 68%),
    radial-gradient(46vw 34vw at 4% 4%, color-mix(in oklab, var(--ecole-secondaire) 12%, transparent), transparent 62%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  /* Conservé, mais ce n'est PAS un filet : tout débordement se
     mesure au scrollWidth comparé à innerWidth avant d'être déclaré
     absent (DECISIONS.md, 19 août 2026). La règle ne corrige rien,
     elle rend le défaut invisible. */
  overflow-x: hidden;
}

img, svg, iframe, video { max-width: 100%; }
img { height: auto; display: block; }

a { color: var(--s-primaire-lisible); text-underline-offset: 0.22em; }
a:hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 3px solid var(--ecole-primaire);
  outline-offset: 3px;
  border-radius: var(--s-s1);
}

h1, h2, h3, h4 {
  font-family: var(--s-titre);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.015em;
  margin: 0;
  text-wrap: balance;
}

h1 { font-size: var(--s-fs-2xl); }
h2 { font-size: var(--s-fs-xl); }
h3 { font-size: var(--s-fs-l); }
h4 { font-size: var(--s-fs-m); font-family: var(--s-texte); font-weight: 600; letter-spacing: 0; }

p { margin: 0 0 var(--s-s4); }
p:last-child { margin-bottom: 0; }

.s-accent { color: var(--ecole-primaire); }

.s-lecture-seule,
.screen-reader-text {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Le lien d'évitement sort de l'écran, pas du flux : masqué en
   `display:none` il ne serait jamais atteignable au clavier. */
.s-skip {
  position: absolute;
  left: var(--s-s4);
  top: calc(var(--s-s4) * -4);
  z-index: 90;
  padding: var(--s-s2) var(--s-s4);
  background: var(--s-primaire-lisible);
  color: var(--s-sur-primaire);
  border-radius: var(--s-r-pilule);
  font-size: var(--s-fs-s);
  font-weight: 600;
  text-decoration: none;
  transition: top 0.2s var(--s-courbe);
}

.s-skip:focus { top: var(--s-s4); }

/* La sentinelle du resserrement de la pilule : un point de repère
   invisible posé juste sous elle. Tant qu'il est à l'écran, on est en
   haut de page. Elle remplace un écouteur de défilement, qui se
   déclencherait à chaque image peinte. */
.s-sentinelle {
  position: absolute;
  top: var(--s-s8);
  left: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

/* ============================================================
   GABARIT — un sol, des objets posés dessus
   ============================================================ */

.s-page {
  /* Dégagement de la pilule flottante : elle mesure environ 68 px
     plus sa marge haute, et le cran 8 la couvre à toutes les largeurs
     sans media query. */
  padding-top: var(--s-s8);
}

.s-enveloppe {
  width: var(--s-largeur);
  margin-inline: auto;
}

.s-enveloppe--large   { width: var(--s-largeur-panneau); }
.s-enveloppe--etroite { width: var(--s-largeur-etroite); }

/* Le rythme vertical a TROIS CRANS selon le rôle de la section,
   pas un seul. Un cran unique est le choix par défaut, et il est
   reconnaissable : c'est ce qui fait que trois thèmes du parc se
   ressemblent.

   DESCENDUS D'UN CRAN le 26 août 2026, sur retour d'Emilien : s8 et
   s10 additionnés entre deux sections voisines donnaient jusqu'à
   240 px d'air — le sol se lisait plus que les objets posés dessus. */
.s-section { padding-block: var(--s-s7); }
.s-section--serree { padding-block: var(--s-s6); }
.s-section--ample  { padding-block: var(--s-s9); }

.s-section > * + * { margin-top: var(--s-s6); }

/* Le panneau : l'objet posé sur le sol. Il ne borde jamais la
   fenêtre — l'encart est ce qui empêche de retomber sur la bande
   pleine largeur des autres thèmes. */
.s-panneau {
  background: var(--s-carte);
  border-radius: var(--s-r-panneau);
  box-shadow: var(--s-ombre);
  padding: var(--s-s7) var(--s-s5);
}

.s-panneau--primaire {
  background: var(--s-primaire-lisible);
  color: var(--s-sur-primaire);
  box-shadow: var(--s-ombre-haute);
  position: relative;
  overflow: hidden;
}

/* Le disque clair en haut à droite de l'aplat d'appel, relevé sur
   la référence. Décor pur, donc `aria-hidden` par construction :
   c'est un pseudo-élément. */
.s-panneau--primaire::after {
  content: '';
  position: absolute;
  top: calc(var(--s-s7) * -1);
  right: calc(var(--s-s7) * -1);
  width: clamp(180px, 26vw, 340px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: color-mix(in oklab, #fff 10%, transparent);
  pointer-events: none;
}

.s-panneau--primaire > * { position: relative; }
.s-panneau--primaire h2,
.s-panneau--primaire h3 { color: var(--s-sur-primaire); }

/* ============================================================
   L'EN-TÊTE — une pilule flottante, et un seul menu qui dit tout

   La pilule est le geste de la direction artistique : un objet blanc
   à grand rayon posé sur le sol crème, avec son ombre teintée. Elle ne
   touche jamais le bord, comme le reste du thème.

   CE QU'ELLE PORTE, ET CE QU'ELLE NE PORTE PAS. Quatre liens, pas
   sept : la référence de la direction artistique en montre trois, et
   une pilule qui tient huit rubriques cesse d'être une pilule. Les
   pages restantes ne sont pas cachées pour autant — elles sont dans
   LE PANNEAU, avec toutes les autres et leurs sous-sections.

   Un seul contrôle ouvre un seul panneau, et ce panneau dit TOUT :
   les rubriques avec leurs sous-sections, les sections de la page
   qu'on est en train de lire, et de quoi joindre l'école. C'est ce
   qui remplace les micro-sous-menus au survol — qu'il faut viser en
   diagonale, qui se ferment au moindre écart, et qui ne montrent
   jamais qu'une rubrique à la fois.
   ============================================================ */

/* CENTRÉE PAR MARGE AUTOMATIQUE, JAMAIS PAR `transform`, et c'est une
   contrainte technique autant qu'un choix : un `transform` sur cet
   élément en ferait le BLOC CONTENEUR de tous ses descendants
   `position: fixed`. Le voile et le panneau du menu — qui sont ses
   enfants — se retrouvaient alors enfermés dans une pilule de 62 px
   de haut au lieu de couvrir la fenêtre. Mesuré : voile de 1178 × 60.

   C'est la même famille de piège que `backdrop-filter`, qui produit
   exactement le même effet. */
.s-entete {
  position: fixed;
  top: var(--s-s3);
  left: 0;
  right: 0;
  margin-inline: auto;
  z-index: 60;
  /* MÊME LARGEUR QUE LE CONTENU, à la même formule. Une pilule de
     1160 au-dessus d'un contenu de 1180 laisse vingt pixels de
     décalage de chaque côté : ça ne se nomme pas, mais ça se voit. */
  width: var(--s-largeur);
}

/* LA PILULE ÉPOUSE SON CONTENU. Depuis qu'elle ne porte plus que la
   marque, le déclic et l'appel à l'action, l'étirer sur toute la
   largeur du contenu laisserait huit cents pixels de verre vide au
   milieu. Elle se centre et fait sa taille. */
.s-pilule-nav {
  position: relative;
  isolation: isolate;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: var(--s-s5);
  padding: var(--s-s2) var(--s-s2) var(--s-s2) var(--s-s5);
  border: 1px solid var(--s-filet);
  border-radius: var(--s-r-pilule);
  box-shadow: var(--s-ombre);
  transition: padding 0.35s var(--s-courbe), box-shadow 0.35s var(--s-courbe);
}

/* LE FLOU EST SUR UN PSEUDO-ÉLÉMENT, PAS SUR LA PILULE, et ce n'est
   pas une préciosité : `backdrop-filter` sur un élément en fait le
   BLOC CONTENEUR de tous ses descendants positionnés, `fixed`
   compris. Posé sur la pilule, il enfermait le panneau du menu dans
   une boîte de 62 px de haut. Sur un pseudo-élément sans descendant,
   il ne piège plus personne, et le panneau peut se centrer dans la
   fenêtre à la largeur du contenu. */
.s-pilule-nav::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--s-voile);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
}

/* La pilule se resserre une fois le héro passé. Le mouvement est
   MOTIVÉ : il rend de la hauteur au contenu au moment précis où on
   commence à lire, et il dit qu'on a quitté le haut de page. Sans
   JavaScript, elle reste simplement large — rien ne casse. */
body[data-defile='1'] .s-pilule-nav {
  padding-block: var(--s-s1);
  box-shadow: var(--s-ombre-basse);
}

/* Une pilule translucide au-dessus de la page a besoin d'un fond de
   secours : `backdrop-filter` n'existe pas partout, et sans lui le
   texte de la page transparaîtrait derrière les liens. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .s-pilule-nav::before { background: var(--s-carte); }
}

@media (prefers-reduced-transparency: reduce) {
  .s-pilule-nav::before {
    background: var(--s-carte);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

.s-marque {
  display: inline-flex;
  align-items: center;
  gap: var(--s-s2);
  text-decoration: none;
  color: var(--s-primaire-lisible);
  flex: 0 0 auto;
}

.s-marque__point {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--ecole-primaire);
  flex: 0 0 auto;
  transition: width 0.35s var(--s-courbe), height 0.35s var(--s-courbe);
}

.s-marque__nom {
  font-family: var(--s-titre);
  font-size: var(--s-fs-l);
  line-height: 1.08;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.s-marque .custom-logo {
  max-height: 44px;
  width: auto;
  transition: max-height 0.35s var(--s-courbe);
}

body[data-defile='1'] .s-entete .s-marque__point { width: 22px; height: 22px; }
body[data-defile='1'] .s-entete .s-marque .custom-logo { max-height: 36px; }

.s-entete__droite {
  display: flex;
  align-items: center;
  gap: var(--s-s2);
  flex: 0 0 auto;
}

/* ---------- Le déclic ---------- */

.s-menu-tout { position: static; }

.s-declic {
  display: inline-flex;
  align-items: center;
  gap: var(--s-s2);
  min-height: 44px;
  padding: 0 var(--s-s4);
  border-radius: var(--s-r-pilule);
  font-size: var(--s-fs-s);
  font-weight: 600;
  color: var(--ecole-texte);
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background-color 0.25s var(--s-courbe);
}

.s-declic:hover { background: color-mix(in oklab, var(--ecole-primaire) 8%, transparent); }
.s-declic::-webkit-details-marker { display: none; }
.s-declic::marker { content: ''; }

/* Trois traits qui deviennent une croix. Le geste est connu, et c'est
   exactement pour ça qu'on ne l'invente pas. */
.s-declic__traits,
.s-declic__traits::before,
.s-declic__traits::after {
  display: block;
  width: 16px; height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform 0.3s var(--s-courbe), opacity 0.2s;
}

.s-declic__traits { position: relative; }
.s-declic__traits::before,
.s-declic__traits::after { content: ''; position: absolute; left: 0; }
.s-declic__traits::before { top: -5px; }
.s-declic__traits::after  { top: 5px; }

.s-menu-tout[open] .s-declic__traits { background: transparent; }
.s-menu-tout[open] .s-declic__traits::before { transform: translateY(5px) rotate(45deg); }
.s-menu-tout[open] .s-declic__traits::after  { transform: translateY(-5px) rotate(-45deg); }

/* ---------- Le panneau ----------
   Bâti sur `<details>` : il s'ouvre et se ferme SANS JAVASCRIPT. C'est
   la seule façon de ne pas rendre un site d'école dépendant d'un
   script pour être navigable.

   L'entrée est une ANIMATION et non une transition : un `<details>`
   fermé ne rend pas ses enfants, il n'y a donc aucun état de départ à
   interpoler. L'animation, elle, démarre au premier rendu. */

/* LE VOILE EST PORTÉ PAR `body`, PAS PAR LE PANNEAU, et ce n'est pas
   un détail d'implémentation : `backdrop-filter` sur la pilule en fait
   le BLOC CONTENEUR de tous ses descendants positionnés, `fixed`
   compris. Un voile déclaré `inset: 0` à l'intérieur de la pilule
   mesurait 1178 × 60 — la taille de la pilule — au lieu de couvrir la
   fenêtre. Mesuré, pas supposé.

   `body:has()` échappe à ce piège parce qu'il n'est pas un descendant,
   et il garde l'ouverture entièrement en CSS : le panneau continue de
   fonctionner sans JavaScript. */
body:has(.s-menu-tout[open])::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 55;
  background: color-mix(in oklab, var(--ecole-texte) 24%, transparent);
  animation: s-voile-entre 0.3s var(--s-courbe) both;
}

/* Le panneau se pose DANS LA FENÊTRE, à la largeur du contenu. Il ne
   peut plus hériter de celle de la pilule, qui épouse désormais ses
   trois éléments : un panneau de cinq cents pixels de large pour huit
   rubriques et leurs sous-sections serait illisible. */
.s-panneau-menu {
  position: fixed;
  top: calc(var(--s-s3) + var(--s-entete-h) + var(--s-s3));
  left: 0;
  right: 0;
  margin-inline: auto;
  z-index: 61;
  width: var(--s-largeur);
  max-height: calc(100dvh - var(--s-entete-h) - var(--s-s3) * 2 - var(--s-s5));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--s-s6);
  background: var(--s-carte);
  border: 1px solid var(--s-filet);
  border-radius: var(--s-r-panneau);
  box-shadow: var(--s-ombre-haute);
  animation: s-panneau-entre 0.42s var(--s-courbe) both;
}

@keyframes s-voile-entre {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes s-panneau-entre {
  from { opacity: 0; transform: translateY(-12px); }
  to   { opacity: 1; transform: none; }
}

.s-panneau-menu__grille {
  display: grid;
  gap: var(--s-s6);
}

.s-menu-titre {
  margin: 0 0 var(--s-s3);
  font-size: var(--s-fs-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--s-doux);
}

.s-rubriques {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: var(--s-s4);
}

.s-rubrique {
  display: block;
  padding: var(--s-s3) var(--s-s4);
  border-radius: var(--s-r-tuile);
  text-decoration: none;
  color: var(--ecole-texte);
  transition: background-color 0.25s var(--s-courbe);
}

.s-rubrique__titre {
  display: block;
  font-family: var(--s-titre);
  font-size: var(--s-fs-l);
  line-height: 1.1;
  letter-spacing: -0.015em;
}

.s-rubrique__detail {
  display: block;
  margin-top: var(--s-s1);
  font-size: var(--s-fs-xs);
  line-height: 1.5;
  color: var(--s-doux);
}

.s-rubrique:hover,
.s-rubrique:focus-visible { background: color-mix(in oklab, var(--ecole-primaire) 7%, transparent); }
.s-rubrique[aria-current] { background: var(--s-tuile-1); }

/* ---------- Le sommaire de la page lue ----------
   Il vit dans le panneau, à côté du menu du site, et il est NOMMÉ :
   sans étiquette, un visiteur d'accueil lirait « Notre esprit, Les
   lieux, Les familles » et croirait voir le menu. Deux listes qui se
   ressemblent sans se distinguer valent moins qu'une seule. */

.s-ancres { list-style: none; margin: 0; padding: 0; }

.s-ancres a {
  display: block;
  padding: var(--s-s2) var(--s-s3);
  border-radius: var(--s-r-tuile);
  font-size: var(--s-fs-s);
  color: var(--s-doux);
  text-decoration: none;
  transition: background-color 0.2s, color 0.2s;
}

.s-ancres a:hover,
.s-ancres a:focus-visible { background: var(--s-tuile-2); color: var(--ecole-texte); }

.s-joindre-menu {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-s3);
  padding: var(--s-s5);
  border-radius: var(--s-r-carte);
  background: var(--s-tuile-1);
  font-size: var(--s-fs-s);
  line-height: 1.6;
  color: var(--ecole-texte);
}

.s-joindre-menu p { margin: 0; }
.s-joindre-menu a { color: var(--ecole-texte); }


/* ============================================================
   BOUTONS — trois registres, et un seul par usage
   ============================================================ */

.s-bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-s2);
  min-height: 44px;
  padding: var(--s-s2) var(--s-s5);
  border: 1.5px solid transparent;
  border-radius: var(--s-r-pilule);
  font-family: var(--s-texte);
  font-size: var(--s-fs-s);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s var(--s-courbe), box-shadow 0.2s var(--s-courbe), background-color 0.2s;
}

.s-bouton:hover { transform: translateY(-2px); box-shadow: var(--s-ombre-basse); }
.s-bouton:active { transform: translateY(0); }

.s-bouton--plein {
  background: var(--s-primaire-lisible);
  color: var(--s-sur-primaire);
}

.s-bouton--contour {
  background: var(--s-carte);
  color: var(--ecole-texte);
  border-color: var(--s-filet);
}

.s-bouton--soleil {
  background: var(--ecole-secondaire);
  /* Le texte reste la couleur de TEXTE de l'école, pas du blanc :
     le secondaire est clair par vocation dans ce thème, et du blanc
     dessus serait illisible. */
  color: var(--ecole-texte);
}

/* Registre réservé aux boutons posés SUR l'aplat de primaire. Sans
   lui, une règle de zone repeindrait les boutons en primaire sur
   primaire — panne déjà payée sur Marelle : orange sur orange, le
   libellé disparaît. */
.s-bouton--clair {
  background: var(--s-sur-primaire);
  color: var(--s-primaire-lisible);
}

.s-bouton--fantome {
  background: transparent;
  color: var(--s-sur-primaire);
  border-color: color-mix(in oklab, var(--s-sur-primaire) 55%, transparent);
}

.s-boutons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-s3);
}

.s-boutons--centre { justify-content: center; }

/* ============================================================
   ÉTIQUETTES, TUILES, FIL D'ANCRES
   ============================================================ */

.s-pilule {
  display: inline-block;
  padding: var(--s-s2) var(--s-s4);
  border-radius: var(--s-r-pilule);
  background: var(--s-tuile-1);
  color: var(--ecole-texte);
  font-size: var(--s-fs-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.4;
}

.s-tuile {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px; height: 56px;
  border-radius: var(--s-r-tuile);
  flex: 0 0 auto;
}

.s-tuile--1 { background: var(--s-tuile-1); }
.s-tuile--2 { background: var(--s-tuile-2); }
.s-tuile--3 { background: var(--s-tuile-3); }

.s-tuile__img {
  width: 30px; height: 30px;
  object-fit: contain;
}

/* ============================================================
   RÉVÉLATION AU DÉFILEMENT
   Piège relevé sur la référence : ses blocs restent à `opacity: 0`
   quand l'observateur ne se déclenche pas — une capture pleine page
   en garde des sections vides. On part donc à 1 et on n'anime que
   si le script a pris la main.
   ============================================================ */

.js-reveal[data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s var(--s-courbe), transform 0.7s var(--s-courbe);
}

.js-reveal[data-reveal='vu'] {
  opacity: 1;
  transform: none;
}

/* À L'IMPRESSION, TOUT EST VISIBLE. Sans cette règle, une école qui
   imprime ses infos pratiques obtient les seules sections qu'elle
   avait fait défiler — l'observateur ne se déclenche pas hors écran.
   C'est la panne exacte que la référence Lovable montre sur sa propre
   capture pleine page. */
@media print {
  .js-reveal[data-reveal] { opacity: 1 !important; transform: none !important; }
  .s-entete, .s-alerte { position: static; }
  .s-page { padding-top: 0; }
}

/* ============================================================
   HÉRO
   ============================================================ */

.s-hero {
  display: grid;
  gap: var(--s-s7);
  align-items: center;
  padding-block: var(--s-s7) var(--s-s8);
}

/* LE RYTHME DU HÉRO N'APPARTIENT QU'AU HÉRO. `.s-hero` sert aussi de
   rangée texte-image À L'INTÉRIEUR d'une section qui porte déjà son
   propre rembourrage : sans cette annulation, chaque rangée de
   l'escalier de « Pédagogies » cumulait jusqu'à 280 px d'air — le
   double rembourrage était la première cause du « trop d'espace »
   relevé par Emilien le 26 août 2026. La spécificité (0,2,0) l'emporte
   sur la règle de palier à 768 px sans qu'il faille la répéter. */
.s-section .s-hero { padding-block: 0; }

.s-hero__texte > * + * { margin-top: var(--s-s4); }
.s-hero__titre { margin: 0; }

/* UNE RANGÉE SANS IMAGE PREND TOUTE LA LARGEUR. Dès 768 px la rangée
   pose deux pistes, et l'image est facultative partout où elle sert :
   intro de Notre école, cantine, bienvenue, mot de la direction,
   inscriptions. Sans elle, le texte restait dans la piste de gauche et
   la droite restait vide — vu à la cantine de Pélissanne, le
   29 septembre 2026. `:only-child` et non `:has()` : la règle tient
   dans tous les navigateurs, et la mesure de lecture reste celle de
   `.s-texte`. */
.s-hero > :only-child { grid-column: 1 / -1; }

.s-hero__accroche {
  font-size: var(--s-fs-l);
  line-height: 1.5;
  color: var(--s-doux);
  max-width: 46ch;
}

/* Le médaillon : la photo flotte dans un anneau clair, posée sur le
   sol par une ombre haute. C'est l'objet le plus reconnaissable du
   thème — il ne se recadre jamais au bord de la fenêtre. */
.s-medaillon {
  position: relative;
  isolation: isolate;
}

.s-medaillon__cadre {
  position: relative;
  z-index: 2;
  padding: var(--s-s2);
  background: var(--s-carte);
  border-radius: var(--s-r-medaillon);
  box-shadow: var(--s-ombre-haute);
}

.s-medaillon__img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: calc(var(--s-r-medaillon) - 8px);
}

/* LES FORMATS ALTERNENT DANS UNE MÊME SÉRIE. Un escalier dont toutes
   les photos sont des portraits 5/6 se lit comme la même carte
   répétée : une rangée sur deux passe au paysage 4/3 — le format des
   photos qu'une école téléverse réellement. La spécificité (0,2,0)
   l'emporte sur le 5/6 du palier 768 sans le répéter. */
.s-medaillon--paysage .s-medaillon__img { aspect-ratio: 4 / 3; }

/* L'ANNEAU SUR TOUTES LES PHOTOS (29 septembre 2026). Le médaillon
   n'était qu'à quelques endroits ; toute photo du site porte désormais
   le même anneau clair de 8 px. Posé en `border` sur l'image même, et
   non en enveloppe : aucun gabarit ne change, et le rayon intérieur se
   déduit tout seul du rayon extérieur moins l'épaisseur. La bannière
   est une photo aussi — l'objet entier reçoit l'anneau.
   Logos, icônes et signature n'en ont PAS : ce sont des marques, pas
   des photos, et un cadre autour d'un logo détouré se lit comme un
   trou. */
.s-carte__img,
.s-histoire__img,
.s-chariot__img,
.s-annee__img,
.s-membre__photo,
.s-une__media img,
.s-article__media,
.s-article__corps img,
.s-banniere {
  border: var(--s-s2) solid var(--s-carte);
}

.s-carte__img,
.s-histoire__img,
.s-annee__img,
.s-membre__photo,
.s-article__corps img { box-shadow: var(--s-ombre); }

/* Une vignette de 84 px ne porte pas 8 px d'anneau : ce serait un
   cinquième de sa largeur. */
.s-bref__vignette {
  border: 4px solid var(--s-carte);
  box-shadow: var(--s-ombre-basse);
}

/* Le jeton chiffré. LA RÉFÉRENCE LE PLACE DERRIÈRE LA PHOTO, où son
   texte disparaît sous le coin de l'image — c'est un accident de
   superposition, pas une intention. Il est ici DÉGAGÉ, en dessous à
   gauche, et posé au-dessus. Une rotation ne change pas la boîte de
   mise en page : la compensation est en pourcentage, jamais en em,
   parce que le débordement suit la largeur et non le texte. */
.s-jeton {
  position: absolute;
  z-index: 3;
  left: -2%;
  bottom: 6%;
  max-width: 62%;
  padding: var(--s-s3) var(--s-s4);
  background: var(--s-sauge-aplat);
  color: var(--s-sauge);
  border-radius: var(--s-r-tuile);
  box-shadow: var(--s-ombre-basse);
  transform: rotate(-6deg);
}

.s-jeton__valeur {
  display: block;
  font-family: var(--s-titre);
  font-size: var(--s-fs-l);
  line-height: 1;
}

.s-jeton__libelle {
  display: block;
  margin-top: var(--s-s1);
  font-size: var(--s-fs-xs);
  font-weight: 500;
  line-height: 1.3;
}

/* ============================================================
   CARTES
   ============================================================ */

/* `auto-fit` plutôt qu'un palier : une media query interroge le
   viewport, jamais la boîte. Le plancher s'importe AVEC sa mesure —
   celui-ci vaut pour des cartes à tuile, titre et trois lignes. */
.s-grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: var(--s-s4);
}

.s-grille--large { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }
.s-grille--menue { grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr)); }

.s-carte {
  display: flex;
  flex-direction: column;
  gap: var(--s-s3);
  padding: var(--s-s5);
  background: var(--s-carte);
  border-radius: var(--s-r-carte);
  box-shadow: var(--s-ombre);
  transition: transform 0.35s var(--s-courbe), box-shadow 0.35s var(--s-courbe);
}

.s-carte:hover { transform: translateY(-4px); box-shadow: var(--s-ombre-haute); }

.s-carte__titre { font-size: var(--s-fs-l); }
.s-carte__texte { color: var(--s-doux); font-size: var(--s-fs-s); }

.s-carte__img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--s-r-photo);
}

/* Une série se lit en travers : primaire, secondaire, accent, puis on
   recommence. Seules les cartes d'une GRILLE se colorent — une carte
   seule reste un objet clair. Une grille qui porte un logo reste
   claire aussi : les logos d'association et de partenaire arrivent
   presque toujours sur fond blanc, et un rectangle blanc sur un
   pastel se voit plus que le logo. */
.s-grille:not(:has(.s-logo-asso, .s-logo-partenaire)) > .s-carte {
  --s-doux: var(--s-texte-teinte);
  background: var(--s-teinte-1);
}

.s-grille:not(:has(.s-logo-asso, .s-logo-partenaire)) > .s-carte:nth-child(3n + 2) { background: var(--s-teinte-2); }
.s-grille:not(:has(.s-logo-asso, .s-logo-partenaire)) > .s-carte:nth-child(3n)     { background: var(--s-teinte-3); }

/* Sur la teinte, la tuile d'icône devient une pastille claire — deux
   dilutions de la même couleur l'une sur l'autre ne se distinguaient
   plus. Et le lien passe à l'encre, souligné (voir le calcul plus
   haut). Le lien de document garde son fond clair : il tient seul. */
.s-grille > .s-carte .s-tuile { background: var(--s-carte); }
.s-grille > .s-carte a:not(.s-doc-lien) { color: var(--ecole-texte); }

/* Chiffre clé : la valeur en serif, le libellé en petit. Aucune
   pastille de couleur derrière — le texte posé sur un aplat piloté
   par l'école est la faute que Marelle porte encore en point
   ouvert. */
.s-chiffre { text-align: center; }

.s-chiffre__valeur {
  display: block;
  font-family: var(--s-titre);
  font-size: var(--s-fs-xl);
  line-height: 1;
  color: var(--ecole-primaire);
}

.s-chiffre__libelle {
  display: block;
  margin-top: var(--s-s2);
  font-size: var(--s-fs-s);
  color: var(--s-doux);
}

/* Jalon de chronologie : l'année en serif, l'événement dessous. Le
   filet à gauche remplace la carte — une frise n'a pas besoin d'un
   contenant, elle a besoin d'un rythme. */
.s-jalon {
  padding-left: var(--s-s4);
  border-left: 2px solid var(--s-filet-fort);
}

/* L'IMAGE D'ARCHIVE EST UNE BANDE, PAS UN PAVÉ. En `s-carte__img`
   (4/3, pleine largeur du panneau large), elle se rendait à environ
   1400 × 1050 px et écrasait la chronologie qu'elle introduit —
   défaut relevé par Emilien le 26 août 2026. Un panoramique borné
   garde le document visible sans qu'il devienne la section. La marge
   est portée ici : les enfants directs d'un panneau n'ont aucun
   rythme vertical propre. */
.s-histoire__img {
  width: 100%;
  aspect-ratio: 21 / 9;
  max-height: 380px;
  object-fit: cover;
  border-radius: var(--s-r-photo);
  margin-block: var(--s-s5) var(--s-s2);
}

.s-jalon__annee {
  display: block;
  font-family: var(--s-titre);
  font-size: var(--s-fs-l);
  line-height: 1;
  color: var(--s-primaire-lisible);
  margin-bottom: var(--s-s2);
}

.s-logo-asso,
.s-logo-partenaire {
  max-height: 72px;
  width: auto;
  object-fit: contain;
}

/* ============================================================
   CHARIOT — une série se lit en travers
   ============================================================ */

.s-chariot {
  display: flex;
  gap: var(--s-s4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Le cran haut est celui d'une section, pas un tassement. `.s-tete`
     ne porte AUCUNE marge basse : elle laisse à ce qui suit le soin de
     s'écarter, et les 8 px d'origine collaient la première vue sous la
     deuxième ligne du titre. Constaté sur « La procédure, étape par
     étape », dont le titre passe à deux lignes. */
  padding-block: var(--s-s5) var(--s-s5);
  scrollbar-width: thin;
  scrollbar-color: var(--s-filet-fort) transparent;
}

/* La barre native est le repère de SECOURS : elle ne sert plus que
   sans JavaScript, et `soleil.js` ne la masque qu'en révélant le rail.
   La masquer ici aurait laissé le chariot sans aucun indice là où le
   script ne tourne pas — il défile toujours au doigt et à la molette,
   mais plus rien ne le dirait. */
.s-chariot::-webkit-scrollbar { height: 6px; }
.s-chariot::-webkit-scrollbar-thumb {
  background: var(--s-filet-fort);
  border-radius: var(--s-r-pilule);
}

.s-chariot.est-raille {
  scrollbar-width: none;
  padding-bottom: var(--s-s3);
}

.s-chariot.est-raille::-webkit-scrollbar { display: none; }

/* TOUTES LES VUES ONT LA MÊME LARGEUR ET LE MÊME RATIO. Une sur trois
   était large, avec un ratio 16/9 quand les autres étaient en 4/3 :
   sur des photos d'école, jamais cadrées, ça ne produisait pas un
   rythme mais trois hauteurs d'image sur une même ligne. *Un rythme se
   voit quand tout le reste est constant.*

   Le 4/3 plutôt que le 16/9 : c'est le format d'un téléphone tenu à
   l'horizontale, donc celui de la plupart des photos qu'une école
   téléverse. Un 16/9 les recadrerait en coupant des têtes. */
.s-chariot__vue {
  flex: 0 0 min(400px, 80%);
  margin: 0;
  scroll-snap-align: start;
}

.s-chariot__img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--s-r-carte);
  box-shadow: var(--s-ombre);
}

/* Le chariot sort de la marge intérieure du panneau et la reprend en
   remplissage : la vue suivante est alors coupée par le BORD du
   panneau, pas par son blanc tournant. C'est ce dépassement qui dit
   qu'il y a une suite — sans lui, la série a l'air de s'arrêter. */
.s-panneau > .s-chariot {
  margin-inline: calc(var(--s-s5) * -1);
  padding-inline: var(--s-s5);
  scroll-padding-inline: var(--s-s5);
}

.s-chariot__legende {
  margin-top: var(--s-s2);
  font-size: var(--s-fs-xs);
  color: var(--s-doux);
}

/* ---------- La scène : le chariot de l'accueil, lu au centre ----------
   Variante demandée par Emilien le 26 août 2026 : la vue au centre est
   grande, ses voisines petites, et le passage de l'une à l'autre est un
   grossissement continu. Le grossissement est piloté par la POSITION
   dans le défilement (`animation-timeline: view()`), pas par un état :
   il n'y a donc ni classe « active » à poser, ni script à écrire, et le
   geste au doigt produit exactement la même animation que les flèches.

   Trois étages de dégradation, tous silencieux : sans prise en charge
   de `view()`, toutes les vues restent à taille pleine — le chariot
   ordinaire ; sous préférence de mouvement réduit, idem ; sans
   JavaScript, les flèches manquent mais le défilement reste. */

.s-chariot--scene .s-chariot__vue {
  flex-basis: min(520px, 86%);
  scroll-snap-align: center;
}

/* Les bouts de série doivent pouvoir ATTEINDRE le centre : sans ce
   dégagement, la première vue reste collée au bord gauche et ne
   grossit jamais. En dessous de ~700 px le dégagement retombe sur la
   marge ordinaire du panneau — un téléphone ne centre pas sa première
   vue, comme tout carrousel. */
/* Double classe à dessein : la règle de palier `.s-panneau > .s-chariot`
   à 768 px arrive plus bas dans la feuille et repasserait le
   dégagement à s7 — à égalité de spécificité, c'est l'ordre qui
   tranche. */
.s-panneau > .s-chariot.s-chariot--scene {
  padding-inline: max(var(--s-s5), calc(50% - 270px));
  scroll-padding-inline: 0;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .s-chariot--scene .s-chariot__vue {
      transform-origin: center bottom;
      animation: s-scene-grossit linear both;
      animation-timeline: view(inline);
    }
  }
}

/* 50 % du trajet = le centre du cadre. Les paliers intermédiaires
   creusent la pente : une vue à mi-chemin est déjà nettement plus
   petite que la centrale, ce qui fait lire « une grande, des
   petites » même à l'arrêt. */
@keyframes s-scene-grossit {
  0%, 100% { transform: scale(0.7); opacity: 0.55; }
  32%, 68% { transform: scale(0.78); opacity: 0.7; }
  50%      { transform: scale(1); opacity: 1; }
}

/* LE RAIL — 120 px, pas la largeur de la série.

   Il remplace la barre native, qui traversait tout le panneau et
   gardait sous Windows ses deux boutons pas-à-pas : une bande d'un
   bord à l'autre avec deux flèches minuscules aux extrémités, posée à
   quarante pixels des cartes qu'elle commandait.

   Sa largeur est FIXE et son pouce PROPORTIONNEL : c'est le pouce qui
   dit quelle part de la série tient à l'écran, pas le rail. Un rail
   proportionnel aurait fait varier sa longueur d'une section à l'autre
   sans que rien ne l'explique.

   `overflow: hidden` sur la piste : le pouce est déplacé en pourcentage
   de SA propre largeur, ce qui le laisse dépasser d'un ou deux pixels
   au bout de la course selon l'arrondi. */
.s-rail {
  width: 120px;
  height: 4px;
  margin-top: var(--s-s3);
  border-radius: var(--s-r-pilule);
  background: color-mix(in oklab, var(--ecole-primaire) 14%, transparent);
  overflow: hidden;
}

.s-rail__pouce {
  height: 100%;
  width: 100%;
  border-radius: inherit;
  background: var(--s-filet-fort);
  transition: transform 0.18s var(--s-courbe), width 0.18s var(--s-courbe);
}

@media (prefers-reduced-motion: reduce) {
  .s-rail__pouce { transition: none; }
}

.s-fleches {
  display: flex;
  gap: var(--s-s2);
  flex: 0 0 auto;
}

.s-fleche {
  width: 48px; height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1.5px solid var(--s-filet);
  background: var(--s-carte);
  color: var(--ecole-texte);
  font-size: var(--s-fs-m);
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s, transform 0.2s var(--s-courbe);
}

.s-fleche--suiv {
  background: var(--ecole-texte);
  color: var(--ecole-fond);
  border-color: var(--ecole-texte);
}

.s-fleche:hover { transform: translateY(-2px); }
.s-fleche[disabled] { opacity: 0.35; cursor: default; transform: none; }

/* En-tête de section à deux pistes : le titre à gauche, la commande
   à droite. C'est le seul endroit du thème où une commande partage
   la ligne d'un titre. */
.s-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-s4);
}

.s-tete__texte { max-width: 52ch; }
.s-tete__texte > * + * { margin-top: var(--s-s3); }
.s-tete__intro { color: var(--s-doux); }

/* ============================================================
   ACCORDÉON
   ============================================================ */

.s-accordeon {
  display: flex;
  flex-direction: column;
  gap: var(--s-s2);
}

.s-pli {
  background: var(--s-carte);
  border-radius: var(--s-r-tuile);
  box-shadow: var(--s-ombre-basse);
  overflow: hidden;
}

.s-pli__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-s3);
  padding: var(--s-s4) var(--s-s5);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.s-pli__q::-webkit-details-marker { display: none; }

.s-pli__signe {
  position: relative;
  width: 16px; height: 16px;
  flex: 0 0 auto;
}

.s-pli__signe::before,
.s-pli__signe::after {
  content: '';
  position: absolute;
  inset: 50% 0 auto 0;
  height: 2px;
  border-radius: 2px;
  background: var(--ecole-primaire);
  transform: translateY(-50%);
  transition: transform 0.25s var(--s-courbe), opacity 0.2s;
}

.s-pli__signe::after { transform: translateY(-50%) rotate(90deg); }
.s-pli[open] .s-pli__signe::after { transform: translateY(-50%) rotate(0); opacity: 0; }

.s-pli__r {
  padding: 0 var(--s-s5) var(--s-s5);
  color: var(--s-doux);
}

/* ============================================================
   PROJETS
   ============================================================ */

/* UN PROJET PAR RANGÉE, le premier paragraphe à découvert. Les projets
   arrivent le plus souvent SANS PDF, tout le texte dans le champ : 400 à
   600 mots chacun chez Pélissanne, listes comprises. En grille, trois
   colonnes de 364 px faisaient des lignes de trente-cinq signes sur près
   de 1 800 px de haut, le défaut que Pétale a soldé en 1.9.0 sur ce même
   texte. D'où la colonne étroite de l'école inclusive, et la suite
   repliée derrière un `<details>` natif : replié, le texte reste dans la
   page, indexé et trouvable par la recherche du navigateur, et rien ne
   dépend d'un script. */
.s-projets {
  display: grid;
  gap: var(--s-s4);
}

/* Une carte de lecture ne bouge pas sous le pointeur : le soulèvement
   des cartes de grille déplacerait ici le texte qu'on est en train de
   lire. Déclarée après `.s-carte:hover`, à spécificité égale. */
.s-projet:hover { transform: none; box-shadow: var(--s-ombre); }

/* 44 px : la cible au doigt. Pétale l'a mesurée à 41 px avant de la
   corriger. */
.s-projet__declic {
  display: inline-flex;
  align-items: center;
  gap: var(--s-s2);
  min-height: 44px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.s-projet__declic::-webkit-details-marker { display: none; }

.s-projet__suite[open] .s-projet__ouvrir,
.s-projet__suite:not([open]) .s-projet__fermer { display: none; }

.s-projet__suite[open] .s-pli__signe::after { transform: translateY(-50%) rotate(0); opacity: 0; }

.s-projet__suite > .s-texte { margin-top: var(--s-s3); }

/* ============================================================
   NOTE, LISTES, TABLEAUX, DOCUMENTS
   ============================================================ */

.s-note { display: inline-flex; gap: 3px; }

.s-note__plein,
.s-note__vide {
  width: 9px; height: 9px;
  border-radius: 50%;
  display: inline-block;
}

.s-note__plein { background: var(--ecole-primaire); }
.s-note__vide  { background: var(--s-filet); }

.s-texte > :first-child { margin-top: 0; }
.s-texte > :last-child { margin-bottom: 0; }
.s-texte { max-width: var(--s-lisible); }
.s-texte ul, .s-texte ol { padding-left: var(--s-s4); }

/* UN TITRE DANS UN TEXTE N'EST PAS UN TITRE DE SECTION. `h1` à `h4`
   portent `margin: 0` et l'échelle des sections (52 px pour `h2`) : les
   mentions légales se lisaient comme une pile de titres géants collés à
   leur paragraphe, et les projets de Pélissanne aussi (29 septembre
   2026). Les valeurs sont celles que le corps des actualités portait
   seul ; elles valent pour tout texte riche, et le corps d'une
   actualité en est un (`.s-texte .s-article__corps`). Le premier titre
   garde `margin-top: 0` : `.s-texte > :first-child` pèse plus lourd. */
.s-texte h2 { margin: var(--s-s6) 0 var(--s-s2); font-size: var(--s-fs-l); }
.s-texte h3 { margin: var(--s-s5) 0 var(--s-s2); font-size: var(--s-fs-m); font-family: var(--s-texte); font-weight: 600; }
.s-texte h4 { margin: var(--s-s4) 0 var(--s-s2); }
.s-texte li + li { margin-top: var(--s-s2); }

/* LA DEVISE ET LE THÈME D'ANNÉE.

   La devise garde la colonne étroite, centrée, sans rien qui la porte.
   Le thème d'année, lui, est une RANGÉE : texte à gauche, illustration
   à droite et bornée à 320 px. Empilés dans la même colonne étroite,
   les deux faisaient 1304 px de haut pour deux idées.

   `align-items: center` et non `start` : l'illustration est un objet
   isolé, pas une légende du texte — alignée en haut elle laissait un
   vide sous elle dès que le texte descendait. */
.s-devise {
  max-width: var(--s-largeur-etroite);
  margin: 0 auto;
  text-align: center;
}

.s-annee {
  display: grid;
  gap: var(--s-s5);
  align-items: center;
}

.s-annee__texte > * + * { margin-top: var(--s-s3); }

.s-annee__img {
  width: 100%;
  border-radius: var(--s-r-carte);
}

@media (min-width: 768px) {
  .s-annee {
    grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
    gap: var(--s-s6);
  }
}

.s-texte--centre { margin-inline: auto; text-align: center; }

.s-liste-nue { list-style: none; margin: 0; padding: 0; }

.s-tableau {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--s-fs-s);
}

.s-tableau th,
.s-tableau td {
  padding: var(--s-s3) var(--s-s3);
  text-align: left;
  border-bottom: 1px solid var(--s-filet);
  vertical-align: top;
}

.s-tableau th {
  font-weight: 600;
  color: var(--ecole-texte);
}

.s-tableau tr:last-child td { border-bottom: 0; }

/* Un tableau ne rétrécit pas indéfiniment : il défile dans sa propre
   boîte plutôt que de déborder la page. */
.s-defile-x {
  overflow-x: auto;
  scrollbar-width: thin;
}

/* ---------- Les menus de cantine, semaine par semaine ----------
   Cinq au plus, une par onglet (DECISIONS.md, 12 septembre 2026).
   L'onglet reprend le BOUTON du thème, en pilule : contour sur la carte
   au repos, primaire lisible quand sa semaine est ouverte, et le seul
   soulèvement du système au survol, avec sa pénombre teintée.

   SANS JAVASCRIPT, la rangée reste cachée et les semaines s'empilent
   sous leur titre. `soleil-js` est posée sur `<html>` en tête de page,
   AVANT le premier rendu : posée par le script différé, elle
   replierait sous les yeux du visiteur des semaines déjà peintes. */

.s-menus { margin-top: var(--s-s6); }

.s-menus__onglets { display: none; }

.soleil-js .s-menus__onglets {
  display: flex;
  gap: var(--s-s2);
  overflow-x: auto;
  scrollbar-width: thin;
  /* Le contour de focus sort de 6 px, et le survol soulève de 2 px avec
     sa pénombre : une boîte qui défile les rognerait. Le rembourrage
     leur laisse la place, la marge négative rend l'alignement. */
  margin: var(--s-s4) calc(var(--s-s3) * -1) 0;
  padding: var(--s-s2) var(--s-s3) var(--s-s3);
}

.s-menus__onglet {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: var(--s-s2) var(--s-s4);
  border: 1.5px solid var(--s-filet);
  border-radius: var(--s-r-pilule);
  background: var(--s-carte);
  color: var(--ecole-texte);
  font-family: var(--s-texte);
  font-size: var(--s-fs-s);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 0.2s var(--s-courbe), box-shadow 0.2s var(--s-courbe), background-color 0.2s var(--s-courbe);
}

.s-menus__onglet:hover { transform: translateY(-2px); box-shadow: var(--s-ombre-basse); }
.s-menus__onglet:active { transform: translateY(0); }

.s-menus__onglet[aria-selected='true'] {
  border-color: transparent;
  background: var(--s-primaire-lisible);
  color: var(--s-sur-primaire);
}

.s-menus__titre {
  margin: var(--s-s4) 0 var(--s-s3);
  font-weight: 600;
}

.s-menus__semaine + .s-menus__semaine { margin-top: var(--s-s5); }

.soleil-js .s-menus--onglets .s-menus__semaine { margin-top: var(--s-s3); }

.soleil-js .s-menus--onglets .s-menus__titre,
.soleil-js .s-menus--onglets .s-menus__semaine:not(.est-ouverte) { display: none; }

/* Un jour, une carte : depuis le 13 septembre 2026, un jour est un texte,
   un plat par ligne (DECISIONS.md). Le tableau à cinq colonnes défilait
   de côté sur téléphone (542 px dans 287, mesuré à 375) ; les cartes
   replient d'elles-mêmes. Posées DANS le panneau, elles prennent le
   contour des onglets plutôt qu'une seconde pénombre. */
.s-menus__jours {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
  gap: var(--s-s3);
}

.s-menus__jour {
  padding: var(--s-s4);
  border: 1.5px solid var(--s-filet);
  border-radius: var(--s-r-carte);
}

.s-menus__nom {
  margin: 0 0 var(--s-s2);
  font-weight: 600;
}

.s-menus__plats {
  display: grid;
  gap: var(--s-s2);
  font-size: var(--s-fs-s);
  color: var(--s-doux);
}

.s-doc-lien,
a.doc-lien {
  display: inline-flex;
  align-items: center;
  gap: var(--s-s2);
  padding: var(--s-s2) var(--s-s4);
  border: 1.5px solid var(--s-filet);
  border-radius: var(--s-r-pilule);
  font-size: var(--s-fs-s);
  font-weight: 500;
  color: var(--ecole-texte);
  text-decoration: none;
  background: var(--s-carte);
}

.s-doc-lien:hover,
a.doc-lien:hover {
  border-color: var(--s-filet-fort);
  color: var(--s-primaire-lisible);
}

.s-plan {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-s4);
  width: 100%;
  min-width: 0;
  height: 24rem;
  padding: var(--s-s4);
  text-align: center;
  background: var(--s-carte);
  border-radius: var(--s-r-carte);
  box-shadow: var(--s-ombre);
  overflow: hidden;
}
.s-plan .yk-carte__texte { max-width: 40ch; margin: 0; }
.s-plan .yk-carte__picto { display: flex; }
.s-plan .yk-carte__picto svg { width: 2rem; height: 2rem; }
.s-plan.est-chargee { padding: 0; }
.s-plan iframe {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: var(--s-r-photo);
  display: block;
}

/* ============================================================
   « NOS SPÉCIFICITÉS » — L'ESCALIER, ET LE RENVOI QUI Y MÈNE
   ============================================================ */

/* L'ESCALIER, TENU À DOUZE. Une rangée image et texte par entrée
   ILLUSTRÉE, le côté alternant d'une rangée à l'autre ; les entrées sans
   image se posent en cartes, par suite ininterrompue, à leur place dans
   la série. En rangée, une entrée sans image laissait sa moitié vide : un
   élément seul se place dans la première case d'une grille, quel que soit
   son `order` — neuf rangées sur douze sur la démonstration du
   13 septembre 2026, et l'escalier ne descendait plus qu'un côté.

   L'alternance passe du style en ligne à une classe, et à 768 px
   seulement : empilée sur téléphone, une rangée sur deux montrait sa
   photo avant son titre. */
.s-escalier__rangee,
.s-escalier__cartes { margin-top: var(--s-s7); }

/* LE RENVOI, sur l'accueil et sur Notre école (DECISIONS.md, 13 septembre
   2026). Un objet posé sur le sol, comme le reste : le panneau et sa
   pénombre, l'en-tête à deux pistes du thème — le titre à gauche, la
   commande à droite, ici le lien qui NOMME la page. Dessous, quatre
   intitulés au plus, chacun avec sa tuile ; jamais leurs textes, que la
   page détaille. Aucune ancre : ce n'est pas une section de la page, c'est
   une porte vers une autre. */
.s-renvoi { padding: var(--s-s6) var(--s-s5); }

.s-renvoi__liste {
  list-style: none;
  margin: var(--s-s5) 0 0;
  padding: 0;
  display: grid;
  gap: var(--s-s3) var(--s-s5);
}

.s-renvoi__entree {
  display: flex;
  align-items: center;
  gap: var(--s-s3);
}

.s-renvoi__titre {
  font-family: var(--s-titre);
  font-size: var(--s-fs-l);
  line-height: 1.15;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

/* ============================================================
   FORMULAIRES — Contact Form 7, par SES classes
   ============================================================ */

/* Le gabarit est une donnée du site : le plugin pose le sien, chaque site
   existant garde le sien (DECISIONS.md, 13 septembre 2026). Cette section
   ne connaît donc que ce que Contact Form 7 écrit lui-même : `.wpcf7-form`,
   le `label`, `.wpcf7-form-control`, le bouton, la bulle d'erreur et le
   message de retour. Seule exception, `.yk-duo`, que le plugin pose pour
   réunir les deux champs courts (560 px, voir les paliers) ; sans elle, un
   champ par ligne.

   Viser les classes de CF7 règle aussi le piège de la règle de conteneur :
   `input[type='submit']` repeignait tout bouton de la zone, d'où un `:not`
   à entretenir ; `.wpcf7-submit` ne désigne que le bouton d'envoi.

   Chaque ligne paie la même marge : le dernier paragraphe d'un groupe
   perdait la sienne, et deux champs se seraient touchés. */
.s-formulaire .wpcf7-form p { margin: 0 0 var(--s-s3); }

.s-formulaire .wpcf7-form label {
  display: block;
  font-size: var(--s-fs-s);
  font-weight: 500;
}

/* CF7 place un saut de ligne entre le libellé et son champ ; le champ porte
   sa propre marge. */
.s-formulaire .wpcf7-form label br { display: none; }

.s-formulaire input.wpcf7-form-control:not(.wpcf7-submit),
.s-formulaire textarea.wpcf7-form-control,
.s-formulaire select.wpcf7-form-control {
  display: block;
  width: 100%;
  min-height: 48px;
  margin-top: var(--s-s1);
  padding: var(--s-s2) var(--s-s3);
  border: 1.5px solid var(--s-filet);
  border-radius: var(--s-r-tuile);
  background: var(--s-carte);
  color: var(--ecole-texte);
  font-family: inherit;
  font-size: var(--s-fs-s);
  font-weight: 400;
}

.s-formulaire textarea.wpcf7-form-control { min-height: 150px; resize: vertical; }

/* Un champ refusé prend le filet de primaire ; la bulle d'erreur dit
   pourquoi. */
.s-formulaire input.wpcf7-form-control[aria-invalid='true'],
.s-formulaire textarea.wpcf7-form-control[aria-invalid='true'],
.s-formulaire select.wpcf7-form-control[aria-invalid='true'] { border-color: var(--ecole-primaire); }

/* Le bouton d'envoi reprend `.s-bouton--plein` sans pouvoir en porter la
   classe : c'est Contact Form 7 qui écrit l'`<input type="submit">`. */
.s-formulaire .wpcf7-submit {
  min-height: 44px;
  padding: var(--s-s2) var(--s-s5);
  border: 0;
  border-radius: var(--s-r-pilule);
  background: var(--s-primaire-lisible);
  color: var(--s-sur-primaire);
  font-family: inherit;
  font-size: var(--s-fs-s);
  font-weight: 600;
  vertical-align: middle;
  cursor: pointer;
  transition: transform 0.2s var(--s-courbe), box-shadow 0.2s var(--s-courbe);
}

.s-formulaire .wpcf7-submit:hover { transform: translateY(-2px); box-shadow: var(--s-ombre-basse); }
.s-formulaire .wpcf7-spinner { vertical-align: middle; }

/* La bulle d'erreur : du texte, et le point de primaire des notes pour la
   repérer. */
.s-formulaire .wpcf7-not-valid-tip {
  display: flex;
  align-items: center;
  gap: var(--s-s2);
  margin-top: var(--s-s1);
  font-size: var(--s-fs-xs);
  font-weight: 600;
  color: var(--ecole-texte);
}

.s-formulaire .wpcf7-not-valid-tip::before {
  content: '';
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--ecole-primaire);
}

/* Le message de retour. La feuille de CF7 (6.1.7), chargée avant celle-ci,
   pèse une balise de plus : `.wpcf7 form .wpcf7-response-output` vaut
   (0,2,1), ses états (0,3,1), et le message y prend un filet bleu, vert ou
   jaune. D'où `.wpcf7-form` dans le sélecteur ; le `display` reste à CF7,
   qui cache le message tant que rien n'est parti. */
.s-formulaire .wpcf7-form .wpcf7-response-output {
  margin: var(--s-s4) 0 0;
  padding: var(--s-s3) var(--s-s4);
  border: 1.5px solid var(--s-filet-fort);
  border-radius: var(--s-r-tuile);
  background: var(--s-carte);
  color: var(--ecole-texte);
  font-size: var(--s-fs-s);
}

.s-formulaire .wpcf7-form.sent .wpcf7-response-output { border-color: var(--s-filet-fort); }

.s-formulaire .wpcf7-form.invalid .wpcf7-response-output,
.s-formulaire .wpcf7-form.unaccepted .wpcf7-response-output,
.s-formulaire .wpcf7-form.payment-required .wpcf7-response-output,
.s-formulaire .wpcf7-form.failed .wpcf7-response-output,
.s-formulaire .wpcf7-form.aborted .wpcf7-response-output,
.s-formulaire .wpcf7-form.spam .wpcf7-response-output { border-color: var(--ecole-primaire); }

/* ============================================================
   BANDEAU D'ALERTE
   ============================================================ */

/* LE BANDEAU N'EST PLUS FIXÉ EN HAUT DE FENÊTRE. Il
   redevient un objet du flux, le premier de la page, dans la même
   famille que tout le reste : surface, rayon, ombre basse. Fixé en
   haut de fenêtre il ferait un second bandeau au-dessus de la pilule,
   et deux barres empilées sur un site d'école ne disent rien de plus
   qu'une seule. */
.s-alerte {
  width: var(--s-largeur);
  margin: 0 auto var(--s-s5);
  padding: var(--s-s3) var(--s-s5);
  border-radius: var(--s-r-tuile);
  background: var(--ecole-secondaire);
  color: var(--ecole-texte);
  font-size: var(--s-fs-s);
  font-weight: 500;
  box-shadow: var(--s-ombre-basse);
}

.s-alerte a { color: inherit; }

/* ============================================================
   BANNIÈRE DES PAGES INTERNES
   ============================================================ */

.s-banniere {
  /* Le voile : l'encre de l'école teintée de la primaire, comme les
     ombres. Viser l'ENCRE et poser le texte en couleur de FOND rend
     le couple symétrique : une école à fond sombre obtient un voile
     clair et un texte sombre. */
  --s-voile-sombre: color-mix(in oklab, var(--ecole-texte) 82%, var(--ecole-primaire));
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  min-height: clamp(300px, 38vw, 480px);
  margin-top: var(--s-s4);
  padding: var(--s-s6) var(--s-s5);
  border-radius: var(--s-r-panneau);
  background: var(--s-voile-sombre);
  box-shadow: var(--s-ombre-haute);
  color: var(--ecole-fond);
}

/* LE VOILE NE DESCEND JAMAIS SOUS 78 % LÀ OÙ IL Y A DU TEXTE. Calculé
   sur le pire cas, une photo toute blanche sous le texte : à 78 %, le
   titre et l'accroche en couleur de fond tiennent 6:1 ; à 65 %, 4,4 —
   sous le seuil. Aucune photo d'école n'est contrôlée à la saisie :
   c'est le voile qui garantit, pas l'image. Sous 1024 px, le texte
   occupe toute la largeur, le voile est donc uniforme. */
.s-banniere::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in oklab, var(--s-voile-sombre) 80%, transparent);
  pointer-events: none;
}

.s-banniere__img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.s-banniere__texte { max-width: 34rem; }
.s-banniere__texte > * + * { margin-top: var(--s-s4); }
.s-banniere h1 { color: var(--ecole-fond); }
.s-banniere__accroche { font-size: var(--s-fs-l); color: var(--ecole-fond); max-width: 48ch; }

/* Sans image, pas de hauteur imposée : un aplat sombre de 480 px pour
   un seul mot se lirait comme une image qui n'a pas chargé. */
.s-banniere--nue { min-height: 0; padding-block: var(--s-s7); }

/* Et un aplat uni de cette taille pèse : une lueur de primaire dans le
   coin opposé au texte lui rend la lumière que la photo aurait donnée.
   Là où la lueur est pleine, le texte en couleur de fond tient 6,9:1
   sur les couleurs par défaut — mais une primaire claire saisie par
   l'école l'éclaircit, et c'est pourquoi le texte n'y va pas : la
   lueur est dans le coin opposé, et seulement dès 1024 px : en
   dessous, le texte prend toute la largeur et passerait dessous. */
/* L'ACCUEIL : la même bannière, plus haute, le texte centré en hauteur.
   Placée APRÈS `--nue` : sans photo, l'accueil garde sa hauteur de héro. */
.s-banniere--accueil {
  min-height: clamp(460px, 48vw, 620px);
  align-items: center;
}

/* Le jeton quitte le coin de la photo pour celui de la bannière, en bas
   à droite, hors de la colonne de texte. Sous 768 px il reprend sa
   place dans le flux, après les boutons (règle de palier existante) —
   à la largeur de son contenu : sans borne, il devenait une barre. */
.s-banniere--accueil .s-jeton { left: auto; right: 5%; bottom: 10%; width: fit-content; }

/* LE MOT ACCENTUÉ NE PEUT PAS RESTER EN PRIMAIRE PLEINE SUR LE VOILE :
   le terracotta y tombe à 2,05:1 au pire cas (photo blanche sous un
   voile à 78 %). Même parade que les cartes : la teinte de l'école à
   clarté imposée, L 0,84, chroma au plus 0,12. Calculé sur neuf
   couleurs dont noir, marine et jaune vif : ≥ 3,77:1 au pire cas — le
   seuil du grand texte est 3:1, et ce mot n'existe qu'au titre. */
.s-banniere .s-accent { color: color-mix(in oklab, var(--ecole-primaire) 45%, var(--ecole-fond)); }

@supports (color: oklch(from red l c h)) {
  .s-banniere .s-accent { color: oklch(from var(--ecole-primaire) 0.84 min(c, 0.12) h); }
}

@media (min-width: 1024px) {
  .s-banniere.s-banniere--nue::before {
    background: radial-gradient(70% 140% at 100% 0%,
      color-mix(in oklab, var(--ecole-primaire) 45%, transparent),
      transparent 70%);
  }
}

/* ============================================================
   ÉQUIPE, ARTICLES, PIED
   ============================================================ */

.s-membre { text-align: center; }

.s-membre__photo {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--s-r-carte);
  margin-bottom: var(--s-s3);
}

.s-membre__nom { font-family: var(--s-titre); font-size: var(--s-fs-l); }
.s-membre__role { font-size: var(--s-fs-s); color: var(--s-doux); }

.s-article__meta {
  font-size: var(--s-fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--s-doux);
}

.s-article__titre { margin-top: var(--s-s2); }

/* ============================================================
   LE PIED — aéré, et rien de plus

   Le plan du site à sept colonnes a été retiré : le panneau du menu
   le porte déjà, en mieux, et un pied qui répète le menu ne fait
   qu'allonger la page. Ce qu'on cherche EN BAS d'un site d'école,
   c'est une adresse, un numéro et une adresse mail — pas une seconde
   navigation.

   Trois étages seulement, très espacés : la maison, le nécessaire,
   les mentions. Un seul filet dans tout le pied.
   ============================================================ */

.s-pied { padding-block: var(--s-s10) var(--s-s6); }

.s-pied__haut {
  display: grid;
  gap: var(--s-s7);
  align-items: start;
}

.s-pied__mot > * + * { margin-top: var(--s-s4); }

.s-pied__phrase {
  max-width: 30ch;
  font-family: var(--s-titre);
  font-size: var(--s-fs-l);
  line-height: 1.25;
  color: var(--ecole-texte);
}

.s-pied__bloc { font-size: var(--s-fs-s); line-height: 1.75; color: var(--s-doux); }
.s-pied__bloc h2 {
  margin-bottom: var(--s-s2);
  font-family: var(--s-texte);
  font-size: var(--s-fs-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--s-doux);
}

.s-pied__bloc p { margin: 0 0 var(--s-s3); }
.s-pied__bloc p:last-child { margin-bottom: 0; }
.s-pied__bloc a { color: var(--ecole-texte); text-decoration: none; }
.s-pied__bloc a:hover { color: var(--s-primaire-lisible); text-decoration: underline; }

.s-pied__liens {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-s2) var(--s-s5);
  margin-top: var(--s-s8);
  font-size: var(--s-fs-s);
}

.s-pied__liens a {
  color: var(--ecole-texte);
  text-decoration: none;
  padding-block: var(--s-s1);
}

.s-pied__liens a:hover { color: var(--s-primaire-lisible); text-decoration: underline; }

.s-partenaires {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-s6);
  margin-top: var(--s-s7);
}

.s-logo-asso,
.s-logo-partenaire { max-height: 56px; width: auto; object-fit: contain; }

/* L'AFFILIATION : le logo secondaire posé à côté du nom de la direction
   diocésaine, comme le font Pétale et Étoile, dans UN seul lien. Le logo
   est décoratif (`alt` vide), le nom porte le lien et son soulignement :
   posé sur le lien lui-même, le trait passerait aussi sous l'image. */
.s-affiliation {
  display: inline-flex;
  align-items: center;
  gap: var(--s-s3);
  text-decoration: none;
}

.s-affiliation .s-membre__role { text-decoration: underline; }
.s-affiliation:hover .s-membre__role { text-decoration-thickness: 2px; }

.s-pied__bas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-s3);
  margin-top: var(--s-s7);
  padding-top: var(--s-s5);
  border-top: 1px solid var(--s-filet);
  font-size: var(--s-fs-xs);
  color: var(--s-doux);
}

.s-pied__bas p { margin: 0; }
.s-pied__bas a { color: var(--s-doux); text-decoration: none; }
.s-pied__bas a:hover { color: var(--s-primaire-lisible); }
.s-pied__legaux { display: flex; flex-wrap: wrap; gap: var(--s-s4); }


/* ============================================================
   PAGINATION, 404
   ============================================================ */

.s-pagination {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-s2);
  margin-top: var(--s-s6);
}

.s-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px; min-height: 44px;
  padding: 0 var(--s-s3);
  border-radius: var(--s-r-pilule);
  border: 1.5px solid var(--s-filet);
  background: var(--s-carte);
  color: var(--ecole-texte);
  text-decoration: none;
  font-size: var(--s-fs-s);
}

.s-pagination .page-numbers.current {
  background: var(--s-primaire-lisible);
  border-color: var(--s-primaire-lisible);
  color: var(--s-sur-primaire);
}

.s-vide {
  text-align: center;
  padding-block: var(--s-s8);
  color: var(--s-doux);
}


/* ============================================================
   PICTOGRAMMES
   Deux familles, deux réglages. Les tracés d'interface viennent de
   Tabler (MIT), les marques de réseaux de Simple Icons (CC0) : rien
   n'est dessiné à la main ici, et rien n'est chargé depuis un CDN.
   ============================================================ */

.s-icone {
  width: 1.15em;
  height: 1.15em;
  flex: 0 0 auto;
  display: block;
}

.s-fleche .s-icone { width: 20px; height: 20px; }

/* Le lien de document reçoit sa flèche par MASQUE, pas par balise :
   `ecole_document_lien()` est un helper du plugin et rend un `<a>`
   fermé — le thème ne peut rien glisser dedans. Un masque prend la
   couleur du texte, donc il suit l'état de survol sans règle en plus. */
.s-doc-lien::before,
a.doc-lien::before {
  content: '';
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask: var(--s-glyphe-doc) center / contain no-repeat;
  mask: var(--s-glyphe-doc) center / contain no-repeat;
}

/* ============================================================
   RÉSEAUX SOCIAUX
   Des marques, pas des mots. Le nom reste dans le document pour les
   lecteurs d'écran — un logo sans nom accessible est un lien muet.
   ============================================================ */

.s-reseaux {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-s2);
  margin: 0;
}

.s-reseau {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid var(--s-filet);
  color: var(--ecole-texte);
  transition: background-color 0.25s var(--s-courbe), color 0.25s var(--s-courbe), border-color 0.25s;
}

.s-reseau .s-icone { width: 19px; height: 19px; }

/* `.s-reseaux` en tête de sélecteur : dans le pied, `.s-pied__bloc
   a:hover` (0,2,1) battait `.s-reseau:hover` (0,2,0) et repeignait le
   pictogramme en primaire lisible — la couleur de son propre fond. Le
   rond se remplissait, la marque disparaissait. */
.s-reseaux .s-reseau:hover,
.s-reseaux .s-reseau:focus-visible {
  background: var(--s-primaire-lisible);
  border-color: var(--s-primaire-lisible);
  color: var(--s-sur-primaire);
}

/* Les deux mêmes ronds dans la pilule, aux couleurs du bouton qu'ils
   remplacent — `.s-bouton--soleil` : aplat secondaire, encre de l'école
   dessus, jamais du blanc (le secondaire est clair par vocation ici).
   Le survol reste celui du pied, il n'y a pas deux grammaires.

   44 px et non 42 : c'est la hauteur du déclic posé juste à gauche, et
   deux pixels d'écart sur deux objets côte à côte se voient sans qu'on
   sache dire pourquoi. */
.s-entete__reseaux { gap: var(--s-s1); }

.s-entete__reseau {
  width: 44px;
  height: 44px;
  background: var(--ecole-secondaire);
  border-color: var(--ecole-secondaire);
  color: var(--ecole-texte);
}

/* ============================================================
   LE MOT DU CHEF D'ÉTABLISSEMENT
   ============================================================ */

/* LE PORTRAIT EST BORNÉ. En deux pistes égales il occupait 557 × 669
   px : une photo d'identité agrandie six fois, qui écrasait le texte
   qu'elle est censée accompagner. Une piste bornée à 300 px lui rend
   sa fonction — on regarde qui parle, on lit ce qui est dit. */
.s-mot { align-items: start; }

.s-mot .s-medaillon__img {
  aspect-ratio: 1;
  border-radius: var(--s-r-carte);
}

.s-mot__signature {
  display: flex;
  align-items: flex-end;
  gap: var(--s-s4);
  flex-wrap: wrap;
  margin-top: var(--s-s5);
  padding-top: var(--s-s4);
  border-top: 1px solid var(--s-filet);
}

.s-mot__signature img { max-height: 52px; width: auto; }
.s-mot__signature p { margin: 0; font-size: var(--s-fs-s); line-height: 1.4; color: var(--s-doux); }

/* ============================================================
   ÉQUIPE
   ============================================================ */

/* LA FICHE EST BORNÉE, ET C'EST UN CORRECTIF, PAS UN RÉGLAGE.
   `repeat(auto-fit, …)` réduit à ZÉRO les pistes vides : une catégorie
   à un seul membre — « Direction », le cas le plus courant — laissait
   donc ce membre occuper toute la grille, avec une photo carrée de
   1180 × 1180 px. Mesuré, pas supposé.

   La borne agit quel que soit le nombre de membres, là où changer
   `auto-fit` en `auto-fill` déséquilibrerait les autres grilles qui
   partagent la même classe. */
.s-membre {
  max-width: 240px;
  text-align: left;
}

.s-membre__photo { border-radius: var(--s-r-carte); }

/* ============================================================
   ACTUALITÉS — une à la une, les suivantes en lignes
   Trois cartes identiques côte à côte, c'est le rendu par défaut de
   tous les gabarits du monde, et l'œil n'y accroche nulle part. La
   première actualité a de la place et une image ; les suivantes sont
   des lignes de journal, avec une vignette et rien de plus.
   ============================================================ */

.s-une {
  display: grid;
  gap: var(--s-s6);
  align-items: center;
}

.s-une__media { display: block; }

.s-une__media img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--s-r-panneau);
  box-shadow: var(--s-ombre);
}

.s-une__texte > * + * { margin-top: var(--s-s3); }

.s-une__titre {
  font-family: var(--s-titre);
  font-size: var(--s-fs-xl);
  line-height: 1.08;
  letter-spacing: -0.015em;
}

.s-une__titre a { color: inherit; text-decoration: none; }
.s-une__titre a:hover { text-decoration: underline; text-underline-offset: 0.14em; }

.s-brefs { margin-top: var(--s-s7); }

.s-bref {
  display: grid;
  grid-template-columns: 84px 1fr;
  gap: var(--s-s4);
  align-items: center;
  padding-block: var(--s-s4);
  border-top: 1px solid var(--s-filet);
}

.s-bref:last-child { border-bottom: 1px solid var(--s-filet); }

.s-bref__vignette {
  width: 84px;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--s-r-tuile);
}

.s-bref__titre {
  margin-top: var(--s-s1);
  font-family: var(--s-titre);
  font-size: var(--s-fs-l);
  line-height: 1.14;
}

.s-bref__titre a { color: inherit; text-decoration: none; }
.s-bref__titre a:hover { text-decoration: underline; text-underline-offset: 0.14em; }

.s-date {
  font-size: var(--s-fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--s-doux);
}

/* Le lien de lecture : une flèche qui avance au survol. Le mouvement
   est dans une transformée, donc il ne relayoute rien. */
.s-lire {
  display: inline-flex;
  align-items: center;
  gap: var(--s-s2);
  font-size: var(--s-fs-s);
  font-weight: 600;
  color: var(--s-primaire-lisible);
  text-decoration: none;
}

.s-lire .s-icone { transition: transform 0.25s var(--s-courbe); }
.s-lire:hover .s-icone { transform: translateX(4px); }

/* ============================================================
   ARTICLE
   ============================================================ */

.s-article__tete { margin-bottom: var(--s-s6); }
.s-article__tete > * + * { margin-top: var(--s-s3); }

.s-article__media {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--s-r-panneau);
  box-shadow: var(--s-ombre);
  margin-bottom: var(--s-s7);
}

.s-article__corps { font-size: var(--s-fs-m); line-height: 1.75; }
.s-article__corps img { border-radius: var(--s-r-carte); }

.s-article__pied {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-s3);
  margin-top: var(--s-s8);
  padding-top: var(--s-s5);
  border-top: 1px solid var(--s-filet);
}

/* ============================================================
   PALIERS — 560 / 768 / 1024 / 1440, ET EUX SEULS
   (DECISIONS.md, 19 août 2026 — contrôlé par verifier-css.py)
   ============================================================ */

@media (min-width: 560px) {
  .s-formulaire .yk-duo {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 var(--s-s4);
  }
}

@media (min-width: 768px) {
  .s-hero {
    grid-template-columns: 1.05fr 0.95fr;
    padding-block: var(--s-s8) var(--s-s9);
  }

  .s-banniere { padding: var(--s-s7); }


  .s-panneau { padding: var(--s-s8) var(--s-s7); }
  .s-medaillon__img { aspect-ratio: 5 / 6; }

  .s-pied__haut { grid-template-columns: 1.2fr 1fr 1fr; }
  .s-mot { grid-template-columns: minmax(0, 300px) 1fr; }
  .s-une { grid-template-columns: 1.05fr 0.95fr; }
  .s-bref { grid-template-columns: 104px 1fr; }
  .s-bref__vignette { width: 104px; }
  .s-panneau > .s-chariot { margin-inline: calc(var(--s-s7) * -1); padding-inline: var(--s-s7); scroll-padding-inline: var(--s-s7); }
  .s-panneau-menu__grille { grid-template-columns: 2fr 1fr; }

  .s-escalier__rangee--inverse > .s-hero__texte { order: 2; }
  /* Après `.s-panneau`, que ce palier rembourre de s8 : le renvoi annonce,
     il ne tient pas la hauteur d'une section. */
  .s-renvoi { padding: var(--s-s6) var(--s-s7); }
  .s-renvoi__liste { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .s-marque__point { width: 30px; height: 30px; }

  /* DÈS 1024 PX, le texte tient dans la moitié gauche : le voile y reste à 90 puis
     78 % jusqu'à 60 % de la largeur, et ne s'ouvre sur la photo
     qu'au-delà. La colonne est bornée à 55 % de la boîte de contenu,
     soit au plus 56 % de la largeur totale une fois le rembourrage
     compté — en deçà du point où le voile descend. */
  .s-banniere__texte { max-width: min(34rem, 55%); }

  .s-banniere::before {
    background: linear-gradient(90deg,
      color-mix(in oklab, var(--s-voile-sombre) 90%, transparent) 0%,
      color-mix(in oklab, var(--s-voile-sombre) 78%, transparent) 60%,
      color-mix(in oklab, var(--s-voile-sombre) 30%, transparent) 100%);
  }
}

@media (max-width: 767.98px) {
  .s-entete { top: var(--s-s2); }
  .s-pilule-nav { padding-left: var(--s-s4); }
  .s-entete .s-marque__nom { font-size: var(--s-fs-m); }
  .s-jeton { position: static; max-width: none; margin-top: var(--s-s4); transform: none; }
  .s-panneau { border-radius: var(--s-r-carte); padding: var(--s-s6) var(--s-s4); }
  .s-boutons .s-bouton { flex: 1 1 auto; }

  /* Le libellé de l'appel pouvait être long et devait se borner ici. Les
     réseaux n'ont plus de libellé du tout : ils rétrécissent d'un cran
     sur petit écran, c'est tout ce qu'ils demandent. */
  .s-entete__reseau { width: 38px; height: 38px; }
  .s-entete__reseau .s-icone { width: 17px; height: 17px; }
}

@media (max-width: 559.98px) {
  .s-carte { padding: var(--s-s4); }
  /* SCOPÉ À L'EN-TÊTE. Sans le sélecteur d'ancêtre, cette règle
     masquait aussi le nom de l'école dans le PIED, où rien ne le
     remplace — le pied n'a pas de logo. */
  .s-entete .s-marque__nom { display: none; }
  .s-declic__mot { display: none; }
  .s-declic { padding-inline: var(--s-s3); }
  .s-pied__bas { flex-direction: column; align-items: flex-start; }
}

@media (min-width: 1440px) {
  :root { --s-gouttiere: 48px; }
  .s-tuile { width: 64px; height: 64px; }
  .s-tuile__img { width: 34px; height: 34px; }
}
