/* ==========================================================================
   Module V — mise en page de la vue du calendrier et de son interaction
   --------------------------------------------------------------------------
   POURQUOI CETTE FEUILLE EXISTE : le noyau ne fournit aucune mise en page pour
   le sélecteur de vue, la grille, la fiche agrandie ni la zone de message.
   Elle n'ajoute QUE cela.

   PE-06 (CONTRAT §6) — AUCUNE COULEUR NI AUCUN RAYON EN DUR : la couleur
   vient de var(--cal-couleur) et la forme de var(--cal-rayon), posées par
   /apparence.css depuis les réglages de l'administration. Changer de couleur
   ou de forme ne demande donc AUCUNE modification de ce fichier (F16).

   Les seules couleurs littérales employées sont des gris translucides
   rgba(128,128,128, …) et des surfaces système (Canvas / CanvasText) : elles
   ne portent aucune identité visuelle et n'entrent pas en concurrence avec la
   couleur réglée. Aucun code hexadécimal (mesure V8).
   ========================================================================== */

/* ==== 1. Cadre du module ==== */

.cal-module {
    /* Rien à imposer au noyau : le module s'insère dans .cal-contenu du layout. */
    margin: 0 auto;
    max-width: 1200px;
}

/* ==== 2. Sélecteur de vue (marqueurs FIGÉS .cal-vue-mois / .cal-vue-annee) ==== */

/* CE QUE CE BLOC NE FAIT PAS : il ne pose ni fond, ni bordure, ni couleur de
   texte sur les deux commandes. L'habillage des commandes appartient au lot D
   (public/assets/apparence.css), chargé à part et qui les dessine déjà. Ne
   garder ici que la géométrie évite que deux feuilles se disputent l'aspect :
   la règle de tolérance du CONTRAT §1 reste tenue, le sélecteur restant lisible
   et cliquable même sans la feuille de D. */

.cal-barre {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.5rem;
}

.cal-selecteur {
    display: inline-flex;
    gap: 0.25rem;
    padding: 0.2rem;
    border-radius: var(--cal-rayon);
    background: rgba(128, 128, 128, 0.14);
}

.cal-vue {
    font: inherit;
    line-height: 1.2;
    padding: 0.4rem 1rem;
    cursor: pointer;
    border-radius: var(--cal-rayon);
}

.cal-vue:focus-visible {
    outline: 2px solid var(--cal-couleur);
    outline-offset: 2px;
}

/* La commande active : c'est ici que la couleur réglée se voit (F16).
   Double crochet — la classe ET aria-pressed — pour que l'état actif soit vrai
   à l'œil comme pour un lecteur d'écran. La feuille de D reconnaît le même
   marqueur (aria-pressed) et le conteneur #calendrier[data-vue=…] : les deux
   lectures concordent, l'habillage ne dépend donc pas de l'ordre de chargement. */
.cal-vue--actif,
.cal-vue[aria-pressed='true'] {
    background: var(--cal-couleur);
    color: rgba(255, 255, 255, 0.98);
}

/* ==== 3. Grille FullCalendar : habillage par les variables du contrat ==== */

/* POURQUOI ICI ET PAS SUR ;root : FullCalendar lit ses variables sur l'élément
   et ses descendants. Les poser sur le conteneur de la grille évite de toucher
   aux autres composants de la page.
   SEULES les variables qui attachent la grille à --cal-couleur (F16) sont
   posées : les bordures, fonds et la case du jour restent à la feuille de D,
   qui les tient de sa propre palette. */
.cal-grille {
    /* Pastilles : couleur réglée (F16). */
    --fc-event-bg-color: var(--cal-couleur);
    --fc-event-border-color: var(--cal-couleur);
    --fc-event-text-color: rgba(255, 255, 255, 0.98);
    /* Boutons de navigation et barre d'outils : couleur réglée (F16). */
    --fc-button-text-color: rgba(255, 255, 255, 0.98);
    --fc-button-bg-color: var(--cal-couleur);
    --fc-button-border-color: var(--cal-couleur);
    --fc-button-hover-bg-color: var(--cal-couleur);
    --fc-button-hover-border-color: var(--cal-couleur);
    --fc-button-active-bg-color: var(--cal-couleur);
    --fc-button-active-border-color: var(--cal-couleur);
}

/* Le rayon suit la forme réglée (F16). Les sélecteurs portent #calendrier : la
   feuille de FullCalendar est injectée par son script APRÈS nos <link>, donc à
   spécificité égale c'est elle qui gagnerait sans cette précision. */
#calendrier .fc-button {
    border-radius: var(--cal-rayon);
    text-transform: none;
    letter-spacing: 0.01em;
    font-size: 0.85rem;
    padding: 0.3rem 0.7rem;
}

#calendrier .fc-scrollgrid {
    border-radius: var(--cal-rayon);
}

#calendrier .fc-toolbar-title {
    font-size: 1.15rem;
    font-weight: 700;
}

/* En vue annuelle les mois sont denses : le titre du mois reste lisible sans
   écraser les cases. */
#calendrier .fc-multimonth-title {
    font-size: 0.95rem;
    font-weight: 700;
}

/* ==== 4. Pastille d'évènement (marqueur FIGÉ .cal-pastille) ==== */

#calendrier .cal-pastille {
    border: none;
    border-radius: var(--cal-rayon);
    font-weight: 600;
    /* Curseur : le glisser-déposer est ouvert (F8). La décision d'accepter le
       déplacement n'est pas ici, elle est côté serveur (CONTRAT §4). */
    cursor: grab;
}

#calendrier .cal-pastille:active {
    cursor: grabbing;
}

/* ==== 4 bis. Zoom de la case du jour au survol d'un évènement (F26) ==== */

/* DÉCISION DE NORBERT (05/10/2026) : le zoom porte sur la CASE DU JOUR, pas sur
   la carte de l'évènement. La classe .cal-case-zoomee est posée et retirée par
   /assets/calendrier.js ; la feuille ne fait que la dessiner.

   POURQUOI « transform » ET NON PAS UNE TAILLE : une transformation ne touche
   PAS à la mise en page. La case grandit à l'écran sans que la grille se
   réorganise, sans déplacer une case voisine et sans ajouter de barre de
   défilement — mesuré sur la page servie, largeur de page identique avant et
   après. Une largeur ou une hauteur auraient, elles, bougé toute la colonne :
   c'est précisément le décalage à éviter.

   Le geste reste purement visuel : la règle ne pose ni pointeur, ni commande,
   ni écouteur — le tactile et les clics ne sont donc pas touchés (F26). */

/* LOT W1 (06/10/2026) — LA CIBLE DU TRANSFORM A CHANGÉ, ET POURQUOI : le zoom
   portait sur la cellule de tableau (.fc-daygrid-day, « display: table-cell »).
   Mesuré : Chromium l'applique, mais une cellule de tableau n'est pas, selon les
   moteurs, un support de transformation fiable — d'où un effet qui marche dans
   un navigateur et pas dans un autre. L'agrandissement est donc porté par le
   CADRE INTERNE de la case (.fc-daygrid-day-frame), un bloc ordinaire, mesuré
   170 × 78 px dans la case 171 × 79. La classe reste posée sur la CASE : c'est
   elle qui porte la logique et le plan de superposition.
   Seule la valeur littérale mesurée sur ce banc (Chromium) a pu être éprouvée ;
   le choix de la cible, lui, ne se réclame d'aucune mesure hors de ce moteur. */

/* La transition est posée sur le CADRE, hors de la classe : elle joue donc dans
   les deux sens, à l'agrandissement comme au retour. Durée inchangée (0,25 s). */
#calendrier .fc-daygrid-day-frame {
    transition: transform 0.25s ease;
}

/* La CASE porte la classe et le PLAN DE SUPERPOSITION. La case agrandie déborde
   d'environ 5,5 % : elle doit passer AU-DESSUS de ses voisines, sinon celles-ci
   sont peintes après elle et rognent le débordement. « position: relative » et
   « z-index » ne déplacent rien (aucun effet sur la mise en page).
   AUCUN « transform » sur cette cellule : c'est tout l'objet du LOT W1. */
#calendrier .fc-daygrid-day.cal-case-zoomee {
    position: relative;
    z-index: 5;
}

/* L'agrandissement lui-même, sur le cadre interne : 1,055 (5,5 %, fourchette
   demandée de 5 à 6 %), même durée de transition qu'avant. */
#calendrier .fc-daygrid-day.cal-case-zoomee .fc-daygrid-day-frame {
    transform: scale(1.055);
}

/* ==== 5. Fiche agrandie (marqueurs FIGÉS .cal-fiche et enfants) ==== */

/* ANIMATION (F6) : la fiche est TOUJOURS dans le document, à sa place finale,
   et c'est une transition CSS qui la fait apparaître et disparaître. Insérer
   un élément juste avant de l'afficher ne s'anime pas : d'où cet élément
   permanent, réduit à l'état invisible (visibility + opacity), que la classe
   .cal-fiche--visible relève. Durée strictement positive, mesurée (V4). */
.cal-fiche {
    position: fixed;
    z-index: 40;
    left: 0;
    top: 0;
    max-width: min(22rem, 86vw);
    padding: 0.75rem 0.9rem;
    border: 1px solid rgba(128, 128, 128, 0.35);
    border-radius: var(--cal-rayon);
    background: Canvas;
    color: CanvasText;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px) scale(0.97);
    /* PAS DE CLIC SUR LA FICHE (X1, écart 2) : quand la fenêtre est courte,
       positionner() place la fiche AU-DESSUS de la pastille et elle la recouvre
       entièrement. Avec pointer-events:auto, c'est la fiche qui recevait le clic
       et la modale d'édition ne s'ouvrait jamais (mesuré : 1280×577). La fiche
       reste donc transparente aux évènements de pointeur, à l'état caché COMME à
       l'état visible ; seul son lien se rend cliquable (règle .cal-fiche-lien). */
    pointer-events: none;
    transition:
        opacity 0.22s ease,
        transform 0.22s ease,
        visibility 0s linear 0.22s;
}

.cal-fiche--visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
    /* pointer-events reste « none » (hérité de .cal-fiche) : c'est tout l'objet
       de la correction X1. Le passage à l'état visible ne doit PAS attendre : le
       délai de sortie ci-dessus ne s'applique qu'à la disparition. */
    transition:
        opacity 0.22s ease,
        transform 0.22s ease,
        visibility 0s linear 0s;
}

.cal-fiche-titre {
    margin: 0 0 0.25rem;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.25;
    /* Filet de gauche à la couleur réglée : la fiche appartient au même
       vocabulaire visuel que la grille (F16). */
    border-left: 3px solid var(--cal-couleur);
    padding-left: 0.5rem;
}

.cal-fiche-date {
    display: block;
    margin: 0 0 0.4rem 0.5rem;
    font-size: 0.82rem;
    text-transform: capitalize;
    opacity: 0.85;
}

.cal-fiche-description {
    margin: 0;
    font-size: 0.88rem;
    line-height: 1.4;
}

.cal-fiche-image {
    display: block;
    width: 100%;
    height: auto;
    margin-top: 0.55rem;
    border-radius: var(--cal-rayon);
    /* LA BORNE DE HAUTEUR DE L'IMAGE N'EST PAS ICI (LOT W1). Mesuré sur la page
       servie, fenêtre 1280 × 577 : l'image est bornée par le module D
       (/assets/apparence.css, règle « #calendrier .cal-fiche-image », spécificité
       supérieure) à « max-height: 190px » avec « object-fit: cover » — le style
       calculé de l'image rend bien 190 px quoi qu'écrive cette feuille. Une
       seconde borne posée ici serait donc sans effet, et deux feuilles qui se
       disputent la même propriété finissent par diverger en silence : la place de
       l'image reste l'affaire de D, le PLACEMENT de la fiche reste celle de V
       (mesure après chargement, voir /assets/calendrier.js). */
}

/* IMAGE CLIQUABLE (F27) — l'image est enveloppée par une ancre (.cal-fiche-image-lien)
   posée par la vue. La boîte de l'ancre est un BLOC, comme l'image qu'elle
   contient : la mise en page de la fiche est exactement celle d'avant, l'image
   gardant ses propres marges et son propre rayon. */
#calendrier .cal-fiche-image-lien,
.cal-fiche-image-lien {
    display: block;
}

/* ==== 5 bis. Place de l'image PENDANT son chargement (LOT W2, corrigé LOT W4) ==== */

/* POURQUOI CETTE RÈGLE EXISTE — MESURÉ, PAS SUPPOSÉ (banc, fenêtre 1280 × 577,
   réseau bridé, cache vidé, <img> vierge) : une image déclarée mais pas encore
   chargée occupe ZÉRO pixel. La fiche est donc placée sur une hauteur trop
   petite, puis saute quand l'image arrive ; et quand l'image est refusée (un
   429 suffit — la cadence de l'hébergeur est limitée), elle ne prend jamais sa
   place et l'image ne s'affiche pas du tout. C'était le symptôme rapporté par
   Norbert : « je n'ai pas l'affichage de l'image ».

   LA PLACE EST TENUE D'AVANCE par cette règle, le temps du chargement (le script
   pose puis retire l'attribut data-image-en-attente). Elle porte sur la BOÎTE DE
   L'ANCRE, qui appartient à ce module ; le module D (/assets/apparence.css)
   reste seul maître de la hauteur de l'image.

   LOT W4 — LA RÉSERVE VAUT LA HAUTEUR RÉELLEMENT APPLIQUÉE, PLUS UN RATIO.
   La version W2 réservait un « aspect-ratio: 3 / 2 » borné à 190 px : pour une
   fiche de 246 px (celle de l'évènement de PRODUCTION, mesuré 243,1 px par le
   contrôle P7-C), la place valait 143,5 px alors que l'image en occupe 190 —
   la fiche gagnait 46,5 px et se replaçait sous le curseur (production : 48,5 px,
   contrôle P7-C § 3.1). La réserve vaut donc désormais EXACTEMENT la hauteur que
   le module D applique à l'image, lue dans le POINT UNIQUE défini par D
   (--cal-fiche-image-hauteur : 190 px, 150 px sur téléphone). Une seule valeur,
   deux lectures : la fiche ne bouge plus du tout. Le repli « 190px » couvre le
   cas, prévu au CONTRAT § 1, où D ne serait pas livrée. */
#calendrier .cal-fiche-image-lien[data-image-en-attente],
.cal-fiche-image-lien[data-image-en-attente] {
    height: var(--cal-fiche-image-hauteur, 190px);
    background: var(--app-fond-doux, rgba(128, 128, 128, 0.12));
    border-radius: var(--cal-rayon);
}

/* SEULE une ancre QUI PORTE UNE ADRESSE reçoit le clic (X1, écart 2 + F27) :
   la fiche est transparente au pointeur, et seuls ses éléments cliquables y
   échappent — le lien du texte et cette ancre d'image. Une image sans « lien »
   renseigné n'a pas d'« href » : elle reste alors invisible au pointeur, donc
   jamais une zone cliquable morte. Rien d'autre dans la fiche n'est cliquable
   (la règle est portée par la présence de href, pas par la classe seule). */
#calendrier .cal-fiche-image-lien[href],
.cal-fiche-image-lien[href] {
    pointer-events: auto;
    cursor: pointer;
}

/* EN MODE ADMINISTRATION, L'IMAGE RESTE TRANSPARENTE AU POINTEUR (F27).
   POURQUOI CETTE EXCEPTION, ET POURQUOI ELLE EST MESURÉE : la fiche agrandie
   peut recouvrir la pastille survolée (l'image lui donne 360 px de haut dans une
   fenêtre courte). Rendue cliquable, l'image y intercepte alors le geste de
   l'administration — mesuré : « elementFromPoint » au centre de la pastille
   renvoyait .cal-fiche-image, le glisser-déposer ne partait plus, et un clic
   aurait quitté la page au lieu d'ouvrir la modale d'édition (F20). Les gestes
   d'administration gardent donc la priorité : l'image reste VISIBLE et son ancre
   garde son adresse, elle ne reçoit simplement pas le clic.
   Le lien du texte n'est pas touché : sa cliquabilité est un acquis du lot X1.
   L'attribut interrogé est celui que le SERVEUR écrit sur .cal-module (vue) et
   que le script réaccorde : la règle tient même si le script ne tourne pas. */
#calendrier .cal-module[data-mode-administration='oui'] .cal-fiche-image-lien,
#calendrier .cal-module[data-mode-administration='oui'] .cal-fiche-image-lien[href] {
    /* Rien d'autre à écrire : « pointer-events: none » suffit pour que le
       curseur et les gestes redeviennent ceux de la pastille située dessous
       (« grab », glisser-déposer, clic d'édition). */
    pointer-events: none;
}

.cal-fiche-lien {
    display: inline-block;
    margin-top: 0.55rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--cal-couleur);
    /* SEUL élément de la fiche qui reçoit le clic (X1, écart 2) : sans cela, la
       correction qui rend la fiche transparente au pointeur rendrait aussi le
       lien de l'article inatteignable. À l'état caché il reste inerte, car il
       hérite de « visibility: hidden » posé sur .cal-fiche. */
    pointer-events: auto;
}

/* Un élément absent ne doit occuper NI place NI contenu (pas de trou dans la
   fiche quand l'évènement n'a pas d'image ou de lien).

   POURQUOI LA DOUBLE ÉCRITURE : le layout charge aussi la feuille de D
   (public/assets/apparence.css), qui pose un « display » sur ces trois
   marqueurs. Or une règle d'auteur bat toujours la règle du navigateur qui
   cache un élément porteur de l'attribut hidden : sans ces règles, un lien
   absent s'afficherait quand même (mesuré). Les sélecteurs préfixés par
   #calendrier passent au-dessus de ceux de D ; les sélecteurs nus suffisent
   quand D n'est pas livrée (règle de tolérance du CONTRAT §1). */
#calendrier .cal-fiche-image[hidden],
#calendrier .cal-fiche-image-lien[hidden],
#calendrier .cal-fiche-lien[hidden],
#calendrier .cal-fiche-description[hidden],
.cal-fiche-image[hidden],
.cal-fiche-image-lien[hidden],
.cal-fiche-lien[hidden],
.cal-fiche-description[hidden],
.cal-message[hidden],
#calendrier .cal-message[hidden] {
    display: none;
}

/* ==== 6. Zone de message (F9) ==== */

.cal-message {
    margin: 0.6rem 0 0;
    padding: 0.5rem 0.75rem;
    border-left: 4px solid var(--cal-couleur);
    border-radius: var(--cal-rayon);
    background: rgba(128, 128, 128, 0.14);
    font-size: 0.9rem;
}

/* Un refus est un échec : il se distingue par la graisse et le filet, sans
   introduire de seconde couleur d'identité dans la page. */
.cal-message--refus {
    font-weight: 700;
}

/* ==== 7. Petits écrans ==== */

@media (max-width: 640px) {
    .cal-barre {
        justify-content: stretch;
    }

    .cal-selecteur {
        width: 100%;
    }

    .cal-vue {
        flex: 1;
    }

    .cal-fiche {
        max-width: 92vw;
    }
}

/* ==== 8. Vue « Liste » (F28, LOT W2) ==== */

/* La vue « Liste » remplace la grille : elle est rendue par le SERVEUR, le
   script ne fait que l'afficher ou la cacher. La classe cal-zone--liste est
   posée sur .cal-zone par le serveur (premier rendu) comme par le script
   (changement de vue) : les deux chemins aboutissent au même HTML, ce que la
   mesure vérifie sur la page servie puis après un clic. */
.cal-zone--liste .cal-grille,
.cal-zone--liste .cal-fiche {
    display: none;
}

/* Un élément en attente ne doit occuper NI place NI contenu : l'attribut
   « hidden », écrit par le serveur au premier rendu et par le script ensuite,
   est donc rendu explicite. C'est la leçon du lot V : une règle d'auteur bat
   toujours celle du navigateur qui cache un élément porteur de « hidden » — la
   feuille du module D pose un « display » sur plusieurs marqueurs. */
#calendrier .cal-liste[hidden],
.cal-liste[hidden] {
    display: none;
}

.cal-liste {
    margin: 0.8rem 0 0;
}

.cal-liste-evenement {
    padding: 0.75rem 0;
    border-top: 1px solid rgba(128, 128, 128, 0.25);
}

.cal-liste-date {
    display: block;
    font-size: 0.82rem;
    text-transform: capitalize;
    opacity: 0.85;
}

.cal-liste-titre {
    margin: 0.15rem 0 0.4rem;
    font-size: 1rem;
    line-height: 1.25;
    /* Même vocabulaire visuel que la fiche : filet à la couleur réglée. */
    border-left: 3px solid var(--cal-couleur);
    padding-left: 0.5rem;
}

/* Le titre mène à l'article (demande du 30/10/2026). L'ancre prend la couleur
   et la graisse du titre qu'elle habite — elle ne doit pas ressembler à un lien
   de texte ordinaire au repos — et ne se signale qu'au survol et au clavier.
   Seule une ancre PORTANT une adresse est ainsi traitée : sans lien, le titre
   reste un titre, sans curseur ni soulignement. */
.cal-fiche-titre-lien,
.cal-liste-titre-lien {
    color: inherit;
    font: inherit;
    text-decoration: none;
}

.cal-fiche-titre-lien[href],
.cal-liste-titre-lien[href] {
    cursor: pointer;
}

/* La fiche est transparente au pointeur (X1) : son titre cliquable doit donc
   demander explicitement le clic, comme l'ancre d'image et le lien du texte.
   La règle est portée par la présence de « href » — un titre sans adresse reste
   inerte, et ne fait pas obstacle aux gestes de la grille en dessous. */
.cal-fiche-titre-lien[href] {
    pointer-events: auto;
}

/* TOUTE LA FICHE MÈNE À L'ARTICLE (demande du 30/10/2026). L'ancre du titre
   étend sa zone de clic à la surface entière de la fiche : un clic n'importe où
   dans la popup ouvre le lien, comme un clic sur l'image ou sur la case.
   C'est un pseudo-élément de l'ancre : il n'existe que si l'ancre PORTE une
   adresse, et il tombe avec elle en mode administration (l'ancre y est déjà
   transparente au pointeur, donc son tapis aussi). La fiche reste
   « position: fixed » : elle est le repère du tapis, rien à changer au flux. */
.cal-fiche-titre-lien[href]::after {
    content: '';
    position: absolute;
    inset: 0;
}

/* EN MODE ADMINISTRATION, MÊME EXCEPTION QUE L'IMAGE (F27) : la fiche agrandie
   peut recouvrir la pastille survolée ; le titre cliquable y intercepterait le
   glisser-déposer de la pastille (mesuré sur l'image : « elementFromPoint » au
   centre de la pastille renvoyait l'élément de la fiche). L'administration garde
   donc la priorité : le titre reste visible et garde son adresse, sans recevoir
   le clic. L'attribut interrogé est écrit par le serveur ET réaccordé par le
   script : la règle tient même si le script ne tourne pas. */
#calendrier .cal-module[data-mode-administration='oui'] .cal-fiche-titre-lien,
#calendrier .cal-module[data-mode-administration='oui'] .cal-fiche-titre-lien[href] {
    pointer-events: none;
    cursor: auto;
}

.cal-fiche-titre-lien[href]:hover,
.cal-fiche-titre-lien[href]:focus-visible,
.cal-liste-titre-lien[href]:hover,
.cal-liste-titre-lien[href]:focus-visible {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 2px;
}

.cal-liste-description {
    margin: 0 0 0.5rem;
    font-size: 0.9rem;
    line-height: 1.45;
}

/* L'image de la liste : largeur bornée et hauteur bornée, comme dans la fiche
   (même valeur que le module D, 190 px) — la liste est écrite par ce module de
   bout en bout, il n'y a donc ici personne avec qui se disputer la propriété.
   `object-fit: cover` est INDISPENSABLE dès que la largeur est imposée et la
   hauteur bornée : sans lui, la photo serait déformée. Le fond neutre sert de
   cadre d'attente, et « loading=lazy » (posé par la vue) évite de demander
   toutes les images d'un coup — la cadence de l'hébergeur est limitée. */
.cal-liste-image {
    display: block;
    width: 100%;
    max-width: 22rem;
    height: auto;
    max-height: 190px;
    object-fit: cover;
    margin: 0 0 0.5rem;
    border-radius: var(--cal-rayon);
    background: var(--app-fond-doux, rgba(128, 128, 128, 0.12));
}

.cal-liste-lien {
    display: inline-block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--cal-couleur);
}

.cal-liste-vide {
    margin: 0.75rem 0 0;
    font-size: 0.9rem;
    opacity: 0.85;
}

@media (max-width: 640px) {
    .cal-liste-image {
        max-width: 100%;
    }
}
