@charset "UTF-8";
/*
 * chine.in — communauté et pages transverses
 * ============================================================================
 *
 * Feuille complémentaire de `site.css`, chargée par les seuls gabarits qui en
 * ont besoin : forum, photothèque, profil de membre, recherche, pages légales
 * et page 404.
 *
 * Elle ne redéfinit aucune couleur en dur : tout repose sur les variables
 * sémantiques de `site.css` (`--surface`, `--encre`, `--bord`, `--marque`…),
 * de sorte que le mode sombre du système continue de fonctionner sans une
 * seule règle dédiée aux composants.
 *
 * Ce qu'elle restitue du site d'origine
 * -------------------------------------
 *  - Forum : l'arborescence en deux colonnes de `forum/index.php` — le thème et
 *    ses sous-forums d'un côté, le dernier message publié de l'autre. Le
 *    portage les empilait dans un même paragraphe gris, où le repère « qui a
 *    écrit quoi, et quand » disparaissait.
 *  - Fil de discussion : `block_forum` séparait la colonne de profil de la
 *    colonne de texte, et alternait les fonds d'un message à l'autre. Faute
 *    d'avatars en base, la pastille d'initiale (décorative, `aria-hidden`)
 *    tient ce rôle : l'œil suit les interlocuteurs sans lire.
 *  - Citations : `blockquote` cadré, avec l'auteur cité **au-dessus** du texte.
 *    Le filtre BBCode produit `<cite>` en ligne : le nom de l'auteur était
 *    collé au premier mot de la citation (« DaweiQuand à empêcher… »).
 *  - Photothèque : la vignette encadrée et sa légende de `photos/index.php`.
 *  - Profil : la pastille de ville de `membres/profil.php` (`.ville`).
 *
 * Le forum est une archive en lecture seule : aucun style de formulaire de
 * réponse ici, il n'y a pas de formulaire à styler.
 */

/* ==========================================================================
   01. Variables locales
   ========================================================================== */

/*
 * Le bleu du forum d'origine (#0C629C) réglé pour tenir le contraste AA sur
 * `--surface` comme sur `--surface-douce`, dans les deux thèmes.
 */
:root {
    --com-encre: #14507d; /* texte bleu sur fond clair — 7,3:1 */
    --com-plein: #14507d; /* aplat portant du blanc — 7,3:1 */
    --com-plein-sur: #fff;
    --com-voile: #eef4fb;
    --com-trait: #b9d0e6;
}

@media (prefers-color-scheme: dark) {
    :root {
        --com-encre: #7ab6ec; /* 7,1:1 sur --surface sombre */
        --com-plein: #2f6ea8; /* blanc dessus — 5,4:1 */
        --com-plein-sur: #fff;
        --com-voile: #17222d;
        --com-trait: #2f4459;
    }
}

/* ==========================================================================
   02. Garde-fous de débordement
   ==========================================================================
   Vingt ans de messages recopiés tels quels : des URLs de 200 caractères, des
   images de 1 200 px, des tableaux, du code. Rien ne doit pousser la page
   au-delà de la fenêtre — sur un téléphone, un débordement horizontal rend la
   lecture pénible bien avant d'être visible. */

.reponse__corps,
.fil__ouverture,
.photo__texte {
    overflow-wrap: anywhere;
}

.reponse__corps img,
.fil__ouverture img,
.photo__texte img {
    max-width: 100%;
    height: auto;
}

.reponse__corps iframe,
.reponse__corps video,
.reponse__corps embed,
.reponse__corps object,
.fil__ouverture iframe,
.fil__ouverture video {
    max-width: 100%;
}

.reponse__corps pre,
.fil__ouverture pre {
    max-width: 100%;
    overflow-x: auto;
    padding: var(--r-3);
    background: var(--surface-appuyee);
    border-radius: var(--rayon-sm);
}

/* Les tableaux collés dans les messages n'ont ni largeur ni classe : on les
   rend défilables sur leur propre axe plutôt que de laisser filer la page. */
.reponse__corps table,
.fil__ouverture table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
}

/*
 * Le libellé masqué d'un en-tête de tableau (`.visually-hidden`) est en
 * `position: absolute` : sans bloc conteneur positionné, il échappe au cadre
 * défilant et repousse le bord droit du document — 460 px de large sur un
 * écran de 390. Positionner le cadre le ramène dans son périmètre.
 */
.table-defilante {
    position: relative;
}

/* ==========================================================================
   03. Forum — en-tête de rubrique
   ========================================================================== */

.page-forum .entete-section {
    margin-bottom: var(--r-5);
}

.page-forum .entete-section .outil__intro {
    max-width: 60ch;
}

/* ==========================================================================
   04. Forum — arborescence des thèmes
   ==========================================================================
   Le site d'origine présentait un tableau à deux colonnes : « Themes des
   Forums Chine » d'un côté, « Dernier message du forum » de l'autre. C'est ce
   partage qui rendait la page lisible ; il est repris ici sous forme de
   cartes, empilées sous 62rem. */

.forum-themes {
    display: grid;
    gap: var(--r-3);
    margin: 0 0 var(--r-6);
}

.forum-theme {
    display: grid;
    gap: var(--r-3);
    padding: var(--r-4);
    background: var(--surface);
    border: 1px solid var(--bord);
    border-radius: var(--rayon-md);
    transition: border-color var(--transition), box-shadow var(--transition);
}

.forum-theme:hover {
    border-color: var(--com-trait);
    box-shadow: var(--ombre-1);
}

@media (min-width: 62em) {
    .forum-theme {
        grid-template-columns: minmax(0, 1.9fr) minmax(16rem, 1fr);
        gap: var(--r-5);
        align-items: start;
    }
}

.forum-theme__corps {
    min-width: 0;
}

.forum-theme__titre {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--r-1) var(--r-3);
    margin: 0 0 var(--r-2);
    font-size: var(--t-xl);
    line-height: 1.25;
    letter-spacing: 0;
}

/* `min-height` plutôt que du remplissage : la cible fait 44 px sans que le
   titre bouge d'un pixel. */
.forum-theme__titre a {
    display: inline-flex;
    align-items: center;
    min-height: var(--cible);
    color: var(--com-encre);
    font-weight: 700;
}

.forum-theme__titre a:hover {
    color: var(--marque-encre);
}

/* Le compte de sujets : une donnée, pas un morceau de titre. */
.forum-theme__compte {
    flex: none;
    padding: 0.1em 0.6em;
    font-size: var(--t-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--encre-faible);
    background: var(--surface-douce);
    border: 1px solid var(--bord);
    border-radius: var(--rayon-pilule);
    white-space: nowrap;
}

.forum-theme__description {
    margin: 0 0 var(--r-3);
    max-width: 62ch;
    font-size: var(--t-sm);
    line-height: 1.55;
    color: var(--encre-douce);
    text-wrap: pretty;
}

/* Les sous-forums restent une phrase — « Sous-forums : a, b, c » — comme à
   l'origine : les virgules appartiennent au texte. Seule la respiration
   change, pour que chaque lien soit atteignable au doigt. */
.forum-theme__sous {
    margin: 0;
    font-size: var(--t-sm);
    line-height: 2.1;
    color: var(--encre-faible);
}

.forum-theme__sous > span:first-child {
    font-size: var(--t-2xs);
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--encre-faible);
}

/* `inline` et non `inline-block` : entre un bloc atomique et la virgule qui le
   suit, le navigateur s'autorise un retour à la ligne, et les virgules se
   retrouvaient en début de ligne. */
.forum-theme__sous a {
    display: inline;
    padding-block: 0.35em;
    color: var(--lien);
}

/* Le dernier message : un encadré à part, jamais une ligne de plus dans le
   paragraphe de description. */
.forum-theme__dernier {
    display: grid;
    gap: var(--r-1);
    margin: 0;
    padding: var(--r-3);
    font-size: var(--t-xs);
    background: var(--surface-douce);
    border: 1px solid var(--bord);
    border-left: 3px solid var(--com-trait);
    border-radius: var(--rayon);
}

.forum-theme__etiquette {
    font-size: var(--t-2xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--encre-faible);
}

.forum-theme__dernier a {
    display: flex;
    align-items: center;
    min-height: var(--cible);
    font-weight: 600;
    line-height: 1.35;
    color: var(--lien);
    overflow-wrap: anywhere;
}

.forum-theme__signature {
    color: var(--encre-faible);
    line-height: 1.45;
}

/* ==========================================================================
   05. Forum — navigation par catégorie
   ========================================================================== */

/* Les pastilles de catégorie font 36 px dans `site.css` : sur un téléphone,
   une liste de vingt-quatre liens serrés se manipule mal. */
.page-forum .category-nav a {
    min-height: var(--cible);
}

.page-forum .category-nav a[aria-current="page"] {
    color: var(--com-plein-sur);
    background: var(--com-plein);
    border-color: var(--com-plein);
}

.page-forum .category-nav a[aria-current="page"] small {
    color: inherit;
    opacity: 0.85;
}

/* ==========================================================================
   06. Forum — liste des discussions
   ==========================================================================
   Une liste de fiches détachées coûtait un écran entier pour dix sujets. Un
   tableau de lignes contiguës, titre à gauche et signature à droite, en montre
   trois fois plus sans rien retirer. */

.page-forum .liste-sujets,
.page-membre .liste-sujets,
.page-search .liste-sujets {
    gap: 0;
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--bord);
    border-radius: var(--rayon-md);
}

.page-forum .liste-sujets > li + li,
.page-membre .liste-sujets > li + li,
.page-search .liste-sujets > li + li {
    border-top: 1px solid var(--bord);
}

.page-forum .liste-sujets a,
.page-membre .liste-sujets a,
.page-search .liste-sujets a {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--r-1) var(--r-4);
    min-height: var(--cible);
    padding: var(--r-3) var(--r-4);
    border: 0;
    border-radius: 0;
}

.page-forum .liste-sujets .sujet__titre,
.page-membre .liste-sujets .sujet__titre,
.page-search .liste-sujets .sujet__titre {
    flex: 1 1 20rem;
    min-width: 0;
    margin: 0;
    overflow-wrap: anywhere;
}

.page-forum .liste-sujets .sujet__meta,
.page-search .liste-sujets .sujet__meta {
    flex: 0 1 auto;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   07. Forum — le fil de discussion
   ==========================================================================
   Un fil est une conversation : le premier message ouvre, les suivants
   répondent. L'alternance des fonds, la pastille d'initiale et la date alignée
   à droite donnent cette lecture au premier coup d'œil. */

.page-forum--topic .article__header {
    margin-bottom: var(--r-5);
    padding-bottom: var(--r-4);
    border-bottom: 2px solid var(--bord);
}

.page-forum--topic .article__header h1 {
    margin-bottom: var(--r-3);
}

.fil__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--r-1) var(--r-2);
    margin: 0;
    font-size: var(--t-sm);
    color: var(--encre-faible);
}

/* Séparateurs décoratifs : la ligne de mention d'origine les portait déjà. */
.fil__meta > * + *::before {
    content: "•";
    margin-inline-end: var(--r-2);
    color: var(--bord-fort);
}

.fil__auteur {
    font-weight: 700;
    color: var(--encre-douce);
}

.fil__meta time {
    font-variant-numeric: tabular-nums;
}

/* Le message d'ouverture, marqué par le filet de marque. */
.fil__ouverture {
    padding: var(--r-4) var(--r-5);
    font-size: var(--t-md);
    line-height: 1.75;
    background: var(--surface);
    border: 1px solid var(--bord);
    border-left: 4px solid var(--marque);
    border-radius: var(--rayon-md);
}

.fil__ouverture > * + * {
    margin-top: var(--r-4);
}

.fil__ouverture p:last-child {
    margin-bottom: 0;
}

.page-forum--topic .replies {
    margin-top: var(--r-6);
}

.page-forum--topic .section-titre {
    margin-bottom: var(--r-4);
}

.page-forum--topic .reponses {
    gap: var(--r-3);
}

.page-forum--topic .reponse {
    padding: var(--r-4);
    background: var(--surface);
    border: 1px solid var(--bord);
    border-left: 3px solid var(--bord-fort);
    border-radius: var(--rayon-md);
    /* Les liens profonds pointent un message précis : l'ancre ne doit pas
       finir sous la barre de navigation fixe. */
    scroll-margin-top: calc(var(--hauteur-barre) + var(--r-4));
}

/* L'alternance : un message sur deux change de fond, comme `linetab1` /
   `linetab2` sur le forum d'origine. */
.page-forum--topic .reponse:nth-child(even) {
    background: var(--surface-douce);
}

.page-forum--topic .reponse:target {
    border-left-color: var(--marque);
    box-shadow: 0 0 0 3px var(--marque-voile);
}

.page-forum--topic .reponse__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--r-2) var(--r-3);
    margin-bottom: var(--r-3);
    padding-bottom: var(--r-2);
    font-size: var(--t-sm);
    border-bottom: 1px solid var(--bord);
}

/*
 * Pastille d'initiale.
 *
 * Le forum d'origine ouvrait chaque message par une colonne de profil : photo,
 * pseudonyme, ville. La base rapatriée ne porte pas l'auteur d'une réponse
 * autrement que par son pseudonyme ; la pastille en reprend l'initiale, et
 * rien d'autre.
 *
 * Elle est dessinée par `content: attr(data-initiale)` : c'est du contenu
 * généré, donc absent du texte de la page, d'une sélection, d'un copier-coller
 * et de l'arbre d'accessibilité. Le contenu de la page ne bouge pas d'un
 * caractère ; seule la lecture y gagne un repère.
 */
.page-forum--topic .reponse__meta[data-initiale]::before {
    content: attr(data-initiale);
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    font-size: var(--t-sm);
    font-weight: 700;
    line-height: 1;
    color: var(--com-plein-sur);
    background: var(--com-plein);
    border-radius: 50%;
    user-select: none;
}

.page-forum--topic .reponse__meta strong {
    min-width: 0;
    font-size: var(--t-sm);
    color: var(--encre);
    overflow-wrap: anywhere;
}

.page-forum--topic .reponse__meta time {
    margin-inline-start: auto;
    font-size: var(--t-xs);
    color: var(--encre-faible);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.page-forum--topic .reponse__corps > * + * {
    margin-top: var(--r-3);
}

.page-forum--topic .reponse__corps p:last-child {
    margin-bottom: 0;
}

/* --- Citations ----------------------------------------------------------
   Le filtre BBCode rend `[quote=X]` en `<cite>X</cite>` suivi du texte, sans
   séparation : le nom se collait au premier mot. `display: block` le remet en
   attribution, au-dessus de ce qui est cité. */

.reponse__corps blockquote,
.fil__ouverture blockquote {
    margin: var(--r-3) 0;
    padding: var(--r-3) var(--r-4);
    font-size: 0.95em;
    color: var(--encre-douce);
    background: var(--surface-douce);
    border: 1px solid var(--bord);
    border-left: 4px solid var(--com-trait);
    border-radius: var(--rayon);
}

.page-forum--topic .reponse:nth-child(even) blockquote {
    background: var(--surface);
}

.reponse__corps blockquote > cite,
.fil__ouverture blockquote > cite {
    display: block;
    margin-bottom: var(--r-2);
    font-size: var(--t-2xs);
    font-style: normal;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--com-encre);
}

/* Citation dans la citation : on resserre le retrait pour ne pas réduire le
   texte à une colonne de trois mots. */
.reponse__corps blockquote blockquote,
.fil__ouverture blockquote blockquote {
    margin-inline: 0;
    padding-inline: var(--r-3);
    border-left-width: 3px;
}

.reponse__corps blockquote p:last-child,
.fil__ouverture blockquote p:last-child {
    margin-bottom: 0;
}

/* Les images des messages : jamais plus hautes qu'un écran, jamais plus larges
   que la colonne. */
.reponse__corps img,
.fil__ouverture img {
    max-height: min(70vh, 32rem);
    border-radius: var(--rayon-sm);
}

@media (max-width: 34em) {
    .page-forum--topic .reponse,
    .fil__ouverture {
        padding-inline: var(--r-3);
    }

    .reponse__corps blockquote,
    .fil__ouverture blockquote {
        padding-inline: var(--r-3);
    }
}

/* Avis d'archive : c'est une information de statut, pas une alerte. */
.page-forum .avis,
.page-membre .avis {
    margin-top: var(--r-6);
}

/* ==========================================================================
   08. Photothèque
   ==========================================================================
   Une grille d'images : le format compte plus que tout. Les clichés sont des
   photographies, pas des icônes — un cadre en 4/3 les recadre beaucoup moins
   qu'un carré, et la légende garde une hauteur constante pour que les lignes
   de la grille restent alignées. */

.page-photos .entete-section,
.page-photos > h1 {
    margin-bottom: var(--r-2);
}

.page-photos .outil__intro {
    margin-bottom: var(--r-5);
    max-width: 60ch;
}

.page-photos .grille {
    grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr));
    gap: var(--r-4);
}

.page-photos .grille a {
    gap: var(--r-2);
}

.page-photos .grille__image {
    aspect-ratio: 4 / 3;
    background: var(--surface-douce);
    border: 1px solid var(--bord);
    border-radius: var(--rayon);
    box-shadow: none;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.page-photos .grille a:hover .grille__image,
.page-photos .grille a:focus-visible .grille__image {
    border-color: var(--com-trait);
    box-shadow: var(--ombre-2);
}

.page-photos .grille h3 {
    /* Deux lignes de légende réservées : la grille ne se déchausse pas selon
       la longueur des titres, et rien n'est tronqué. */
    min-height: 2.8em;
    font-size: var(--t-xs);
    line-height: 1.4;
    color: var(--encre-douce);
    overflow-wrap: anywhere;
}

/* --- Une photo ---------------------------------------------------------- */

.page-photo .fiche-photo {
    display: grid;
    gap: var(--r-4);
}

/* Le titre, le cadre et la légende partagent le même bord gauche. `site.css`
   centre le titre d'un article sur la mesure de lecture (`margin-inline: auto`),
   ce qui, sur une grille, le réduit à sa largeur de texte et le décentrait de
   l'image. */
.page-photo .fiche-photo > h1 {
    max-width: none;
    margin-inline: 0;
    margin-bottom: 0;
}

.photo__cadre {
    display: grid;
    place-items: center;
    margin: 0;
    padding: var(--r-3);
    background: var(--surface-douce);
    border: 1px solid var(--bord);
    border-radius: var(--rayon-md);
}

.photo__cadre img {
    display: block;
    width: auto;
    max-width: 100%;
    height: auto;
    max-height: min(72vh, 40rem);
    border-radius: var(--rayon-sm);
}

/*
 * La légende. `.article__texte` est une grille à trois colonnes dans
 * `site.css` : un texte nu, sans balise de bloc, y devient un élément anonyme
 * placé dans la gouttière de gauche et se réduisait à une colonne de 140 px.
 * Ici la légende est un bloc simple, plafonné à la mesure de lecture.
 */
.photo__texte {
    display: block;
    max-width: var(--mesure);
    margin-inline: 0;
    font-size: var(--t-md);
    line-height: 1.75;
}

.photo__texte > * + * {
    margin-top: var(--r-4);
}

/* ==========================================================================
   09. Profil de membre
   ========================================================================== */

.profil {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--r-4);
    margin: 0 0 var(--r-5);
    padding: var(--r-4);
    background: var(--surface-douce);
    border: 1px solid var(--bord);
    border-radius: var(--rayon-md);
}

.profil__photo {
    flex: none;
    width: 5rem;
    height: 5rem;
    object-fit: cover;
    background: var(--surface);
    border: 1px solid var(--bord);
    border-radius: 50%;
}

.profil__infos {
    display: grid;
    gap: var(--r-2);
    min-width: 0;
}

/* La pastille de ville du profil d'origine (`.ville`), au contraste près. */
.profil__ville {
    justify-self: start;
    margin: 0;
    padding: 0.15em 0.7em;
    font-size: var(--t-xs);
    font-weight: 700;
    color: var(--marque-encre);
    background: var(--marque-voile);
    border: 1px solid color-mix(in srgb, var(--marque) 25%, transparent);
    border-radius: var(--rayon-pilule);
}

.profil__depuis {
    margin: 0;
    font-size: var(--t-sm);
    color: var(--encre-faible);
}

.profil__signature {
    margin: 0;
    padding-left: var(--r-3);
    font-size: var(--t-sm);
    font-style: italic;
    line-height: 1.6;
    color: var(--encre-douce);
    border-left: 3px solid var(--bord-fort);
    overflow-wrap: anywhere;
}

.page-membre > h1 {
    margin-bottom: var(--r-4);
}

/* ==========================================================================
   10. Recherche
   ========================================================================== */

.page-search .recherche-principale {
    flex-wrap: wrap;
    margin-bottom: var(--r-6);
}

/* Les cases de section passent sous le champ, sur toute la largeur du
   formulaire, et s'enroulent au besoin — le formulaire est en `display: flex`
   (site.css), d'où `flex: 1 0 100%` pour forcer le retour à la ligne. */
.page-search .recherche-filtres {
    flex: 1 0 100%;
    display: flex;
    flex-wrap: wrap;
    gap: var(--r-2) var(--r-4);
    margin: 0;
    padding: 0;
    border: 0;
}

.page-search .recherche-filtre {
    display: inline-flex;
    align-items: center;
    gap: var(--r-2);
    font-size: var(--t-sm);
    color: var(--encre-douce);
    cursor: pointer;
}

/* Remise à zéro : sans elle, la case hériterait de la hauteur de 3 rem et du
   cadre du champ de recherche (`.recherche-principale input` dans site.css). */
.page-search .recherche-filtre input {
    width: auto;
    min-width: 0;
    min-height: 0;
    padding: 0;
    border: 0;
    accent-color: var(--marque);
}

/* ==========================================================================
   La liste unique de résultats — DES CARTES, ET UNE SEULE COLONNE
   ==========================================================================

   Deux demandes de l'éditeur se croisent ici, et elles ne disent pas la même
   chose. Le 21 août 2026 : « j'aimerais que tous les résultats soient mélangés
   par ordre de pertinence plutôt qu'un bloc de dico, un bloc guide » — donc plus
   de <section> par rubrique. Le 22 août, devant le résultat : « je n'aime pas du
   tout le design des résultats : plat, triste, banal […] avant au moins c'était
   un peu plus joli avec des cards ».

   La première demande porte sur l'ORDRE, la seconde sur la FORME, et la
   première version avait cru devoir payer l'une par l'autre : les six grilles de
   cartes étaient devenues une liste de lignes séparées par un filet. Ce fichier
   rend les cartes en gardant la liste unique — c'est `.card` de `site.css`,
   couchée : même surface, même bord, même rayon, mêmes trois signaux au survol.

   LA COLONNE UNIQUE A TENU UN JOUR, ET VOICI CE QUI L'A REMPLACÉE. Elle se
   justifiait ainsi : sur une liste où la place d'UNE ligne est toute
   l'information, deux cartes côte à côte se lisent comme deux égales, et la
   colonne unique rend le classement visible.

   L'éditeur a tranché le 22 août 2026 : « ce serait mieux sur plusieurs
   colonnes, avec — si la hauteur n'est pas haute — une sorte d'imbrication,
   maçonnerie, comme des briques ». Ce que l'argument ci-dessus ne voyait pas,
   c'est qu'une colonne unique de cartes hautes ne montre que quatre résultats
   par écran : le classement était lisible, mais il n'y avait presque rien à
   classer à l'écran. Trois colonnes en montrent une douzaine, et l'ordre reste
   celui de la lecture — gauche à droite, ligne après ligne.

   « POUR MOBILE ON PEUT LAISSER UN RÉSULTAT PAR LIGNE », dit la même
   conversation, et c'est ce que `minmax()` fait sans règle de plus : sous
   ~600 px, une seule colonne tient, et `auto-fill` en pose une seule.

   LA MAÇONNERIE N'EST PAS ICI, ELLE EST DANS `recherche.js`. Aucun navigateur
   ne la sait faire en CSS aujourd'hui — relevé sur Chrome 151 le 22 août 2026 :
   `CSS.supports('grid-template-rows', 'masonry')` et `CSS.supports('display',
   'masonry')` rendent tous deux `false`. Ce que ce fichier pose est donc la
   grille ORDINAIRE, celle qui aligne les rangées ; le script la resserre après
   coup en ajoutant `.resultats--maconnerie`.

   L'ORDRE DES DEUX COMPTE, et c'est pourquoi la maçonnerie est un ajout et non
   le défaut : sans JavaScript — script bloqué, erreur, instant avant son
   exécution — la page reste une grille correcte. L'inverse (des rangées de 4 px
   par défaut, redressées par le script) donnerait une page illisible à qui n'a
   pas de JavaScript. */
.resultats {
    display: grid;
    /* 260 px : la carte doit tenir un titre de deux lignes et une pastille sans
       que le titre se coupe. Mesuré plus bas, les titres du dictionnaire
       débordaient. */
    grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
    gap: var(--r-3);
    /* Chaque carte garde SA hauteur au lieu de s'étirer sur celle de sa rangée.
       C'est la moitié de l'effet de brique, et la seule que le CSS puisse
       donner seul : les trous entre rangées, eux, demandent le script. */
    align-items: start;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* ==========================================================================
   La maçonnerie, posée par `recherche.js`
   ==========================================================================

   LE PRINCIPE : des rangées de 4 px, et chaque carte occupe autant de rangées
   que sa hauteur mesurée en demande. Une carte de 122 px prend 31 rangées, sa
   voisine de 208 px en prend 52, et la carte suivante démarre juste sous la
   première au lieu d'attendre la seconde. C'est ce que fait toute maçonnerie
   sans `grid-template-rows: masonry`.

   POURQUOI 4 PX ET NON 1. Le nombre de rangées d'une grille est un coût réel
   pour le moteur de rendu, et 4 px suffit : l'erreur d'arrondi maximale est de
   3 px sur une carte, invisible à l'œil, quand 1 px multiplierait par quatre le
   nombre de pistes pour un gain qu'on ne verrait pas.

   `row-gap: 0` EST OBLIGATOIRE, et c'est le piège de ce réglage : l'écart entre
   deux cartes empilées est déjà compté dans le `span` que le script calcule
   (il ajoute l'équivalent d'un `gap` en rangées). Laisser le `row-gap` de la
   grille ordinaire l'ajouterait une seconde fois, et les colonnes se
   décaleraient les unes des autres d'un cran par carte.

   `align-items` RESTE À `start`, HÉRITÉ DE LA GRILLE ORDINAIRE, et c'est le
   réglage qui a coûté le plus de temps ici. Le premier essai posait `stretch`,
   sur l'idée que la carte devait remplir exactement les rangées réservées. Elle
   les remplit, en effet — et le script se met alors à lire sa propre écriture :
   il mesure la carte pour en déduire le nombre de rangées, mais la carte fait la
   hauteur des rangées qu'on vient de lui donner. Le calcul converge vers un
   point fixe et toutes les cartes finissent identiques.

   Mesuré sur « nouvel an chinois » : trente-quatre cartes à 132 px et
   `--span: 39`, quand leurs hauteurs naturelles s'échelonnent de 74 à 401 px. Une
   règle `height: auto` sur le lien n'y change rien : c'est le `<li>`, élément de
   grille, qui est étiré, et le lien à `height: 100%` le suit.

   En `start`, le `<li>` fait la hauteur de son contenu, le script mesure ce
   contenu, et le `span` ne fait que RÉSERVER la place — ce qui est exactement son
   rôle. L'écart entre deux cartes empilées est la différence entre la place
   réservée et la hauteur occupée. */
.resultats--maconnerie {
    grid-auto-rows: 4px;
    row-gap: 0;
}

.resultats--maconnerie > .resultat {
    /* `--span` est posé par le script, carte par carte. La valeur de repli sert
       l'instant qui sépare l'ajout de la classe du premier calcul, et le cas
       d'une carte apparue après coup. */
    grid-row: span var(--span, 30);
}


/* Le masquage d'une carte quand on décoche sa case (assets/js/recherche.js pose
   `hidden` sur le <li>). L'attribut doit l'emporter sur le `display` du <li> de
   grille : il le vise ici avec une spécificité supérieure. */
.resultats > li[hidden] {
    display: none;
}

/* ==========================================================================
   La teinte de provenance
   ==========================================================================

   SIX SOURCES, SIX TEINTES, ET AUCUNE N'EST INVENTÉE. Le site en définit
   exactement six dans `site.css` (`--teinte-*`), et `Support\Rubrique` dit déjà
   laquelle va à quelle rubrique. Quatre se recopient donc telles quelles : le
   dictionnaire est `/mandarin/…`, donc bleu ; le guide, brun ; le forum, bleu
   clair ; l'actualité garde le rouge de marque, comme `Rubrique::TEINTES` le
   pose. Les outils prennent l'indigo des Loisirs, le portail dont ils relèvent.

   Reste « Rubriques », et c'est le seul choix qui ne se déduise pas : un hub
   n'appartient à aucune rubrique — il en traverse plusieurs —, et il reçoit donc
   l'olive, la seule teinte que les cinq autres sources ne prennent pas. C'est le
   procédé du composant de la revue de presse (`.revue-cat--*` dans `site.css`),
   qui range onze rubriques dans les six mêmes teintes en écartant les paires.

   Le mécanisme aussi est celui de la revue : une variable locale `--cat`, qui
   sert d'encre et d'aplat à 10 %. Il apporte le mode sombre sans une règle de
   plus — `site.css` redéfinit les six `--teinte-*` sous `prefers-color-scheme:
   dark`, et `--surface` avec elles, donc l'aplat suit. Une couleur écrite en dur
   ici resterait, elle, sombre sur fond sombre.

   `/search/` n'existe qu'en français (`config/routes.php` l. 1112, aucune route
   anglaise), donc la règle qui ramène toutes les teintes au rouge sous
   `html[lang="en"]` ne s'y applique pas aujourd'hui. Elle s'y appliquerait le
   jour où la page serait traduite, et c'est le bon comportement : la marque
   anglaise est rouge de bout en bout. */
.resultat--outils { --cat: var(--teinte-loisirs); }
.resultat--rubriques { --cat: var(--teinte-nouvel-an); }
.resultat--dictionnaire { --cat: var(--teinte-chinois); }
.resultat--guide { --cat: var(--teinte-guide); }
.resultat--actualite { --cat: var(--teinte-defaut); }
.resultat--forum { --cat: var(--teinte-forum); }

/* ==========================================================================
   La carte
   ==========================================================================

   AUCUN SOULIGNEMENT AU SURVOL, ET CE N'EST PAS UN RETRAIT. L'éditeur l'a
   demandé le 22 août 2026 ; le Pilote avait tranché le même point le 20 (voir
   le docblock de `piloteFeuille()`, « Les liens ne sont plus soulignés »), et la
   règle qui en sort vaut ici : le trait DÉSIGNE le lien, et l'enlever sans rien
   mettre à la place laisse une page où l'on ne sait plus ce qui est cliquable.

   Trois signaux le remplacent, et l'un d'eux n'est PAS une couleur :

     - le RELIEF — l'ombre passe de `--ombre-1` à `--ombre-2` et la carte monte
       de deux pixels. C'est le survol de `.card > a` dans `site.css`, repris tel
       quel : le même geste garde la même réponse d'un bout à l'autre du site ;
     - le BORD, qui prend la teinte de la source plutôt que de rester gris — la
       carte survolée se rattache visiblement à sa pastille ;
     - le CONTOUR DE FOCUS, qui ne se retire jamais. Le soulignement ne servait
       pas d'indicateur de focus (le navigateur pose son propre anneau), mais un
       `text-decoration: none` posé sans y penser sur `:focus-visible` rend une
       page inutilisable au clavier, et c'est l'erreur classique de ce réglage.

   Le titre, lui, change d'encre au survol. C'est un quatrième signal, et il est
   en trop pour qui distingue mal les couleurs : les trois ci-dessus tiennent
   sans lui. */
.resultat__lien {
    display: flex;
    align-items: flex-start;
    gap: var(--r-3);
    height: 100%;
    /* La carte est la brique : elle ne dépasse jamais des rangées que la
       maçonnerie lui a réservées, et son coin arrondi coupe l'image du bandeau
       ci-dessous sans qu'il faille l'arrondir elle-même. */
    overflow: hidden;
    padding: var(--r-3);
    color: inherit;
    background: var(--surface);
    border: 1px solid var(--bord);
    /* LE LISERÉ EST CE QUI FAIT LIRE LA COLONNE SANS LA LIRE. Une pastille se
       lit ; un trait de 3 px sur toute la hauteur de la carte se reconnaît en
       balayant la page, et c'est ce qu'on fait d'une liste de résultats. Le
       procédé et la variable `--cat` viennent du même endroit que la pastille :
       les sections de la revue de presse, où `--cat` habille déjà « le filet, le
       liseré et le tag ». */
    border-left: 3px solid var(--cat, var(--marque));
    border-radius: var(--rayon);
    box-shadow: var(--ombre-1);
    transition: border-color var(--transition), box-shadow var(--transition),
        transform var(--transition);
}

.resultat__lien:hover,
.resultat__lien:focus-visible {
    border-color: var(--cat, var(--marque));
    box-shadow: var(--ombre-2);
    transform: translateY(-2px);
    text-decoration: none;
}

.resultat__lien:hover .resultat__titre {
    color: var(--cat, var(--marque));
}

/* ==========================================================================
   La carte illustrée
   ==========================================================================

   « CEUX QUI ONT DES IMAGES : IMAGES PLUS GROSSES » (l'éditeur, 22 août 2026).
   La vignette carrée de 88 px posée à gauche du texte devient un bandeau en
   tête, sur toute la largeur de la carte — de 88 px à 260-340 px, soit trois à
   quatre fois plus de surface.

   POURQUOI `:has()` ET NON UNE CLASSE POSÉE PAR LE GABARIT. La condition existe
   déjà dans le HTML : la carte porte un `.resultat__media`, ou elle n'en porte
   pas. Une classe `resultat--illustre` dirait la même chose une seconde fois,
   et les deux se contrediraient le jour où l'une serait oubliée. `:has()` est
   partout depuis 2023 ; si un navigateur ne le connaît pas, il rend la carte
   horizontale d'avant, ce qui est un repli parfaitement lisible.

   LE BANDEAU EST EN 16/9 SUR UNE SOURCE CARRÉE, et c'est délibéré : demander un
   dérivé 16/9 ferait fabriquer des fichiers que le préchauffage ne connaît pas
   (CLAUDE.md règle 4). `object-fit: cover` recadre le carré déjà fabriqué, et
   `object-position: 50% 25%` garde le HAUT du sujet — « il faut TOUJOURS montrer
   le haut des vignettes verticales », demande générale du 19 août 2026.

   LES MARGES NÉGATIVES sortent l'image du `padding` de la carte pour qu'elle en
   touche les bords. `overflow: hidden` sur `.resultat__lien` la fait suivre le
   rayon des coins. */
.resultat__lien:has(.resultat__media) {
    flex-direction: column;
    gap: 0;
    padding: 0;
}

.resultat__lien:has(.resultat__media) .resultat__corps {
    padding: var(--r-3);
}

.resultat__media {
    flex: 0 0 auto;
    width: 100%;
    line-height: 0;
}

.resultat__media img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    object-position: 50% 25%;
}

.resultat__corps {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--r-1);
    min-width: 0;
}

/* La pastille de provenance porte le mot EXACT de la case à cocher : c'est ce
   qui fait comprendre d'un coup d'œil quelle case masquerait cette carte. Aplat
   à 10 % de la teinte sur la surface, encre à pleine teinte — les proportions de
   `.revue-cat__pastille`, mesurées AA sur les six (le brun du guide, le plus
   sombre, donne 5,61:1 sous blanc). */
.resultat__source {
    padding: 0.1em 0.5em;
    font-size: var(--t-2xs);
    font-weight: 700;
    line-height: 1.5;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--cat, var(--marque));
    background: color-mix(in srgb, var(--cat, var(--marque)) 10%, var(--surface));
    border: 1px solid color-mix(in srgb, var(--cat, var(--marque)) 30%, transparent);
    border-radius: var(--rayon-pilule);
    /* C'est une pastille, pas un mot de la phrase : elle ne se coupe pas. */
    white-space: nowrap;
}

.resultat__titre {
    font-size: var(--t-lg);
    font-weight: 600;
    line-height: 1.3;
    color: var(--encre);
    text-wrap: pretty;
    overflow-wrap: anywhere;
    transition: color var(--transition);
}

/* ==========================================================================
   LE SINOGRAMME EST L'OBJET DE LA CARTE, PAS SON TITRE
   ==========================================================================

   « Ceux qui ont du texte chinois : texte plus gros » (l'éditeur, 22 août 2026).

   Une entrée de dictionnaire n'est pas un article dont le titre annoncerait le
   contenu : le sinogramme EST ce qu'on est venu voir, et le reste de la carte
   l'explique. Le rendre au corps d'un titre d'article le traitait comme un
   intitulé parmi d'autres — et deux caractères au corps d'un titre, dans une
   carte de 260 px, ne se lisent pas : les traits d'un caractère composé se
   confondent bien avant ceux d'une lettre latine.

   2,1 fois le corps du texte, et non un `font-size` en dur : la carte suit ainsi
   l'échelle typographique du site et le réglage de corps du visiteur. La valeur
   vient de ce que fait déjà la fiche du dictionnaire pour sa vedette.

   `line-height: 1.15` PARCE QUE LE CJK N'A NI JAMBAGE NI HAMPE. L'interligne de
   1,3 hérité du titre creuse un vide sous un caractère chinois, très visible dès
   que la carte n'a qu'une ligne. */
.resultat--dictionnaire .chinois {
    font-size: 2.1em;
    font-weight: 500;
    line-height: 1.15;
    /* Un caractère se lit entier ou pas du tout : `anywhere`, hérité du titre,
       couperait une graphie de trois caractères au milieu. */
    overflow-wrap: normal;
}

/* Le pinyin accompagne le sinogramme sans le concurrencer : corps plus petit,
   encre douce — la hiérarchie du tableau du dictionnaire. Il passe À LA LIGNE
   depuis que le sinogramme a doublé de corps : sur la même ligne, il flottait
   au milieu d'une hauteur de deux fois la sienne, et la carte devenait large
   sans raison. */
.resultat--dictionnaire .resultat__titre {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.1em;
}

.resultat__pinyin {
    font-size: var(--t-sm);
    font-weight: 400;
    color: var(--encre-douce);
}

.resultat__extrait {
    font-size: var(--t-sm);
    line-height: 1.45;
    color: var(--encre-douce);
    overflow-wrap: anywhere;
}

.resultat__date {
    font-size: var(--t-xs);
    color: var(--encre-faible);
    font-variant-numeric: tabular-nums;
}

/* CETTE RÈGLE A DISPARU LE 22 AOÛT 2026, ET IL FAUT SAVOIR CE QU'ELLE FAISAIT.
   Elle ramenait la vignette de 88 à 64 px sous 26 em, « à 375 px elle prenait le
   quart de la largeur utile ». Elle n'a plus d'objet : la vignette n'est plus un
   carré posé à gauche du texte mais un bandeau en tête de carte, et sur
   téléphone la carte occupe toute la largeur — c'est précisément là que l'image
   doit être la plus grande.

   Ce qui reste vrai de son commentaire : au doigt, la carte entière est la
   cible, et le `padding` suffit à passer les 44 px réglementaires dès qu'il y a
   un titre et une pastille. */

/* Les liens vers les pages de recherche par rubrique, sous la liste : elle n'en
   montre que les huit meilleures lignes de chacune. */
.resultats-ailleurs {
    margin-top: var(--r-5);
    font-size: var(--t-sm);
    color: var(--encre-douce);
}

/* ==========================================================================
   11. Pages légales
   ==========================================================================
   Des textes longs et denses — identification de l'éditeur, conditions
   d'utilisation, droits RGPD. `site.css` centre les paragraphes sur la mesure
   de lecture mais laisse les titres pleine largeur : les deux ne partageaient
   pas le même bord gauche, et l'œil perdait la structure. Ici la colonne est
   unique et les sections sont franchement séparées. */

.page-static .article {
    max-width: 46rem;
    margin-inline: auto;
}

.page-static .article > h1,
.page-static .article > h2,
.page-static .article > h3,
.page-static .article > p,
.page-static .article > ul,
.page-static .article > ol {
    max-width: none;
    margin-inline: 0;
}

.page-static .article > h1 {
    margin-bottom: var(--r-5);
    padding-bottom: var(--r-4);
    font-size: var(--t-3xl);
    line-height: 1.15;
    border-bottom: 3px solid var(--marque);
}

.page-static .article > h2 {
    margin-top: var(--r-7);
    margin-bottom: var(--r-3);
    padding-top: var(--r-4);
    font-size: var(--t-xl);
    line-height: 1.3;
    color: var(--encre);
    border-top: 1px solid var(--bord);
    scroll-margin-top: calc(var(--hauteur-barre) + var(--r-4));
}

.page-static .article > h2:first-of-type {
    margin-top: var(--r-6);
}

.page-static .article > h2 strong {
    font-weight: inherit;
}

.page-static .article > p {
    margin-bottom: var(--r-4);
    line-height: 1.75;
    text-wrap: pretty;
}

.page-static .article > ul {
    margin-bottom: var(--r-4);
    padding-left: var(--r-5);
    line-height: 1.7;
}

.page-static .article > ul > li + li {
    margin-top: var(--r-2);
}

.page-static .article a {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    overflow-wrap: anywhere;
}

/* Le nom de l'éditeur revient à chaque paragraphe : en gras il rythme la
   lecture au lieu de la hacher. */
.page-static .article > p strong {
    font-weight: 600;
    color: var(--encre);
}

/* La liste des flux par rubrique, sur `/flux-rss/`.

   CENT QUATRE-VINGTS ENTRÉES, ET C'EST LA SEULE RAISON DE CES TROIS RÈGLES.
   Une colonne unique donnerait un ruban de six écrans qu'on parcourt au pouce
   pour y chercher un nom qu'on connaît déjà. `columns` les range en colonnes
   dont le navigateur choisit le nombre selon la largeur disponible : trois sur
   un écran de bureau, une seule sous 320 px, sans point de rupture à tenir.

   `break-inside: avoid` sur l'élément : sans lui, un titre long — « Patrimoine
   mondial et géoparcs de l'UNESCO » — se coupe en fin de colonne et se lit sur
   deux, ce qui est exactement l'illisibilité qu'on cherchait à supprimer.

   Pas de puces : à cette densité elles ajoutent une colonne de points sans rien
   dire, et le lien se signale déjà tout seul. */
.flux-categories {
    columns: 16rem auto;
    column-gap: var(--r-5);
    padding-left: 0;
    list-style: none;
}

.flux-categories li {
    break-inside: avoid;
    margin-bottom: var(--r-2);
}

/* ==========================================================================
   12. Page 404 — PARTIE, ET ELLE NE DOIT PAS REVENIR ICI

   Sept règles vivaient à cet endroit : le titre, la phrase, et la grille de
   cartes des six suggestions que la page d'erreur proposait. Elles sont
   remplacées par `404.css`, et surtout la 404 NE CHARGE PLUS cette feuille.

   Deux raisons de ne pas l'y ramener. La première est qu'elle n'en tirait plus
   que ces sept règles, pour 13 Ko réduits. La seconde tient au volume : la page
   introuvable est servie 123 000 fois par jour — 11,5 % du trafic, le deuxième
   code de réponse du site — et tout ce qu'elle charge se multiplie par ce
   nombre.

   Ces règles n'ont d'ailleurs jamais servi à la 500 : `500.html.twig` hérite
   directement de `layout.html.twig` et n'a jamais chargé `communaute.css`. Elles
   étaient donc, depuis leur écriture, servies aux douze gabarits de cette
   feuille — forum, profils, recherche, pages légales — pour une seule page.
   ========================================================================== */

/* ==========================================================================
   13. Notifications — les interrupteurs
   ========================================================================== */

/*
 * POURQUOI CES RÈGLES SONT ICI ET NON DANS `site.css`, OÙ VIT LE RESTE DE
 * `.notif-*`
 *
 * `/notifications/` est rendue par `layout-communaute.html.twig` : cette
 * feuille-ci est donc exactement celle que cette page charge, et elle ne part
 * nulle part ailleurs qu'aux douze gabarits qui la demandent déjà. Les mêmes
 * règles posées dans `site.css` voyageraient dans les vingt mille pages du plan
 * du site — dont la page introuvable, servie 123 000 fois par jour — pour un
 * composant qui n'existe que sur une seule adresse. C'est le raisonnement qui a
 * fait sortir d'ici les sept règles de la 404 (section 12), pris dans l'autre
 * sens.
 *
 * CE QUE CELA LAISSE DERRIÈRE, ET IL FAUT LE SAVOIR AVANT DE CHERCHER : le bloc
 * `.notif-*` de `site.css` (état, cartouche des sujets, grille de chaque ligne,
 * boutons) n'a pas bougé. Les interrupteurs sont ici, le reste est là-bas. Un
 * chantier qui rassemblerait les deux irait dans ce sens-ci, jamais dans
 * l'autre.
 *
 * L'ORDRE DE CHARGEMENT REND CES RÈGLES GAGNANTES : `site.css` est posée par
 * `partials/head.html.twig`, cette feuille par le bloc `head_extra` qui suit.
 * La spécificité est malgré tout portée à (0,2,1) — `.notif-sujet
 * input[role="switch"]` — parce que `site.css` écrit `.notif-sujet input`, qui
 * vaut autant : à égalité, c'est l'ordre qui tranche, et l'ordre est une
 * propriété du gabarit, pas de la feuille. Une page qui chargerait un jour les
 * deux dans l'autre sens ferait revenir la case native sans rien casser
 * d'autre, donc sans que personne ne le remarque.
 */

/*
 * L'INTERRUPTEUR EST UNE VRAIE CASE À COCHER, ET TOUT CE QUI SUIT N'EST QUE SON
 * DESSIN.
 *
 * `appearance: none` retire le gabarit du système ; la piste est le fond de la
 * case, le curseur est son `::before`. Aucun script n'entretient l'état :
 * `:checked` est posé par le navigateur, et `role="switch"` fait suivre
 * `aria-checked` tout seul.
 *
 * SI `::before` N'ÉTAIT PAS RENDU — un navigateur qui refuserait les
 * pseudo-éléments sur un élément remplacé —, il resterait la piste, dont le fond
 * et la bordure changent aussi à `:checked`. L'état reste donc lisible sans le
 * curseur : c'est le repli, et il est gratuit.
 */
.notif-sujet input[role="switch"] {
    /* Repris de `site.css` : la case occupe une colonne à elle sur les trois
       lignes du sujet. Le redire ici évite que la règle d'en face, qui vaut
       autant, ne reprenne la main sur ces deux propriétés. */
    grid-row: 1 / span 3;
    margin-top: 0.15em;

    box-sizing: border-box;
    flex: none;
    width: 2.5rem;
    height: 1.375rem;
    padding: 0;
    appearance: none;
    cursor: pointer;
    background: var(--surface-douce);

    /*
     * LA BORDURE EST LÀ POUR LE CONTRASTE, PAS POUR LE GOÛT. Un interrupteur
     * éteint dont la piste vaudrait `--bord-fort` (#c9c2b0) sur la surface
     * claire tiendrait 1,9:1, quand une commande doit tenir 3:1 (WCAG 1.4.11).
     * `--encre-douce` porte la frontière à plus de 6:1 dans les deux thèmes.
     */
    border: 2px solid var(--encre-douce);
    border-radius: var(--rayon-pilule);
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

/*
 * LA TAILLE DU CURSEUR EST DICTÉE PAR LA PISTE, ELLE NE SE CHOISIT PAS.
 *
 * La piste est en `border-box` : 2,5rem sur 1,375rem moins deux bordures de
 * 2px laissent une boîte de contenu de 2,25rem sur 1,125rem (36 × 18 px). Le
 * curseur doit la remplir en hauteur, marges comprises — d'où 1rem plus deux
 * fois 0,0625rem, soit exactement 1,125rem.
 *
 * Il valait 0,75rem : douze pixels dans dix-huit, collés en haut par la marge,
 * ce qui donnait un petit rond perdu dans son cadre au lieu d'un interrupteur.
 * Le `translateX` d'en dessous, lui, n'avait jamais bougé et dit la mesure
 * juste : 36 − 16 − 2 = 18 px = 1,125rem. C'est le curseur qui avait tort.
 *
 * TOUCHER L'UNE DE CES QUATRE VALEURS OBLIGE À REFAIRE LES TROIS AUTRES.
 */
.notif-sujet input[role="switch"]::before {
    display: block;
    width: 1rem;
    height: 1rem;
    margin: 0.0625rem;
    content: "";
    background: var(--encre-douce);
    border-radius: 50%;
    transition: transform 0.15s ease, background-color 0.15s ease;
}

/*
 * DEUX CANAUX POUR UN SEUL ÉTAT — la position du curseur ET la couleur de la
 * piste. Un interrupteur qui ne dirait son état que par la couleur serait
 * illisible pour un daltonien ; qui ne le dirait que par la position le serait
 * de loin.
 */
.notif-sujet input[role="switch"]:checked {
    background: var(--marque);
    border-color: var(--marque);
}

.notif-sujet input[role="switch"]:checked::before {
    background: var(--marque-sur);
    transform: translateX(1.125rem);
}

.notif-sujet input[role="switch"]:focus-visible {
    outline: 2px solid var(--anneau);
    outline-offset: 2px;
}

/*
 * Le glissement du curseur n'apprend rien : il fait joli. Il tombe donc quand
 * le système demande moins de mouvement, et l'interrupteur bascule d'un coup —
 * ce qui reste parfaitement lisible, la couleur changeant en même temps.
 */
@media (prefers-reduced-motion: reduce) {
    .notif-sujet input[role="switch"],
    .notif-sujet input[role="switch"]::before {
        transition: none;
    }
}

/*
 * CONTRASTES FORCÉS (Windows, « mode contraste élevé ») : `appearance: none`
 * retire le gabarit du système, donc aussi le dessin que ce mode aurait
 * repeint. Sans ces quatre lignes, l'interrupteur devient un rectangle vide dont
 * l'état ne se lit plus du tout — le seul cas où ce composant serait pire que la
 * case qu'il remplace.
 */
@media (forced-colors: active) {
    .notif-sujet input[role="switch"] {
        border-color: ButtonText;
        forced-color-adjust: none;
        background: ButtonFace;
    }

    .notif-sujet input[role="switch"]::before {
        background: ButtonText;
    }

    .notif-sujet input[role="switch"]:checked {
        background: Highlight;
        border-color: Highlight;
    }

    .notif-sujet input[role="switch"]:checked::before {
        background: HighlightText;
    }
}

/*
 * « Ces choix prendront effet quand vous activerez les notifications. »
 *
 * Révélée par `notifications.js` dans le seul état où l'interrupteur ne peut
 * rien enregistrer, faute d'abonnement. Le pourquoi est dans
 * `NotificationsTextes::commandes()`.
 */
.notif-attente {
    margin: var(--r-3) 0 0;
    font-size: var(--t-sm);
    color: var(--encre-douce);
}

.notif-attente[hidden] {
    /* `hidden` ne gagne pas contre une règle de classe : voir la note de
       `site.css` au-dessus de `.installer[hidden]`, où le même piège est décrit
       en entier. Ici, `.notif-attente` ne pose pas de `display`, mais la règle
       est écrite pour que l'ajout d'un `display: flex` un jour ne rende pas la
       phrase visible en permanence sur une page qui n'en veut pas. */
    display: none;
}

/* ==========================================================================
   14. Impression
   ========================================================================== */

@media print {
    .forum-theme,
    .page-forum--topic .reponse,
    .fil__ouverture,
    .profil {
        border: 1px solid #999;
        box-shadow: none;
        break-inside: avoid;
    }

    .page-forum--topic .reponse__meta[data-initiale]::before {
        content: none;
    }
}
