/* ====================================================================
 * Fiona Lebre — LE TÉLÉPHONE
 * ====================================================================
 *
 * UNE COMPOSITION, PAS UN REPLIEMENT. La home desktop est une page fixe
 * de 8 colonnes sur 7 rangs, validée au pixel. On ne l'adapte pas par
 * dégradation : on redessine une grille de 6 sur 10 avec ses propres
 * marges, et on n'y garde du desktop que ce qui a encore un sens.
 *
 * CE QUI RESTE, ET C'EST L'ESSENTIEL : le carrousel, sa physique, le
 * fondu en relais de la légende, la continuité vers la page projet.
 * Aucun de ces mécanismes n'est retouché ici — ils sont dans theme.css,
 * carousel.css et js/main.js, et cette feuille ne fait que les reloger.
 *
 * CE QUI DISPARAÎT : le SURVOL. Sur un écran tactile il n'existe pas, et
 * c'est lui qui pilotait les deux vues — l'index de la home, la planche
 * de contact du projet. Ce n'est pas une perte à compenser, c'est le
 * geste qui change de nature : on glisse (cf. js/mobile-gestures.js).
 *
 * --------------------------------------------------------------------
 * UN SEUL MARKUP, ET C'EST NON NÉGOCIABLE.
 *
 * template-parts/home-content.php sert les quatre vues et reste intact.
 * Tout ce que Fiona saisit passe par lui ; deux rendus finiraient par
 * diverger sans que personne ne le voie, et les transitions reposent
 * justement sur le fait que la destination est déjà dans le document.
 *
 * D'où une conséquence élégante : LA NUMÉROTATION EST L'INDEX. Les
 * chiffres romains vivent déjà DANS les liens de l'index (cf.
 * .home-index-num). Il suffit donc de masquer les noms et de coucher les
 * chiffres en une rangée : on obtient le repère de position sans ajouter
 * une ligne de PHP, et sans dupliquer une donnée. Mieux, l'état du
 * projet courant est déjà géré — le chiffre étant dans le lien, il passe
 * au noir avec lui.
 *
 * --------------------------------------------------------------------
 * LA HAUTEUR EST EN svh, ET C'EST LE PIÈGE PRINCIPAL DU MOBILE.
 *
 * 100vh vaut le GRAND viewport, celui qu'on aurait si l'interface du
 * navigateur était repliée — donc 874 sur un iPhone 16 Pro. Or la barre
 * d'adresse ne se replie qu'au défilement, et cette page ne défile
 * jamais : elle est verrouillée comme les trois autres vues. On est donc
 * en permanence dans le PETIT viewport, ~680, et une grille en 100vh
 * enverrait le rang 10 — la numérotation — 78px sous le pli. Invisible,
 * et sans barre de défilement pour le signaler.
 *
 * svh est exactement ce petit viewport. Et comme les rangs sont des
 * fractions, la composition se resserre ou se détend selon l'appareil
 * sans qu'aucune valeur ne soit à recalculer.
 *
 * Un navigateur trop ancien pour svh ignore simplement la déclaration et
 * retombe sur le 100vh de theme.css — c'est-à-dire le comportement
 * d'avant ce fichier. Dégradation, pas panne.
 *
 * --------------------------------------------------------------------
 * LE SEUIL EST À 900px, ET CE N'EST PAS UN CHOIX D'APPAREIL.
 *
 * C'est le plancher de la composition desktop, mesuré : le titre le plus
 * long de l'index (« Midnight cosmetics », 106,8px) doit tenir dans une
 * colonne sur huit, ce qui demande 106,8 x 8 + 50 de marges = 905px. En
 * dessous, il déborde de sa piste et l'alignement sur « Info » se casse.
 * Le seuil suit donc ce que la mise en page peut contenir, pas le nom
 * qu'on donne à l'écran — une tablette en portrait reçoit cette feuille,
 * la même en paysage reçoit le desktop.
 *
 * À SAVOIR : ce plancher dépend des titres de Fiona. Un projet nommé plus
 * long le fait remonter, et l'index desktop se mettrait à serrer à 900.
 *
 * --------------------------------------------------------------------
 * CHARGÉE EN DERNIER, APRÈS transition-project.css.
 *
 * Plusieurs règles d'ici ont exactement la même spécificité que les
 * siennes (body + deux classes) — notamment sur .fl-home-img, dont ce
 * fichier-là redéfinit déjà les retraits. À spécificité égale c'est
 * l'ordre de chargement qui tranche, donc la dépendance déclarée dans
 * functions.php n'est pas décorative.
 * ==================================================================== */

@media ( max-width: 900px ) {

/* ------------------------------------------------------------------ */
/* 1. Le socle                                                         */
/* ------------------------------------------------------------------ */

/* ON REDÉFINIT LES TOKENS DE GRILLE, et le reste suit tout seul.
   .home-layout construit déjà ses pistes avec repeat(var(--grid-columns))
   et repeat(var(--grid-rows)) : les passer à 6 et 10 suffit à changer la
   grille, sans réécrire une seule déclaration de template.

   --grid-margin passe à 20 pour les côtés. La marge HAUTE du header
   reste distincte (20 aussi : le titre se pose dans la bande de 80 que
   la grille laisse au-dessus d'elle, pas au milieu).

   Les marges verticales de la grille, elles, ne peuvent pas passer par
   ces tokens : .home-layout applique --grid-margin en bas et
   --grid-margin-top en haut, or il nous faut trois valeurs distinctes —
   80 en haut, 0 en bas, 20 sur les flancs. D'où les tokens propres
   ci-dessous, et le padding réécrit plus bas.

   LE SOCLE COUVRE fl-home ET fl-about, et ce n'est pas de la prudence :
   c'est une correction de bug.

   js/about.js ne recharge pas la page quand on touche « Info » — il joue
   le pli sur place, et POUR FINIR IL ÉCHANGE LA CLASSE DU BODY : fl-home
   s'en va, fl-about arrive. Tout ce qui n'était accroché qu'à fl-home
   décrochait donc au milieu du geste. Constaté : « Overview » réapparaissait
   dans la nav, la grille repassait à 8 colonnes et la bio glissait de 20 à
   25px de marge — la composition mobile entière se démontait en une
   demi-seconde.

   Les deux classes partagent donc tout ce qui décrit la PAGE, et seul ce
   qui décrit le CONTENU reste propre à chaque vue. */
body.fl-home,
body.fl-about {
	--grid-columns: 6;
	--grid-rows: 10;
	--grid-margin: 20px;
	--grid-margin-top: 20px;

	--fl-m-side: 20px;

	/* 80 EN HAUT, RIEN EN BAS, et ce zéro est le résultat d'un calcul.
	   La maquette portait 80px de marge basse pour contrer la barre de
	   navigation du navigateur — sauf que 100svh l'a déjà retirée (c'est
	   sa définition : la hauteur visible interface DÉPLOYÉE). Les garder
	   revenait à payer deux fois le même espace.

	   Et les retirer fait retomber la maquette au pixel sur l'écran
	   réel : 80 + 10 rangs de 60 = 680, soit exactement le plan de 760
	   moins sa compensation. Le carton retrouve ses 332 x 390 et la boîte
	   intérieure ses 241 x 299.

	   Le rang 10 fournit lui-même l'air sous les romains — ils occupent
	   644 -> 656 dans un rang qui va de 620 à 680. Cette réserve est donc
	   PROPORTIONNELLE : elle grandit avec l'écran au lieu d'être figée. */
	--fl-m-top: 80px;
	--fl-m-bottom: 0px;

	/* LA COLONNE MOBILE, en pixels réels. Elle sert au passe-partout de
	   la photo, qui se mesure en colonnes et non en pourcentage (cf. plus
	   bas). Même procédé que --fl-col dans css/project.css : la grille
	   raisonne en fractions, mais certaines mesures ont besoin de la
	   valeur. */
	--fl-col-m: calc( ( 100vw - 2 * var(--fl-m-side) ) / var(--grid-columns) );

	/* LE RETRAIT DU CARTON dans le beige. Seul pixel dur de la
	   composition avec les marges, et il est volontairement dur : c'est
	   une épaisseur de carton, pas une proportion de page. */
	--fl-mat-inset: 15px;

	/* svh et non vh — cf. le pavé d'en-tête. C'est la correction la plus
	   importante de ce fichier. */
	height: 100svh;

	/* Pas de rebond élastique. La page ne défile pas ; sans ça, un
	   glissement vertical fait tirer tout le document et le geste de
	   navigation entrerait en concurrence avec le caoutchouc du
	   navigateur. */
	overscroll-behavior: none;
}

/* La barre d'admin fait 46px sous 782px de large (cf. theme.css, qui
   applique la même correction en vh). Ne concerne que Fiona connectée. */
body.fl-home.admin-bar,
body.fl-about.admin-bar {
	height: calc( 100svh - 46px );
}

/* ------------------------------------------------------------------ */
/* 2. Le header redevient une ligne                                    */
/* ------------------------------------------------------------------ */

/* EN FLEX ET NON EN GRILLE, parce que la grille n'a plus que 6 colonnes.
   theme.css cale le titre sur « 1 / 8 » et la nav sur « 8 / -1 » : avec
   six pistes ces deux valeurs sortent de la grille et le navigateur
   fabrique des colonnes implicites pour les loger. Le header partait
   donc en morceaux.

   Un space-between dit exactement ce qu'on veut — un bord, l'autre bord
   — et ne dépend d'aucun nombre de colonnes. */
body.fl-home .site-header,
body.fl-about .site-header {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	padding: var(--grid-margin-top) var(--fl-m-side) 0;
}

body.fl-home .site-title,
body.fl-home .site-logo,
body.fl-home .site-nav,
body.fl-about .site-title,
body.fl-about .site-logo,
body.fl-about .site-nav {
	grid-column: auto;
}

/* OVERVIEW DISPARAÎT DU TÉLÉPHONE. La mosaïque est une vue à survoler et
   à viser ; au doigt, sur 402px, elle donnerait des tirages de 60px. Le
   site se réduit donc à deux entrées : les projets, et Info.

   Ciblé par l'ADRESSE et non par la position, parce que « le deuxième
   item » ne veut rien dire et se casserait si l'ordre changeait. La
   contrepartie est que ce sélecteur connaît le permalien de l'archive :
   si le slug /overview/ change un jour, cette règle cesse de mordre en
   silence. À remplacer par une classe posée côté PHP la prochaine fois
   qu'on touche à fl_default_nav_fallback(). */
body.fl-home .site-nav li:has( a[href$="/overview/"] ),
body.fl-about .site-nav li:has( a[href$="/overview/"] ) {
	display: none;
}

/* Le space-between du <ul> n'a plus qu'un item à placer : il le colle au
   bord droit, ce qui est voulu. Le gap devient sans objet. */
body.fl-home .site-nav ul,
body.fl-about .site-nav ul {
	gap: 0;
}

/* ------------------------------------------------------------------ */
/* 3. La grille                                                        */
/* ------------------------------------------------------------------ */

/* 80 en haut, 0 en bas, 20 sur les côtés — cf. le calcul du zéro sur le
   token. Le padding est réécrit en entier plutôt que piloté par les
   tokens de theme.css : --grid-margin y sert les deux flancs ET le bas,
   or ici les trois valeurs diffèrent.

   ET LES PISTES SONT REDÉCLARÉES, ce qui ne devrait pas être nécessaire.
   Redéfinir --grid-columns suffirait, puisque theme.css construit ses
   pistes avec repeat(var(--grid-columns), 1fr) — sauf que son ancien bloc
   @media (max-width: 900px) écrase ce template par un « 1fr » sec. À
   spécificité égale c'est la dernière règle du fichier qui gagne, donc la
   grille retombait à UNE colonne : tout paraissait juste (un élément en
   1 / -1 occupe la largeur dans les deux cas) mais --fl-col-m ne
   correspondait plus à aucune piste réelle, et le passe-partout de la
   photo était calculé sur une colonne fantôme.

   On vise donc body.fl-home pour passer devant, et on le dit ici plutôt
   que de compter sur la variable. Ces deux lignes deviendront redondantes
   le jour où le vieux bloc sera retiré de theme.css — elles resteront
   justes, simplement inutiles. */
body.fl-home .home-layout,
body.fl-about .home-layout {
	grid-template-columns: repeat( var(--grid-columns), 1fr );
	grid-template-rows: repeat( var(--grid-rows), 1fr );
	padding: var(--fl-m-top) var(--fl-m-side) var(--fl-m-bottom);
}

/* ------------------------------------------------------------------ */
/* 4. Le beige                                                         */
/* ------------------------------------------------------------------ */

/* LES 6 COLONNES ET LES RANGS 1 À 9. Il ne couvre donc PAS le rang 10 :
   la numérotation se pose sur le blanc de la page, en dessous. C'est
   voulu — elle ne fait pas partie de la table, elle dit où l'on est dans
   le site.

   Il garde ses marges latérales (il s'arrête aux 20px comme la grille) :
   il lui reste donc quelque chose à étendre, et le jour où un geste
   voudra le faire grandir, le mécanisme est intact. */
body.fl-home .home-beige {
	grid-column: 1 / -1;
	grid-row: 1 / 10;
}

/* ------------------------------------------------------------------ */
/* 5. Le carton                                                        */
/* ------------------------------------------------------------------ */

/* 6 COLONNES SUR 7 RANGS, MOINS 15px DE RETRAIT, aligné en haut du
   beige.

   C'est .home-work qui porte la zone de grille, et le retrait est son
   padding : le carton (.fl-home-frame) remplit ce qui reste. On évite
   ainsi de calculer une taille — la boîte est décrite par la grille, le
   carton l'occupe.

   align-items: stretch renverse le centrage de theme.css. Sur la home
   desktop le cadre est un carré qui se centre dans sa zone ; ici il doit
   la remplir, comme sur la page projet (même recette dans
   css/project.css).

   SA FORME N'EST DONC PAS FIXE : 7 rangs moins 30px donnent 332 x 390 sur
   un écran de 680 — le 5:7 de la maquette — et s'allongent un peu sur un
   téléphone plus haut.

   C'est l'arbitrage retenu : la composition reste équilibrée partout, au
   prix d'un cadrage qui varie légèrement selon l'appareil. L'alternative
   (rapport figé) déversait toute la variation de hauteur dans le vide
   sous le carton, et la légende venait le toucher sur un écran court. */
body.fl-home .home-work {
	grid-column: 1 / -1;
	grid-row: 1 / 8;
	padding: var(--fl-mat-inset);
	align-items: stretch;
}

body.fl-home .fl-home-frame {
	aspect-ratio: auto;
	width: 100%;
	height: 100%;
	flex: 1 1 auto;
}

/* ------------------------------------------------------------------ */
/* 6. La photo                                                         */
/* ------------------------------------------------------------------ */

/* LE PASSE-PARTOUT VAUT UNE COLONNE MOINS 15px, et cette formule n'est
   pas un réglage : elle se déduit.

   Le carton fait 6 colonnes moins 30px de retrait, la photo en fait 4.
   Le blanc de chaque côté vaut donc ( 6 col - 30 - 4 col ) / 2, soit
   exactement 1 colonne - 15px. À 402 de large : 60,33 - 15 = 45,3px.

   Appliqué aux DEUX axes, donc uniforme sur les quatre côtés. La boîte
   intérieure vaut ainsi 4 colonnes de large sur 7 rangs - 2 colonnes de
   haut — 241 x 299 sur un plan de 402 x 760.

   PAR max-* ET NON PAR padding, parce que c'est ce que
   transition-project.css a établi : la boîte de l'<img> doit épouser la
   photo pour que les deux instantanés de la transition se recouvrent.
   Un padding rendrait la boîte plus grande que son contenu et on
   retomberait sur le défaut corrigé là-bas.

   Une VERTICALE remplit la boîte. Une HORIZONTALE fait 241 x 161 avec du
   blanc au-dessus et en dessous : aucun rapport de carton ne règle ça, et
   le desktop a exactement la même limite, documentée dans theme.css. */
body.fl-home .fl-home-img {
	max-width: calc( 100% - 2 * ( var(--fl-col-m) - var(--fl-mat-inset) ) );
	max-height: calc( 100% - 2 * ( var(--fl-col-m) - var(--fl-mat-inset) ) );
}

/* ------------------------------------------------------------------ */
/* 7. La légende                                                       */
/* ------------------------------------------------------------------ */

/* QUATRE COLONNES, TEXTE CENTRÉ, CALÉE AU BAS DU RANG 8.

   LE CENTRAGE EST UNE DÉCISION DE DESIGN, pas une conséquence technique :
   « sur la home, le texte doit être centré, on se dédouane du design web
   ici ». Tout le reste de cette section découle de cette contrainte-là.

   LES COLONNES 2 À 5, et pas 1 à 6, parce que la boîte doit être centrée
   sur la PAGE : de 80,33 à 321,66, son milieu tombe à 201, exactement le
   milieu de l'écran. Une boîte pleine largeur aurait donné le même
   résultat visuel, mais pas la même largeur que celle de la page projet —
   et c'est cette égalité-là qui fait tout ce qui suit.

   ------------------------------------------------------------------
   POURQUOI LA LARGEUR ET LE FER DOIVENT COÏNCIDER AVEC LA PAGE PROJET.

   Le passage vers un projet est une VRAIE NAVIGATION : deux documents,
   deux légendes différentes, qui ne coexistent jamais. Le navigateur ne
   peut donc pas déplacer un élément — il photographie l'ancienne page,
   photographie la nouvelle, et interpole entre les deux images (cf.
   css/transition-project.css). Or une image, ça se déplace et ça se
   redimensionne, mais ça ne se RÉ-ALIGNE pas : elle ne sait pas qu'elle
   contient du texte. Une boîte centrée d'un côté et ferrée à gauche de
   l'autre ne lui laisse donc qu'un seul recours, le fondu.

   C'est exactement la contrainte que transition-project.css énonce pour
   le desktop : « ce qui doit coïncider, ce n'est pas la position, c'est
   la LARGEUR et le FER ».

   ICI ON LA RÉSOUT AUTREMENT : ce n'est pas le pavé qui voyage, c'est le
   TEXTE — cf. section 7 bis. Le pavé ne porte donc plus de nom de
   transition, et ce qu'il décrit encore est la mise en page au repos :
   où tombe la légende, sur quelle largeur elle a le droit de s'étendre.

   Elle court sur quatre colonnes alors que son texte est plus court parce
   que .caption-line est en overflow:hidden : un titre long serait TRANCHÉ
   plutôt que reporté, il lui faut donc de la course. Quatre colonnes font
   241px, de quoi loger les titres actuels au large.

   Son fondu en relais, ses deux couches, sa virgule en CSS et ses trois
   temps (ligne 1, photo, ligne 2) ne sont PAS retouchés : tout est dans
   theme.css et js/main.js, rien là-dedans ne dépend de la largeur, et ce
   fondu-là raconte un changement de projet, pas un changement de page. */
body.fl-home .home-caption {
	grid-column: 2 / 6;
	grid-row: 8 / 9;
	align-self: end;
	text-align: center;
}

/* ------------------------------------------------------------------ */
/* 7 bis. La légende voyage — ce qui bouge, c'est le TEXTE             */
/* ------------------------------------------------------------------ */

/* CENTRÉE SUR LA HOME, FERRÉE À GAUCHE SUR LE PROJET, ET SANS FONDU.
 *
 * L'objection qui avait fait abandonner cette piste — « une boîte qui
 * épouse le texte change de largeur à chaque pas du carrousel » — était
 * fausse d'un niveau. Le texte n'est pas dans le pavé : il est dans
 * .caption-text, qui est en position ABSOLUE (deux couches superposées
 * pour le fondu en relais, cf. theme.css). Une couche absolue ne
 * participe pas au flux, donc width:max-content la fait épouser son
 * texte SANS QUE RIEN NE BOUGE AUTOUR. Mesuré : le pavé reste à 80,3 et
 * la couche sortante garde sa largeur pendant tout le fondu.
 *
 * Et dès lors il n'y a plus d'alignement à animer : la boîte capturée EST
 * le texte, mêmes mots et même fonte des deux côtés, donc même largeur au
 * dixième (86,4px et 93,1px sur « An ode to daylight »). Il ne reste
 * qu'une translation.
 *
 * UN NOM PAR LIGNE : les deux lignes n'ont pas la même largeur, donc pas
 * le même décalage à rattraper. Un seul nom pour le bloc laisserait la
 * ligne courte désalignée à l'intérieur, et le fondu reviendrait pour
 * elle.
 *
 * LE NOM NE VA QUE SUR LA COUCHE ACTIVE — deux éléments portant le même
 * view-transition-name annulent la transition. .is-active existe sur les
 * deux documents (posée par js/main.js, rendue côté serveur), ce qui est
 * la condition de l'appariement. Nommer les couches par leur rang dans le
 * DOM serait faux : la parité change à chaque pas du carrousel.
 *
 * VÉRIFIÉ EN TRANSITION RÉELLE, dans Chrome, timeline active : la
 * transition n'est PAS annulée et les groupes fl-cap-1 / fl-cap-2 sont
 * bien créés. C'était le point aveugle — une première tentative avait été
 * retirée sur la foi d'une observation impossible (un document caché fait
 * sauter les transitions de vue, donc on ne voyait rien et on concluait
 * qu'il n'y avait rien).
 *
 * LA DURÉE EST OBLIGATOIRE, et c'était le vrai défaut : mesurés à 250ms —
 * le défaut du navigateur — contre 900 pour tout le reste de la page. Un
 * texte qui parcourt 137px trois fois et demie plus vite que le beige qui
 * l'entoure ne se lit pas comme un déplacement, il claque.
 *
 * ET ON RETIRE fl-caption DU PAVÉ : sinon il voyage AUSSI, avec son propre
 * instantané contenant le même texte, et chaque ligne apparaît en double.
 * Le desktop le garde — cette section est dans le bloc mobile, et là-bas
 * le pavé a la même largeur ET le même fer des deux côtés. */
body.fl-home .home-caption,
body.fl-project .home-caption {
	view-transition-name: none;
}

/* theme.css tend la couche d'un bord à l'autre (left:0; right:0) : une
   largeur explicite la libère de cet étirement, et les deux offsets ne
   servent plus qu'à définir l'espace où elle se place. */
body.fl-home .home-caption .caption-text,
body.fl-project .home-caption .caption-text {
	width: max-content;
	max-width: 100%;
}

/* CENTRÉE PAR LES MARGES AUTO, PAS PAR UN transform : le groupe de
   transition anime la boîte capturée par SON transform, un transform
   propre à l'élément entrerait en concurrence. */
body.fl-home .home-caption .caption-text {
	left: 0;
	right: 0;
	margin-inline: auto;
	transform: none;
}

body.fl-project .home-caption .caption-text {
	left: 0;
	right: auto;
	margin-inline: 0;
	transform: none;
}

body.fl-home .caption-title .caption-text.is-active,
body.fl-project .caption-title .caption-text.is-active {
	view-transition-name: fl-cap-1;
}

body.fl-home .caption-meta .caption-text.is-active,
body.fl-project .caption-meta .caption-text.is-active {
	view-transition-name: fl-cap-2;
}

/* Les durées. transition-project.css les impose NOM PAR NOM ; un nom qui
   n'est pas dans sa liste retombe sur les 250ms du navigateur. On réemploie
   ses variables au lieu de recopier ses valeurs. */
::view-transition-group(fl-cap-1),
::view-transition-group(fl-cap-2) {
	animation-duration: var(--project-vt-duration);
	animation-timing-function: var(--project-vt-ease);
}

::view-transition-old(fl-cap-1),
::view-transition-new(fl-cap-1),
::view-transition-old(fl-cap-2),
::view-transition-new(fl-cap-2) {
	inline-size: 100%;
	block-size: 100%;
	object-fit: contain;
	object-position: center;
	animation-duration: var(--project-vt-duration);
	animation-timing-function: var(--project-vt-ease);
}

/* ------------------------------------------------------------------ */
/* 8. L'index devient la numérotation                                  */
/* ------------------------------------------------------------------ */

/* LA RANGÉE DE CHIFFRES ROMAINS, centrée dans le rang 10.
   I II III IV V VI VII VIII IX — le projet affiché en noir, les autres
   dans la couleur d'accent.

   C'EST LE MÊME ÉLÉMENT QUE L'INDEX DESKTOP, réduit à ses chiffres. On
   masque les noms, on couche les liens en ligne, et le tour est joué :
   aucune donnée dupliquée, aucun PHP touché, et la bascule de couleur du
   projet courant fonctionne déjà — le chiffre est DANS le lien, il hérite
   donc de .is-highlighted comme le nom le faisait.

   Les liens gardent leur href : ils restent dans le document pour les
   moteurs et la navigation clavier, ils ne sont simplement plus
   pointables (cf. plus bas).

   LES ROMAINS ONT DES LARGEURS TRÈS INÉGALES — « I » fait 3px, « VIII »
   en fait 24 au même corps. Le gap étant constant, ce sont les ESPACES
   qui sont réguliers et les centres qui ne le sont pas. C'est le rythme
   naturel du chiffre romain ; le forcer demanderait une avance fixe par
   caractère, et on y perdrait le dessin. Rien ne saute au changement de
   projet, de toute façon : la rangée est statique, seul le noir se
   déplace. */
body.fl-home .home-index {
	display: flex;
	grid-column: 1 / -1;
	grid-row: 10 / 11;
	align-self: center;
	justify-content: center;
	align-items: baseline;
	gap: 0.55em;
	/* L'interlignage de 1,8 de l'index desktop n'a plus d'objet sur une
	   seule ligne, et il gonflerait la hauteur de la rangée. */
	line-height: 1;
}

/* INDICATIFS, PAS TAPPABLES. À ~15px de large un romain est très en
   dessous du seuil du doigt (44px) : en faire une cible produirait des
   erreurs de visée plutôt qu'un raccourci. On entre dans un projet en
   touchant la photo, pas en visant un chiffre.

   display:block annule la grille de 6 colonnes que theme.css donne à ces
   liens — elle n'a plus de sens quand le lien ne contient qu'un chiffre. */
body.fl-home .home-index a {
	display: block;
	pointer-events: none;
}

body.fl-home .home-index-name {
	display: none;
}

/* Le chiffre reprend sa place normale dans le flux : sur desktop il est
   posé en colonne 1 d'une grille interne qui n'existe plus ici. */
body.fl-home .home-index-num {
	grid-column: auto;
	line-height: 1;
	pointer-events: none;
}

/* ==================================================================== */
/* LA PAGE PROJET                                                       */
/* ==================================================================== */
/*
 * LE TIRAGE PREND HUIT RANGS, LA DERNIÈRE BANDE PORTE LE RESTE — la
 * légende à gauche, la planche de contact à droite.
 *
 * LA PLANCHE SURVIT AU TÉLÉPHONE, et c'était la vraie question. Elle est
 * le geste signature du site — on lit la série, on choisit une vue, on la
 * tire en grand — et la supprimer aurait vidé la page de son sujet. Elle
 * change simplement de statut : d'une colonne de vignettes qu'on survole,
 * elle devient un REPÈRE DE POSITION. On y voit où l'on est dans la série
 * et combien il reste, sans avoir à viser.
 *
 * Parce que viser, à cette taille, ne marche pas : une vignette fait 25px
 * de côté, très en dessous des 44px du doigt. Elles restent cliquables —
 * js/project.js écoute déjà le clic pour cette raison exacte — mais ce
 * n'est pas par là qu'on parcourt la série. C'est par le GLISSEMENT (cf.
 * js/mobile-gestures.js), et la planche dit où il en est. Exactement le
 * rôle des chiffres romains sur la home : même grammaire des deux côtés.
 *
 * ET LES VIGNETTES RESTENT PETITES, délibérément. C'est déjà la règle du
 * desktop (--project-thumb, 42 % d'une colonne) : « les vignettes doivent
 * rester petites, sinon ce ne sont plus des indices mais des images
 * concurrentes du tirage central ». Les grossir pour les rendre visables
 * aurait mis la planche au même rang que la photo.
 */

/* ------------------------------------------------------------------ */
/* 9. Le socle de la page projet                                       */
/* ------------------------------------------------------------------ */

/* Même grille que la home — 6 sur 10, mêmes marges — parce que c'est la
   même page arrêtée sur un projet. Les deux vues doivent partager leurs
   rangs, sinon le passage de l'une à l'autre déplacerait tout ce qui est
   censé rester en place.

   body.fl-project NE PORTE PAS fl-home (cf. fl_body_class), donc rien de
   la section précédente ne s'applique ici : il faut tout redire. C'est le
   prix de la séparation, et c'est le bon prix — les deux vues peuvent
   diverger sans se surveiller. */
body.fl-project {
	--grid-columns: 6;
	--grid-rows: 10;
	--grid-margin: 20px;
	--grid-margin-top: 20px;

	--fl-m-side: 20px;
	--fl-m-top: 80px;
	--fl-m-bottom: 0px;

	--fl-col-m: calc( ( 100vw - 2 * var(--fl-m-side) ) / var(--grid-columns) );

	/* LE RANG, EN PIXELS RÉELS. La planche est en position:fixed — elle est
	   rendue hors de .home-layout — donc elle ne peut pas se poser sur la
	   grille : il lui faut la valeur. Même procédé que --fl-row dans
	   css/project.css, recalculé sur 10 rangs et sur la hauteur visible. */
	--fl-row-m: calc( ( 100svh - var(--fl-m-top) ) / var(--grid-rows) );

	/* LE PASSE-PARTOUT DU TIRAGE VAUT 15px, la même épaisseur que le
	   retrait du carton dans le beige. Un seul constant, employé deux
	   fois.

	   Sur la home il vaut une colonne moins 15 (45px) : la photo y est un
	   objet posé dans une page, elle a besoin d'air. Ici elle EST la page,
	   donc le carton se réduit à un liseré et le tirage domine. C'est la
	   même différence qu'entre les deux vues du desktop, où le mat vaut un
	   rang entier sur la page projet — ramené ici à 15px parce qu'un rang
	   de 60 sur un écran de 402 mangerait la moitié de la photo. */
	--project-mat: 15px;

	/* 42 % de la colonne, comme sur desktop : 25px. Trois par rangée. */
	--project-thumb: calc( var(--fl-col-m) * 0.42 );

	/* Le retrait du carton dans le beige, identique à la home. */
	--fl-mat-inset: 15px;

	height: 100svh;
	overscroll-behavior: none;
}

body.fl-project.admin-bar {
	height: calc( 100svh - 46px );
}

/* Le header, comme sur la home : la grille n'a plus 8 colonnes, donc les
   « 1 / 8 » et « 8 / -1 » de theme.css sortiraient de la piste. */
body.fl-project .site-header {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	padding: var(--grid-margin-top) var(--fl-m-side) 0;
}

body.fl-project .site-title,
body.fl-project .site-logo,
body.fl-project .site-nav {
	grid-column: auto;
}

body.fl-project .site-nav li:has( a[href$="/overview/"] ) {
	display: none;
}

body.fl-project .site-nav ul {
	gap: 0;
}

/* Les pistes redéclarées pour la même raison que sur la home : l'ancien
   bloc @media de theme.css écrase le template par un « 1fr » sec, et il
   ne distingue pas les vues. */
body.fl-project .home-layout {
	grid-template-columns: repeat( var(--grid-columns), 1fr );
	grid-template-rows: repeat( var(--grid-rows), 1fr );
	padding: var(--fl-m-top) var(--fl-m-side) var(--fl-m-bottom);
}

/* ------------------------------------------------------------------ */
/* 10. Le beige, le carton, le tirage                                  */
/* ------------------------------------------------------------------ */

/* LE BEIGE EST À FOND PERDU, et RIEN N'EST DÉCLARÉ ICI — c'est le sens
   de ce commentaire vide de règle.

   css/project.css le passe déjà en position:fixed sur les quatre bords :
   sur une page projet, le beige cesse d'être un rectangle posé dans la
   page pour devenir la table elle-même. Ça vaut au téléphone comme au
   grand écran, donc on laisse faire.

   Une version de cette feuille le remettait dans ses colonnes, par
   symétrie avec la home. C'était une erreur, et pour une raison qui
   dépasse le goût : LE BEIGE EST CE QUI VOYAGE. Le passage home ->
   projet le fait grandir de son rectangle jusqu'au fond perdu (cf.
   css/transition-project.css, fl-beige). S'il a des marges des deux
   côtés, il n'a plus rien à parcourir — et le passage perd son geste le
   plus lisible, celui qui ouvre la page.

   UNE COUCHE DE MARGE EN MOINS POUR LE CARTON, du coup. Le beige n'en
   ayant plus, le carton n'a plus à s'insérer dedans : il se cale
   directement sur la marge de page. D'où un padding nul sur .home-work
   ci-dessous, contre 15px sur la home. Le carton passe ainsi de 332 à
   362 de large — il gagne exactement les deux retraits qu'on vient de
   retirer. */

/* HUIT RANGS, SANS RETRAIT : 362 x 480. La zone de grille EST le carton.
   Le passe-partout de la photo, lui, reste à 15px (cf. --project-mat) :
   c'est le seul blanc qui subsiste, et il tient du montage, pas de la
   mise en page. */
body.fl-project .home-work {
	grid-column: 1 / -1;
	grid-row: 1 / 9;
	padding: 0;
	align-items: stretch;
}

/* ------------------------------------------------------------------ */
/* 11. La légende                                                      */
/* ------------------------------------------------------------------ */

/* COLONNES 1 À 4, FERRÉE À GAUCHE, calée au milieu de la dernière bande.
   Elle partage cette bande avec la planche, qui est ferrée à droite :
   chacune se cale sur sa marge, et le vide se creuse entre les deux.

   LE FER À GAUCHE ICI ET LE CENTRAGE SUR LA HOME NE S'OPPOSENT PLUS, cf.
   section 7 bis : ce qui voyage est le texte lui-même, épousé au plus
   juste, donc il n'y a plus d'alignement à réconcilier entre les deux
   pages.

   Son pavé de 241px empiète sur celui de la planche (qui commence à 201),
   mais aucun texte ne s'y rend : la légende la plus large mesure une
   centaine de pixels depuis la marge. Les deux boîtes se chevauchent,
   leurs contenus non. */
body.fl-project .home-caption {
	grid-column: 1 / 5;
	grid-row: 9 / -1;
	align-self: center;
	text-align: left;
	position: relative;
	z-index: 2;
}

/* ------------------------------------------------------------------ */
/* 12. La planche de contact                                           */
/* ------------------------------------------------------------------ */

/* EN BAS À DROITE, SUR LA HAUTEUR DES DEUX DERNIERS RANGS.
   Toujours en position:fixed — elle est rendue hors de .home-layout (cf.
   single-project.php) et ne peut donc pas être un élément de la grille —
   mais ancrée au bas de l'écran au lieu d'être centrée verticalement.
   Comme la marge basse vaut zéro, les deux derniers rangs touchent le
   bord : une hauteur de deux rangs collée en bas tombe donc exactement
   sur la bande de la légende.

   DEUX RANGS, ET C'EST LE NOMBRE DE COLONNES QUI VARIE. Quatre photos
   font deux colonnes, neuf en font cinq. C'est la TRANSPOSITION exacte
   de la planche desktop, qui est en deux colonnes sur autant de rangs
   qu'il faut — on fait pivoter la même idée d'un quart de tour, parce que
   sur un téléphone c'est la largeur qui manque le moins en bas de page.

   grid-auto-flow: column est ce qui produit ça : deux rangs déclarés, et
   le navigateur crée les colonnes au fur et à mesure. Le remplissage est
   donc en COLONNES — photo 1 au-dessus de la 2, la 3 au-dessus de la 4.
   Ce n'est pas un pis-aller : c'est précisément l'ordre du desktop
   transposé, où deux photos consécutives sont déjà côte à côte. La
   contiguïté des vues successives est préservée, seul son axe change.

   LE GROUPE EST FERRÉ À DROITE, SUR LA MARGE DE PAGE. Quel que soit le
   nombre de photos, sa dernière colonne tombe donc sur le même bord que
   « Info » au-dessus et que le carton au-dessus encore. Il grandit vers
   la GAUCHE, en direction de la légende.

   Une version précédente le centrait sur la ligne qui ouvre la 6e
   colonne. Ça tenait, mais le repère n'était vrai qu'à demi : dès que la
   boîte se remplissait, le groupe venait de toute façon buter à droite.
   L'alignement variait donc avec le nombre de photos — ferré à droite sur
   les projets fournis, centré sur les autres. Un seul bord, toujours le
   même, se lit mieux qu'un centre qui ne tient pas ses promesses.

   ET LA BOÎTE S'ÉLARGIT À TROIS COLONNES, ce qui est la conséquence
   directe du fer à droite. Le bord droit étant désormais ce qui fixe la
   position, le bord GAUCHE ne sert plus qu'à dire à partir d'où ça
   défile — autant le reculer jusqu'à la légende, qui s'arrête à la
   colonne 4. La boîte couvre donc 4 à 6, soit 181px : de quoi loger six
   colonnes de vignettes, donc DOUZE photos sans rien faire défiler. Le
   projet à neuf, qui débordait de 28px, tient maintenant largement — et
   son groupe s'arrête à 30px de la légende.

   DES CARRÉS FORCÉS, et ça se paie : aspect-ratio + cover RECADRENT. Le
   site s'interdit le recadrage partout ailleurs, et c'est écrit noir sur
   blanc dans css/project.css. L'exception se défend ici parce qu'une
   planche contact EST une grille de cadres identiques — c'est même ce qui
   la rend lisible d'un coup d'œil : à 25px, des vignettes de formats
   différents ne se lisent plus comme une série mais comme un désordre.
   Le tirage, lui, n'est jamais recadré.

   DÉFILEMENT HORIZONTAL PLUTÔT QUE VERTICAL, puisque c'est l'axe qui
   grandit désormais. Il ne servira qu'au-delà de douze photos, mais il
   reste la soupape : ni la légende, ni le tirage, ni le beige ne bougent
   quel que soit le nombre de vues, et c'était toute la question.

   « safe end » plutôt que « end » : un contenu plus large que sa boîte,
   ferré à droite, voit son début sortir de la zone défilable et devient
   inatteignable. Le mot-clé safe bascule sur un alignement au début dans
   ce cas précis, et seulement dans ce cas. Les navigateurs qui l'ignorent
   lisent la ligne d'avant. */
body.fl-project .project-sheet {
	top: auto;
	bottom: 0;
	right: var(--fl-m-side);
	transform: none;
	width: calc( 3 * var(--fl-col-m) );
	height: calc( 2 * var(--fl-row-m) );
	max-height: none;

	grid-template-columns: none;
	grid-template-rows: repeat( 2, var(--project-thumb) );
	grid-auto-flow: column;
	grid-auto-columns: var(--project-thumb);
	gap: 6px;

	justify-content: end;
	justify-content: safe end;
	align-content: center;
	align-content: safe center;

	overflow-x: auto;
	overflow-y: hidden;
}

/* LE CADRE DEVIENT CARRÉ. .project-frame est un <button> à width:100% :
   dans une piste de 25px il fait donc 25 de large, et l'aspect-ratio lui
   donne sa hauteur. */
body.fl-project .project-frame {
	aspect-ratio: 1;
}

/* Et la photo remplit ce carré. project.css lui donne height:auto pour
   qu'elle garde son format — ici c'est le cadre qui commande, donc
   cover. Le seul recadrage du site, et il est confiné à 25px. */
body.fl-project .project-frame img {
	height: 100%;
	object-fit: cover;
}


/* ==================================================================== */
/* LA PAGE INFO                                                         */
/* ==================================================================== */
/*
 * PROVISOIRE, ET IL FAUT LE DIRE. Cette section corrige un bug — la
 * composition mobile se démontait au toucher d'« Info » — mais le
 * placement du texte lui-même n'a pas encore de maquette. Il est
 * transposé du desktop, pas dessiné pour le téléphone.
 *
 * LE CALQUE EST LA PAGE. Sur /about/ la grille de la home est masquée
 * (.home-layout.is-about-done) et il ne reste que .fl-about-overlay,
 * qui porte sa propre grille — même nombre de colonnes et de rangs, mêmes
 * marges. C'est ce qui permet au texte de tomber exactement où était
 * l'index pendant le pli, au lieu de sauter à l'arrivée.
 *
 * Il faut donc lui redonner la grille mobile à lui aussi, et défaire le
 * « grid-template-columns: 1fr » de l'ancien bloc @media d'about.css —
 * le troisième filet de sécurité de ce genre dans le thème, après ceux de
 * theme.css et de project.css.
 *
 * ET IL FAUT L'AVOIR DÈS LA PREMIÈRE IMAGE, PAS À L'ARRIVÉE. C'est le
 * second bug, mesuré : pendant toute la durée du pli le calque restait à
 * une colonne de 362px — la bio à y=84 sur 362 de large — puis basculait
 * d'un coup sur la grille de 6 à l'instant où js/about.js échange la
 * classe du body. Le texte se recomposait donc SOUS L'ŒIL, une demi-
 * seconde après avoir fini d'apparaître.
 *
 * D'où un principe, valable au-delà d'ici : LA GÉOMÉTRIE DE DESTINATION
 * NE PEUT PAS DÉPENDRE DE LA CLASSE QUI ARRIVE EN DERNIER. Le calque doit
 * porter la grille pendant qu'il est encore sur la home, sinon le pli
 * dépose son texte à une place qui n'est pas la sienne.
 *
 * On l'accroche donc aux deux classes. Sans effet de bord : sur la home
 * le calque est transparent et hors du flux (position:fixed), donc lui
 * donner des pistes ne déplace rien de visible — ça ne fait que préparer
 * l'endroit où le texte va se poser.
 */

/* ------------------------------------------------------------------ */
/* 13. Le calque Info                                                  */
/* ------------------------------------------------------------------ */

body.fl-home .fl-about-overlay,
body.fl-about .fl-about-overlay {
	grid-template-columns: repeat( var(--grid-columns), 1fr );
	grid-template-rows: repeat( var(--grid-rows), 1fr );
	padding: var(--fl-m-top) var(--fl-m-side) var(--fl-m-bottom);
}

/* LES MÊMES RANGS QUE SUR DESKTOP POUR LA BIO — 2 à 5 —, et c'est
   volontairement littéral : c'est là que tombait l'index qu'elle
   remplace, et le pli vers Info fait justement l'un se substituer à
   l'autre.

   LES CONTACTS, EUX, GAGNENT DEUX RANGS. Sur desktop ils tiennent dans un
   seul rang de 121px ; ici un rang fait 60px pour cinq lignes de texte,
   soit 108px — ça débordait. Trois rangs mobiles valent à peu près le
   rang desktop, la proportion est donc préservée même si le nombre change.

   CINQ COLONNES SUR SIX. La sixième reste vide : du texte qui court jusqu'à
   la marge droite se lit mal, et c'est aussi ce que fait la légende de la
   page projet, qui s'arrête à la colonne 4. */
body.fl-home .about-bio,
body.fl-about .about-bio {
	grid-column: 1 / 6;
	grid-row: 2 / 5;
}

body.fl-home .about-details,
body.fl-about .about-details {
	grid-column: 1 / 6;
	grid-row: 5 / 8;
}

}
