/* =================================================================
   Youen Frémont — Tablette et au-delà : mises en page larges, planches à l'horizontale
   Feuille 7 sur 8. La feuille unique a été découpée le 2026-09-19 aux
   frontières de ses sections, sans qu'une règle ne change de place : les huit
   fichiers se chargent dans l'ordre de base.njk, et cet ordre EST la cascade.
   Les tokens et les surfaces vivent dans style.css, chargée en premier.
   ================================================================= */

/* -----------------------------------------------------------------
   Tablette et au-delà
   ----------------------------------------------------------------- */
/* Sous 34 em, les paires ville / rôles et mentions / retour en haut se serrent
   trop pour rester aux deux bords : elles s'empilent, centrées. */
@media (max-width: 33.999em) {
  .hero__pied,
  .pied__barre {
    flex-direction: column;
    align-items: center;
    gap: var(--pas-2);
    text-align: center;
  }

  /* Le pied du hero empilé fait deux lignes centrées au lieu d'une : il monte,
     et la flèche tombait dessus — sur « FRANCE », exactement au centre. Elle se
     relève de la hauteur qu'il vient de prendre. Constaté à 375 px le
     2026-09-02. */
  .hero__invite {
    bottom: calc(var(--pas-5) + var(--pas-8));
  }
}

@media (min-width: 48em) {
  .grille-projets {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* La vitrine passe en deux colonnes : l'intitulé à gauche, le cadre à droite.
     Plus rien de collant — le cadre tient dans l'écran (plafonné dans
     projets.css depuis le 2026-09-20) et défile de lui-même, il n'y a donc
     aucune course à suivre. Les deux colonnes se centrent l'une sur l'autre,
     comme la référence. */
  .section-projets:has(.vitrine) {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    gap: var(--pas-7);
    align-items: center;
  }

  .section-projets:has(.vitrine) .entete-section {
    margin-bottom: 0;
  }

  /* La carte n'est plus qu'une photo : son titre et son année sont dans la
     colonne de gauche. Ils restent dans le HTML — le lien couvre toujours toute
     la carte et les lecteurs d'écran ont toujours de quoi la nommer —, ils ne
     sont qu'invisibles à l'œil. */
  .vitrine__liste .carte-projet__legende {
    opacity: 0;
  }

  /* Au focus clavier, la légende revient. Sans cette règle, l'anneau de focus
     du lien serait dessiné sur un élément transparent, donc invisible : on
     tabulerait dans la vitrine sans jamais savoir où l'on est. */
  .vitrine__liste .carte-projet:focus-within .carte-projet__legende {
    opacity: 1;
  }

  .section-contact__corps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--pas-7);
  }

  /* Le visuel se contente de ses 16/9 tant qu'il est le plus haut des deux ;
     dès que la liste le dépasse, ce minimum le fait descendre jusqu'en bas —
     sans lui, la proportion l'emporterait sur l'étirement et il resterait
     court. L'image est recadrée, jamais déformée : elle est en object-fit. */
  .section-contact__visuel {
    min-height: 100%;
  }

  .section-projets {
    padding-block: var(--pas-9) var(--pas-8);
  }
}

/* -----------------------------------------------------------------
   Page projet : le passage à l'horizontale.
   Dès la tablette, le document ne défile plus — c'est la suite de planches qui
   défile, latéralement. En dessous, sur téléphone, rien de tout ceci ne
   s'applique : les planches restent empilées et la page se lit comme les autres.
   ----------------------------------------------------------------- */
@media (min-width: 48em) {
  body:has(.planches) {
    overflow: hidden;
  }

  /* Sans script, le document doit pouvoir défiler : le menu est rendu en liste
     sous la bande, et sans cette règle il restait exactement sous le bord bas de
     l'écran, hors d'atteinte — ni la molette ni le lien « Menu » n'y menaient,
     mesuré le 2026-09-19. Avec script, le menu est une modale et rien ne
     change. */
  html:not(.js) body:has(.planches) {
    overflow: auto;
  }

  /* Chaque planche est un écran neuf qui réserve la hauteur de l'en-tête : rien
     ne passe plus dessous, le voile n'a plus rien à séparer. */
  .entete--planches::before {
    display: none;
  }

  .planches {
    display: flex;
    height: 100dvh;
    overflow-x: auto;
    overflow-y: hidden;
    /* Aucun calage : on s'arrête où l'on veut, entre deux planches comprises.
       Un calage, même souple, ramenait chaque avance au bord le plus proche et
       interdisait de rester à cheval sur deux images. */
    overscroll-behavior-x: contain;
  }

  /* Aucune planche n'est une zone de défilement verticale, et c'est ce qui fait
     marcher la molette sans une ligne de script : un navigateur ne reporte le
     geste vertical sur l'axe horizontal que si l'élément sous le pointeur ne
     peut pas défiler verticalement. Avec overflow-y: auto, chaque planche
     prenait le geste et le gardait, sans avoir rien à en faire.
     « clip » et non « hidden » : hidden en fait malgré tout une zone de
     défilement, que le script peut déplacer et que le navigateur doit
     considérer. clip n'en fait pas une du tout. */
  .planche {
    flex: 0 0 100%;
    height: 100%;
    overflow-y: clip;
  }

  /* Seule exception, la landing : ses crédits peuvent dépasser d'un écran peu
     haut, et elle est la seule planche qui contienne du texte suivi. Elle garde
     donc sa course verticale — le geste y descend le texte, puis passe aux
     planches une fois le bas atteint. */
  .planche--landing {
    overflow-y: auto;
  }

  /* Le titre déborde : la planche prend la largeur qu'il lui faut, et le premier
     geste en découvre la fin. */
  .planche--titre {
    flex: 0 0 auto;
    width: max-content;
    min-width: 100%;
    /* À cette taille et avec un interlignage serré, les jambages débordent de
       la boîte de ligne. « clip » et non « hidden » : hidden laisse une zone de
       défilement, que le navigateur doit considérer avant de reporter le geste
       sur l'axe horizontal. clip n'en laisse aucune. */
    overflow-y: clip;
  }

  .planche-titre__texte {
    font-size: var(--texte-planche-titre);
    line-height: 0.8;
    white-space: nowrap;
  }

  /* L'indice reste au coin de l'écran d'arrivée, quelle que soit la largeur
     prise par le titre — et la flèche change de sens avec le geste. */
  .planche-titre__indice {
    position: absolute;
    bottom: var(--pas-5);
    left: var(--marge-page);
    margin-top: 0;
  }

  .planche-titre__indice::after {
    content: " →";
  }

  /* Deux colonnes dès que la page passe à l'horizontale, tablette comprise :
     le texte et les crédits à gauche, le visuel jusqu'aux bords à droite. */
  .planche--landing {
    display: grid;
    grid-template-columns: minmax(0, 38%) 1fr;
    /* Même plancher que les planches de visuels, et pour la même raison : le
       minimum d'une rangée automatique est la hauteur intrinsèque de l'image.
       Sans lui, une ouverture en portrait — 800 × 1 000 étalés sur 62 % de la
       largeur — réclamait 1 116 px de rangée dans une planche de 900, et la
       course verticale de la landing devenait une barre de défilement. Les
       ouvertures étaient toutes en paysage jusqu'ici : le défaut dormait. */
    grid-template-rows: minmax(0, 1fr);
  }

  .landing__texte {
    /* « safe » : quand le texte est plus haut que la planche — crédits longs sur
       un écran peu haut —, le centrage rognerait le haut, hors d'atteinte même
       en défilant. Le mot rend alors la main au calage en haut. */
    align-self: safe center;
    padding-block: var(--hauteur-entete) var(--pas-6);
  }

  /* La colonne borne déjà la mesure du texte. */
  .projet__texte {
    max-width: none;
  }

  /* Le visuel monte jusqu'aux bords de la planche. */
  .landing__visuel:empty {
    aspect-ratio: auto;
  }

  /* Les visuels remplissent leur planche, jusqu'aux quatre bords.
     minmax(0, 1fr) et non 1fr : le minimum d'une rangée automatique est la
     hauteur intrinsèque de l'image, qui se compte en milliers de pixels. Sans
     ce plancher à zéro, la première rangée mange toute la planche. */
  .planche--visuels {
    grid-auto-rows: minmax(0, 1fr);
  }

  .planche--visuels picture {
    display: block;
    min-height: 0;
  }

  /* Un cadre recadré reste étiré par sa cellule là où la disposition rogne —
     duo, trio, grille, pile, duo-large : c'est elle qui commande sa forme, et
     l'image la remplit en `cover` comme avant. Il faut le dire : un élément
     qui porte une forme ne s'étire plus par défaut dans une grille — `normal`
     y vaut `start` —, et le cadre prendrait alors la forme de la photo, haut
     comme trois rangées. Les dispositions où l'image porte son bloc écrasent
     ceci plus bas, avec un centrage ou un coin. */
  .planche--visuels > .visuel-cadre {
    place-self: stretch;
  }

  /* La planche est déclarée conteneur pour que `cqh` — l'unité de la taille
     d'une photo sur la planche, écrite par cadres.js — parle bien de la planche
     et non de la cellule. Sans effet sur sa propre taille : à l'horizontale,
     elle la tient déjà de son parent, pas de son contenu. Ne vaut qu'ici, où
     les planches ont une hauteur : en colonne, le conteneur n'aurait plus de
     hauteur à donner et couperait la sienne. */
  .planche--visuels {
    container-type: size;
  }

  .planche--visuels img {
    height: 100%;
    object-fit: cover;
  }

  /* Une image seule est montrée entière, dans ses proportions : un scope garde
     ses bandes noires plutôt que d'être recadré. Sauf recadrage libre : celui-ci
     dit qu'on ne veut qu'une part de l'image, et rogner est alors le sujet. */
  .planche--pleine img:not([data-cadre]),
  .planche--scope img:not([data-cadre]),
  .planche--legende img:not([data-cadre]) {
    object-fit: contain;
  }

  /* Le cadre d'une image recadrée se dimensionne lui-même : sa forme, dans la
     place que lui laisse la planche. Étiré, il ne pourrait pas la tenir — deux
     dimensions imposées ne laissent aucune part au rapport. */
  .planche--pleine .visuel-cadre,
  .planche--scope .visuel-cadre,
  .planche--legende .visuel-cadre {
    /* Largeur en `auto` et non « celle de l'image » : voir le pseudo-élément
       plus bas. Un cadre qui se mesurerait à son image ne se mesurerait à rien
       tant qu'elle n'est pas chargée — et une image paresseuse dans une boîte
       de zéro n'est jamais visible, donc jamais chargée. Le cercle se ferme, le
       cadre reste à zéro. Mesuré dans la table de montage le 2026-09-11. */
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    place-self: center;
  }

  /* --- La taille d'une photo sur la planche --------------------------------
     `tailles:` du bloc, un nombre par image : la hauteur que son cadre prend,
     en part de la hauteur de planche. Ce n'est pas le zoom — lui agrandit ce
     qu'on voit DANS le cadre, la taille agrandit le cadre SUR la planche.
     Vaut pour toutes les dispositions : dans un duo ou une grille, le cadre
     prend alors la forme de la photo au milieu de sa cellule, l'aplat autour,
     là où sans réglage il la remplirait bord à bord. La hauteur et la forme
     sont écrites par emplacement dans le bloc <style> de la page ; ce qui reste
     ici, c'est que le cadre se dimensionne lui-même et ne déforme jamais — si
     la largeur bute sur la cellule, c'est elle qui commande. */
  .planche--visuels > .visuel-taille {
    /* La largeur en `auto`, plafonnée à celle qu'écrit cadres.js et à la
       cellule ; la hauteur suit par la forme, et si c'est elle qui bute — 90 %
       de planche dans une grille à deux rangées — sa limite se reporte sur la
       largeur à travers la forme, parce que la largeur est `auto`. C'est ce
       transfert qui fait que rien n'est jamais rogné ni déformé, quelle que
       soit la contrainte qui mord. Mesuré : 90 % dans une grille donne
       247 × 370, au ratio exact de la photo. */
    width: auto;
    max-width: min(var(--visuel-largeur, 100%), 100%);
    height: auto;
    max-height: 100%;
    place-self: center;
  }

  /* Un cadre dont la largeur est `auto` se mesure à son contenu — et son
     contenu est une image à 100 %, qui ne pèse rien tant qu'elle n'est pas
     chargée : le cadre resterait à zéro, la page sauterait à l'arrivée de
     chaque photo. Ce pseudo-élément sans hauteur lui donne une largeur
     intrinsèque plus grande que tout, que le plafond ramène aussitôt à la
     bonne : le cadre a sa taille avant la première image. */
  .planche--visuels > .visuel-cadre::before,
  .planche--visuels > .visuel-taille::before {
    content: "";
    display: block;
    width: 100vw;
    height: 0;
  }

  /* Deux images de poids inégal : l'une porte la planche, l'autre lui répond.
     C'est la seule différence avec le duo, qui les traite à égalité.
     `miroir` renvoie la dominante de l'autre côté — un seul champ à basculer au
     lieu d'une seconde disposition à nommer. */
  .planche--duo-large {
    grid-template-columns: minmax(0, 62%) minmax(0, 1fr);
  }

  .planche--duo-large.planche--miroir {
    grid-template-columns: minmax(0, 1fr) minmax(0, 62%);
  }

  /* La rangée est nommée en même temps que la colonne, et ce n'est pas
     décoratif : avec la seule colonne, le placement automatique renvoie la
     seconde image à la rangée suivante — la place de la colonne 1 est déjà
     passée quand il l'examine. Les deux images s'empilaient. */
  .planche--duo-large.planche--miroir > :nth-child(1) { grid-area: 1 / 2; }
  .planche--duo-large.planche--miroir > :nth-child(2) { grid-area: 1 / 1; }

  /* Deux images l'une sous l'autre, à parts égales : la planche des formats
     larges, où deux images côte à côte deviendraient étroites. C'est l'exacte
     contrepartie du duo, en hauteur. `miroir` échange les deux. */
  .planche--pile {
    grid-template-rows: repeat(2, minmax(0, 1fr));
  }

  .planche--pile.planche--miroir > :nth-child(1) { grid-row: 2; }
  .planche--pile.planche--miroir > :nth-child(2) { grid-row: 1; }

  /* L'image prend toute la planche moins la ligne de légende, qui se réserve
     sa hauteur propre — d'où auto, et non une seconde rangée à parts égales.
     `miroir` remonte la légende au-dessus de l'image. */
  .planche--legende {
    grid-template-rows: minmax(0, 1fr) auto;
  }

  .planche--legende.planche--miroir {
    grid-template-rows: auto minmax(0, 1fr);
  }

  .planche--legende.planche--miroir > .planche-legende { grid-row: 1; }
  .planche--legende.planche--miroir > :is(picture, .cellule-extrait) { grid-row: 2; }

  /* Comme une image montrée entière : la vidéo occupe toute la planche et garde
     ses proportions, l'aplat remplit ce qui reste de part et d'autre.
     width et height à 100 %, et non auto : sur un élément remplacé, auto vaut la
     taille intrinsèque — celle de l'affiche tant que rien n'est chargé. La vidéo
     restait donc à la largeur de sa vignette, 800 px au milieu d'un écran. */
  /* Le bloc épouse l'extrait, et non la cellule : c'est l'extrait qui se
     tient dans la place disponible, dans ses proportions, et le bloc se
     resserre dessus — pour que le bouton de son se pose dans le vrai coin de
     l'image, demandé le 2026-09-15, et non dans celui d'une cellule où
     l'extrait flotte entre deux bandes. La hauteur disponible s'écrit en cqh,
     l'unité de la planche : la cellule n'a pas de hauteur à donner à un bloc
     qui se resserre. Sur un élément remplacé, deux plafonds — largeur et
     hauteur — se tiennent ensemble : c'est le « contain » de la feuille de
     style, sans object-fit. */
  /* Sélecteur à deux classes, exprès : en colonne, l'encart et la pile posent
     une largeur de 82 % avec la même spécificité, et elle l'emporterait sur un
     `.extrait` seul. */
  .planche--visuels .extrait {
    width: fit-content;
    height: fit-content;
    max-width: 100%;
    --extrait-hauteur: calc(100cqh - 2 * var(--planche-retrait));
  }

  .visuel-video {
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: var(--extrait-hauteur);
  }

  /* Un <video> ne peut pas tenir sa taille de son contenu. Tant que le clip
     n'est pas chargé — et il ne l'est qu'un écran à l'avance —, sa taille
     intrinsèque est celle de l'affiche, 800 px, et `auto` la lui donnait telle
     quelle au milieu de la planche, puis l'extrait sautait à sa vraie taille à
     l'arrivée du clip. Constaté le 2026-09-18 ; c'est précisément la règle de
     CLAUDE.md, section Vidéo, que le `width: auto` du 2026-09-15 avait
     enfreinte. Le confinement de taille lui retire toute taille intrinsèque,
     `contain-intrinsic-size` lui en prête une plus grande que tout, et les deux
     plafonds — largeur et hauteur — la ramènent dans la forme des attributs
     width et height, celle du relevé. Mesuré à 1440×810 sur Cœur Serré, avant
     chargement : 1215×810 en plein cadre, 826×551 en encart, au lieu de
     800×533. Sans `contain-intrinsic-size`, le confinement seul ferait une
     boîte de 300×150 : d'où le @supports, qui laisse aux navigateurs plus
     anciens le rendu d'avant. */
  @supports (contain-intrinsic-size: 1px) {
    .planche--visuels .visuel-video {
      contain: size;
      contain-intrinsic-size: 100vw 100vh;
    }
  }

  /* Un extrait dans une planche d'images — un duo, une pile, une grille qui
     mêlent photos et extraits, demandé le 2026-09-18. La cellule prend la place
     de l'image, exactement comme un <picture> : étirée par la grille, rognée
     par la disposition. L'extrait, lui, ne se rogne pas : il se tient entier
     dans la cellule, dans ses proportions, l'aplat autour. La cellule est
     déclarée conteneur pour que sa hauteur, en cqh, soit le plafond de
     l'extrait — comme la planche l'est pour une planche vidéo. Le confinement
     ne vaut qu'ici, à l'horizontale, où la grille donne sa hauteur à la
     cellule : en colonne elle n'en aurait aucune. */
  .cellule-extrait {
    display: grid;
    place-items: center;
    min-width: 0;
    min-height: 0;
    container-type: size;
  }

  .cellule-extrait .extrait {
    --extrait-hauteur: 100cqh;
  }

  /* En diagonale, la cellule tient le rôle de l'image nue : plafonnée en
     hauteur par le cran de `taille:`, rangée en haut d'un côté et en bas de
     l'autre — l'ancrage horizontal vient des règles de la diagonale, qui
     alignent le contenu de chaque case. */
  .planche--diagonale > .cellule-extrait {
    height: var(--planche-taille, var(--planche-taille-moyenne));
  }

  .planche--diagonale > .cellule-extrait:nth-child(1) { align-self: start; }
  .planche--diagonale > .cellule-extrait:nth-child(2) { align-self: end; }

  /* En encart : l'extrait est tenu en retrait, l'aplat fait marge de tous les
     côtés. Le contenant est borné en largeur ET en hauteur, l'extrait s'inscrit
     dedans dans ses proportions — un plan vertical y tient donc aussi bien qu'un
     16/9, là où le plein cadre le noierait entre deux bandes. */
  .planche--video-encart .extrait {
    max-width: 68%;
    --extrait-hauteur: calc(0.68 * (100cqh - 2 * var(--planche-retrait)));
  }

  /* En duo : deux extraits, chacun entier sur sa moitié de planche. Le même
     minmax(0, 1fr) que les images — sans plancher à zéro, la taille intrinsèque
     de la vidéo, qui se compte en milliers de pixels, ferait déborder la
     colonne. Centrés, et non étirés : le bloc épouse l'extrait, il n'a plus
     de bandes à remplir. */
  .planche--video-duo {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    place-items: center;
  }

  /* En pile : les deux extraits l'un sous l'autre, chacun en encart dans sa
     moitié de hauteur. C'est la planche des formats larges — deux 16/9 côte à
     côte deviennent étroits, empilés ils gardent leur largeur. */
  .planche--video-pile {
    grid-template-rows: repeat(2, minmax(0, 1fr));
  }

  /* Moins d'air qu'un encart simple, demandé le 2026-08-21 : deux extraits
     empilés se partagent déjà la hauteur, la marge se prend donc sur ce qui
     reste. La hauteur est le vrai plafond — un 16/9 dans une demi-planche ne
     peut pas dépasser deux fois sa moitié de hauteur, quelle que soit la
     largeur qu'on lui laisse. */
  .planche--video-pile .extrait {
    max-width: 96%;
    --extrait-hauteur: calc(0.98 * (100cqh - 2 * var(--planche-retrait) - var(--planche-ecart)) / 2);
  }

  .planche--duo {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .planche--trio {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* Deux images en haut, une plus large en dessous. `miroir` retourne la
     planche : la large passe en haut, les deux autres en dessous. */
  .planche--grille {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: minmax(0, 1fr) minmax(0, 1.15fr);
  }

  .planche--grille > :nth-child(3) {
    grid-column: 1 / -1;
  }

  .planche--grille.planche--miroir {
    grid-template-rows: minmax(0, 1.15fr) minmax(0, 1fr);
  }

  .planche--grille.planche--miroir > :nth-child(1) { grid-row: 2; }
  .planche--grille.planche--miroir > :nth-child(2) { grid-row: 2; }
  .planche--grille.planche--miroir > :nth-child(3) { grid-row: 1; }

  /* Deux images en diagonale. La disposition ne dit qu'une chose : où se pose
     chaque image — la première en haut d'un côté, la seconde en bas de
     l'autre. Elle ne dit rien de leur format. Chacune garde ses proportions
     d'origine et dessine son propre bloc : une verticale monte, une
     horizontale s'étale, et les deux se rangent par leur coin. Ce qui les borne
     n'est plus un cadre à remplir : la colonne en largeur, le cran de `taille:`
     en hauteur.
     La première image nommée est toujours celle du haut ; `miroir` ne fait que
     basculer le côté, pour qu'on puisse enchaîner deux planches sans répéter le
     même geste. C'est ce qui a remplacé `diagonale-inverse` le 2026-09-10 : une
     composition asymétrique et son reflet sont la même disposition, pas deux.
     Sur téléphone la planche retombe sur la colonne unique et les deux images
     s'empilent, comme partout ailleurs — une diagonale n'a pas de sens dans une
     seule colonne.
     La marge, elle, n'est plus écrite ici : c'est celle de la planche, réglable
     comme partout ailleurs. Le gabarit donne 3 % à la diagonale par défaut,
     mesuré le 2026-09-10 — la marge ne desserrait de toute façon les images que
     d'un dixième, et 5 % les rognaient pour de l'air que les deux quarts vides
     donnaient déjà. Ce qui les fait vraiment grandir est le cran de `taille:`,
     ajouté le 2026-09-11. */
  /* Deux colonnes, une seule rangée pleine hauteur — et non plus deux rangées
     à parts égales. C'est ce qui libère la taille : tant que la planche était
     coupée en quatre, aucune image ne pouvait dépasser la demi-hauteur, quelle
     que soit la marge. Ici chacune monte jusqu'au plafond que dit `taille:`, et
     au-delà de la moitié les deux se croisent en hauteur sans jamais se
     toucher, chacune tenant sa colonne. Le vide en diagonale reste le dessin. */
  .planche--diagonale {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: minmax(0, 1fr);
  }

  /* C'est l'image qui donne sa taille au bloc, et non l'inverse : width et
     height en auto, plafonnés en largeur par la colonne et en hauteur par le
     cran de `taille:`. La boîte prend alors très exactement les proportions de
     la photo — object-fit n'a plus rien à recadrer, il n'est gardé que pour
     absorber l'arrondi du pixel. */
  .planche--diagonale picture {
    display: flex;
    min-width: 0;
    min-height: 0;
  }

  .planche--diagonale img:not([data-cadre]) {
    width: auto;
    height: auto;
    max-width: 100%;
    /* Le repli vaut `moyenne` : une planche écrite avant le réglage garde le
       rendu qu'elle avait. */
    max-height: var(--planche-taille, var(--planche-taille-moyenne));
    object-fit: contain;
  }

  /* L'ancrage, seul rôle de la disposition : chaque image se range par son
     coin, la marge de la planche restant entre elle et le bord. */
  .planche--diagonale > :nth-child(1) {
    grid-area: 1 / 1;
    justify-content: flex-start;
    align-items: flex-start;
  }

  .planche--diagonale > :nth-child(2) {
    grid-area: 1 / 2;
    justify-content: flex-end;
    align-items: flex-end;
  }

  .planche--diagonale.planche--miroir > :nth-child(1) {
    grid-area: 1 / 2;
    justify-content: flex-end;
    align-items: flex-start;
  }

  .planche--diagonale.planche--miroir > :nth-child(2) {
    grid-area: 1 / 1;
    justify-content: flex-start;
    align-items: flex-end;
  }

  /* Une image recadrée ne se dimensionne plus elle-même : c'est son cadre qui
     porte la boîte, et c'est donc lui qu'il faut plafonner et ranger par son
     coin. Les deux mécaniques cohabitent — l'alignement du contenu ci-dessus
     pour une image nue, l'alignement du cadre ici — et chacune ne s'applique
     qu'au cas qui la concerne. */
  .planche--diagonale > .visuel-cadre {
    /* En bloc : le flex de la diagonale range une image nue dans son coin, un
       cadre n'en a pas besoin, et le pseudo-élément qui lui donne sa largeur y
       deviendrait un item de ligne. */
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: var(--planche-taille, var(--planche-taille-moyenne));
  }

  /* Une taille réglée sur la photo prend le pas sur le cran de la planche :
     la règle générale vaut, seul l'ancrage au coin change, ci-dessous.
     En bloc et non en flex : le flex de la diagonale sert à ranger une image
     nue dans son coin, et un cadre n'en a pas besoin — son image le remplit.
     Il y ferait même du tort : le pseudo-élément qui donne au cadre sa largeur
     deviendrait un item de la ligne et pousserait l'image dehors. */
  .planche--diagonale > .visuel-taille {
    display: block;
    /* Répété : la règle du cadre recadré, ci-dessus, remettrait la largeur à
       celle de la colonne sur un cadre qui est à la fois recadré et taillé. */
    max-width: min(var(--visuel-largeur, 100%), 100%);
    max-height: 100%;
  }

  .planche--diagonale > :is(.visuel-cadre, .visuel-taille):nth-child(1) { place-self: start start; }
  .planche--diagonale > :is(.visuel-cadre, .visuel-taille):nth-child(2) { place-self: end end; }
  .planche--diagonale.planche--miroir > :is(.visuel-cadre, .visuel-taille):nth-child(1) { place-self: start end; }
  .planche--diagonale.planche--miroir > :is(.visuel-cadre, .visuel-taille):nth-child(2) { place-self: end start; }

  /* L'image d'un cadre le remplit, quelle que soit la disposition. Écrit ici,
     après toutes les dispositions, parce que celles qui montrent l'image
     entière — pleine, scope, légende, diagonale — s'adressent à l'image nue
     avec la même spécificité, et lui donneraient sinon une taille à elle. */
  .planche--visuels .visuel-cadre > img,
  .planche--visuels .visuel-taille > img {
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: cover;
  }

  /* --- La planche libre ----------------------------------------------------
     Aucune grille : chaque image porte sa place et sa taille, en part de la
     planche. C'est la seule disposition du site où une image est positionnée en
     absolu, et c'est assumé — CLAUDE.md interdit le positionnement absolu POUR
     CONSTRUIRE UNE GRILLE, et il n'y en a pas ici : c'est précisément ce qu'on
     lui demande de ne pas être.
     Les quatre nombres de chaque image ne s'écrivent pas ici, ils sont propres à
     une planche : le gabarit les rend dans un bloc <style>, une règle par
     emplacement, accrochée à l'identifiant de la planche. Voir cadres.njk.
     Sur téléphone, la planche libre retombe en colonne : une composition libre
     réglée sur un écran de 1440 n'a aucun sens dans 320 px de large. C'est la
     même règle que pour la diagonale, et pour la même raison. */
  .planche--libre {
    display: block;
    position: relative;
    /* Pas de marge ici, et ce n'est pas un oubli : les emplacements se comptent
       en part de la PLANCHE, et un élément positionné en absolu se cale sur la
       boîte de padding — c'est-à-dire la planche entière, marge comprise. Un
       retrait n'y déplacerait donc rien. L'air d'une planche libre, c'est celui
       qu'on laisse entre les images en les plaçant. La table de montage retire
       le réglage plutôt que d'offrir un bouton sans effet. */
    padding: 0;
  }

  .planche--libre > :is(picture, .cellule-extrait) {
    position: absolute;
    /* Le repli, quand la planche nomme plus d'images que d'emplacements : au
       centre, en grand, visible — un oubli doit se voir. */
    inset: 10%;
  }

  .planche--libre > picture {
    display: block;
  }

  .planche--libre img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .visuel-vide {
    aspect-ratio: auto;
    height: 100%;
  }

  /* À l'horizontale, l'entrée et la sortie suivent le sens de lecture : la page
     arrive par la droite et s'en va par la gauche, comme les planches. */
  @media (prefers-reduced-motion: no-preference) {
    @keyframes page-entree {
      from {
        opacity: 0;
        transform: translateX(3rem);
      }
    }

    @keyframes page-sortie {
      to {
        opacity: 0;
        transform: translateX(-3rem);
      }
    }
  }
}

@media (min-width: 64em) {

  .section-contact__titre {
    margin-bottom: var(--pas-8);
  }

}
