/* ============================================================
   site.css
   1. base   2. header   3. filets   4. index   5. theory
   6. info   7. page projet   8. responsive
   ============================================================ */

/* --- 1. base --- */
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:var(--bg);color:var(--ink);font-family:var(--font);
  font-size:var(--fs-base);line-height:1.35;font-weight:var(--w-body);
  -webkit-font-smoothing:antialiased;
}
a{color:inherit;text-decoration:none}
button{font:inherit;font-weight:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}
:focus-visible{outline:1px solid var(--ink);outline-offset:3px}
main{padding:0 var(--pad) 90px;position:relative;z-index:20}
/* Titre de page pour les lecteurs d'écran et les moteurs, invisible : la nav
   tient déjà ce rôle à l'écran (Projets, Théorie). */
.page-title{position:absolute;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap}

/* --- 2. header --- */
header{
  position:sticky;top:0;z-index:30;background:var(--bg);
  padding:14px var(--pad) 20px;
  display:flex;justify-content:center;align-items:baseline;gap:16px;
}
body[data-page="info"] header{background:transparent}
.wordmark{font-weight:var(--w-label);letter-spacing:.04em;font-size:14px;text-transform:uppercase}
nav{display:flex;gap:14px;font-size:15px}
nav a{color:var(--grey)}
nav a[aria-current="page"]{color:var(--ink);border-bottom:var(--rule) solid var(--ink);padding-bottom:2px}
.lang{position:absolute;right:var(--pad);top:14px;font-size:13px;color:var(--grey)}
.lang button[aria-pressed="true"]{color:var(--ink)}

/* --- 3. filets (dispositif commun aux trois pages) --- */
.rule-label{font-weight:var(--w-label);font-size:16px;padding-bottom:3px;border-bottom:var(--rule) solid var(--ink)}
.rule-line{padding:5px 0 3px;border-bottom:var(--rule) solid var(--ink)}

/* Retour : le même libellé et le même filet que les rubriques, mais à la
   mesure du mot. Sur les pages projet seulement — les trois pages principales
   ont la nav (CLAUDE.md §3). */
.back{display:inline-block;margin-top:80px;
  font-size:16px;font-weight:var(--w-label);
  padding-bottom:3px;border-bottom:var(--rule) solid var(--ink)}

/* --- 4. index --- */
.filters{margin-bottom:32px}
.filter-opts{padding:5px 0 16px;font-size:16px;font-weight:var(--w-label)}
.filter-opts button{color:var(--grey)}
.filter-opts button[aria-pressed="true"]{color:var(--ink)}

#grid{display:grid;grid-template-columns:repeat(4,1fr);grid-auto-rows:var(--row);column-gap:var(--gap)}
.card{align-self:start}
.card[data-cols="2"]{grid-column:span 2}
.card[data-cols="3"]{grid-column:span 3}
.thumb{width:100%;background:var(--placeholder);
  background-image:repeating-linear-gradient(45deg,#e7e7e7 0 10px,#efefef 10px 20px);overflow:hidden}
.thumb img,.thumb video{width:100%;height:100%;object-fit:cover;display:block}
/* Aperçu au survol : la vidéo ou les images défilantes se posent sur la
   vignette fixe, qui reste ce que l'on voit au repos et sur écran tactile.
   Seule l'opacité change — c'est la seule animation admise (CLAUDE.md §3). */
.thumb{position:relative}
.preview{position:absolute;inset:0;opacity:0;transition:opacity .25s}
.preview[data-on]{opacity:1}
.cap{padding:9px 0 30px}
.cap h3{margin:0;font-size:16px;font-weight:var(--w-label)}
.cap p{margin:0;font-size:17px;font-weight:var(--w-light);color:var(--grey)}
.card a:hover h3{text-decoration:underline;text-underline-offset:3px}
/* Filtres croisés sans résultat : une ligne, au traitement de la ligne de type. */
.grid-empty{grid-column:1 / -1;margin:0;font-size:17px;font-weight:var(--w-light);color:var(--grey)}

/* --- 5. theory --- */
/* Index de textes. Chaque entrée montre toujours le début de son résumé,
   coupé net à cinq lignes ; « Lire la suite » déroule la suite sur deux
   colonnes. La coupe est conditionnée à `data-fold`, que seul js/fold.js
   pose : sans JS le résumé s'affiche entier. */
.text-index{max-width:none}
.entry{padding:12px 0 10px;border-bottom:var(--rule) solid var(--ink)}
.entry:first-of-type{border-top:var(--rule) solid var(--ink)}
.entry-head{display:grid;grid-template-columns:1fr auto;gap:24px;align-items:baseline}
.entry h3{margin:0 0 2px;font-size:16px;font-weight:var(--w-label)}
.entry-info{display:block;font-size:16px;color:var(--grey)}
.entry-status{font-size:15px;color:var(--grey);white-space:nowrap}

.entry-abstract{font-size:var(--fs-base);line-height:1.45;margin:18px 0 0;
  columns:2;column-gap:calc(var(--gap) * 3)}
.entry-abstract p{margin:0 0 1em;break-inside:avoid}
.entry-abstract p:last-child{margin-bottom:0}

/* Replié, le résumé garde exactement la mesure de la première colonne :
   déplier prolonge le texte au lieu de recomposer ce qui est déjà lu. */
.text-index[data-fold] .entry-abstract:not([data-open]){
  columns:auto;max-width:calc((100% - var(--gap) * 3) / 2);
  display:-webkit-box;-webkit-box-orient:vertical;
  -webkit-line-clamp:5;line-clamp:5;overflow:hidden}

.entry-actions{display:flex;flex-wrap:wrap;gap:2px 26px;margin-top:12px;
  font-size:16px;color:var(--grey)}
.entry-actions a{border-bottom:var(--rule) solid var(--grey)}
.fold-more{font:inherit;color:inherit;background:none;border:0;padding:0;
  cursor:pointer;border-bottom:var(--rule) solid var(--grey);display:none}
[data-fold] .fold-more{display:inline}
.more-open{display:none}
.fold-more[aria-expanded="true"] .more-shut{display:none}
.fold-more[aria-expanded="true"] .more-open{display:inline}

/* --- 6. info --- */
#backdrop{position:fixed;inset:0;z-index:1;overflow:hidden;
  filter:blur(26px);opacity:.5;pointer-events:none;transform:scale(1.06)}
#backdrop .ghost{padding:0 var(--pad)}
#backdrop .ghost-grid{display:grid;grid-template-columns:repeat(4,1fr);
  grid-auto-rows:var(--row);column-gap:var(--gap)}
#backdrop .thumb{background:#dcdcdc}

/* Le scan, le nom et la bio gardent leur place, centrés l'un sur l'autre.
   C'est le haut du pied de page qui se cale : le bas de l'écran tranche le
   libellé Formation (`data-cut`), le reste se lit en défilant.
   `--head-h` et `--contact-h` sont mesurées à l'exécution par js/info.js. */
body[data-page="info"] main{padding-bottom:60px}
.info-top{display:grid;grid-template-columns:38fr 62fr;gap:calc(var(--gap) * 3);
  align-items:center;padding:10px 0 40px;
  height:calc(100dvh - var(--head-h, 58px) - var(--contact-h, 190px));
  min-height:340px}
/* Le cadre du scan déborde sur la colonne Contact : le buste passe devant les
   filets, et c'est voulu. Mais un cadre transparent attrape quand même les
   clics — Instagram et LinkedIn devenaient inatteignables. Il ne capte donc
   rien par défaut, y compris sans JS. Le suivi du regard écoute la fenêtre,
   pas l'élément ; seule la rotation au doigt a besoin des événements, et
   js/info.js les rend au buste dans cette seule branche. */
.scan{aspect-ratio:3/4;max-height:100%;pointer-events:none;
  display:flex;align-items:center;justify-content:center;color:var(--grey);font-size:14px;text-align:center}
.info-name{font-size:var(--fs-name);font-weight:var(--w-label);letter-spacing:-.035em;line-height:.95;margin:0 0 .5em}
.info-body{font-size:var(--fs-base);line-height:1.45}
.info-body p{margin:0 0 1em}
.info-foot{display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:start}
.info-foot .col{min-width:0}
.info-foot .rule-label:not(:first-child){margin-top:34px}
/* Le copyright ferme la page, tout en bas : au bord du premier écran, il
   disait au lecteur que c'était fini. */
.copyright{margin-top:70px;color:var(--grey)}

/* --- 7. page projet --- */
.project-head{margin-bottom:26px}
.project-head h1{font-size:clamp(28px,4vw,54px);font-weight:var(--w-label);letter-spacing:-.02em;margin:0 0 10px}
.project-meta{display:grid;grid-template-columns:repeat(4,1fr);column-gap:var(--gap);margin-bottom:34px}
/* Valeurs des rubriques : même traitement que la ligne de type de la grille. */
.project-meta .rule-line{font-size:17px;font-weight:var(--w-light);color:var(--grey)}

/* Bas de page : Liens, Crédits, Diffusion. Même dispositif — un libellé, un
   filet, des lignes. Colonne jusqu'au milieu, deux colonnes au-delà de 5. */
.diffusion,.links,.credits{margin-top:70px}
.diffusion-list,.links-list,.credits-list{display:grid;grid-template-columns:1fr;max-width:50%}
.diffusion-list:has(> :nth-child(6)),.links-list:has(> :nth-child(6)),
.credits-list:has(> :nth-child(6)){grid-template-columns:1fr 1fr;
  column-gap:calc(var(--gap) * 3);max-width:none}
.diffusion-list .rule-line,.links-list .rule-line,.credits-list .rule-line{
  font-size:17px;font-weight:var(--w-light);color:var(--grey)}
.links-list a{border-bottom:var(--rule) solid var(--grey)}

/* Mosaïque : des vignettes, trois à cinq par ligne. `data-cols` va de 2 à 12,
   la largeur suit le ratio natif ; les rangées ne se referment pas toutes sur
   12 et ces restes font les décalages. `data-start` accroche une image à une
   colonne précise — réservé aux pages qui rejouent une mise en page imprimée. */
.drawings{display:grid;grid-template-columns:repeat(12,1fr);gap:calc(var(--gap) / 2);
  align-items:start;margin-bottom:36px}
.drawings img{width:100%;height:auto;display:block}
.drawings [data-cols="2"]{grid-column-end:span 2}
.drawings [data-cols="3"]{grid-column-end:span 3}
.drawings [data-cols="4"]{grid-column-end:span 4}
.drawings [data-cols="5"]{grid-column-end:span 5}
.drawings [data-cols="6"]{grid-column-end:span 6}
.drawings [data-cols="7"]{grid-column-end:span 7}
.drawings [data-cols="8"]{grid-column-end:span 8}
.drawings [data-cols="9"]{grid-column-end:span 9}
.drawings [data-cols="10"]{grid-column-end:span 10}
.drawings [data-cols="11"]{grid-column-end:span 11}
.drawings [data-cols="12"]{grid-column-end:span 12}
.drawings [data-start="1"]{grid-column-start:1}
.drawings [data-start="2"]{grid-column-start:2}
.drawings [data-start="3"]{grid-column-start:3}
.drawings [data-start="4"]{grid-column-start:4}
.drawings [data-start="5"]{grid-column-start:5}
.drawings [data-start="6"]{grid-column-start:6}
.drawings [data-start="7"]{grid-column-start:7}
.drawings [data-start="8"]{grid-column-start:8}
.drawings [data-start="9"]{grid-column-start:9}
.drawings [data-start="10"]{grid-column-start:10}
.drawings [data-start="11"]{grid-column-start:11}
.drawings [data-drop="1"]{margin-top:8%}
.drawings [data-drop="2"]{margin-top:16%}
.drawings [data-drop="3"]{margin-top:30%}
.drawings img{cursor:zoom-in}
.drawings-title{margin:0 0 var(--gap)}
/* Liens remontés sous le texte (Réalitude, Awakening) : ils prolongent la
   lecture au lieu de fermer la page. Il leur faut alors l'air d'un bloc de
   bas de page avant la mosaïque. */
.links + .drawings-title{margin-top:60px}
/* Mosaïque repliée : la rubrique n'ouvre que sur ses premières images, le
   bouton déroule le reste. Seul js/fold.js pose `data-fold` — sans lui,
   toutes les images sont là et le bouton reste masqué (CLAUDE.md §2). */
.drawings-fold{margin-bottom:36px}
.drawings-fold .drawings{margin-bottom:14px}
.drawings-fold .drawings-actions{font-size:16px;color:var(--grey)}
/* Rien à déplier : js/fold.js pose `data-full` et le bouton disparaît. */
.drawings-fold[data-full] .fold-more{display:none}
.drawings a{display:block}
/* `.drawings a{display:block}` l'emporterait sur la règle navigateur de
   `[hidden]` : sans cette ligne, le repli ne masquerait rien. */
.drawings a[hidden]{display:none}

/* Plein écran d'un dessin. L'en-tête reste au-dessus : z-index inférieur. */
#lightbox{position:fixed;inset:0;z-index:25;background:var(--bg);
  display:flex;align-items:center;justify-content:center;padding:92px var(--pad) 40px}
#lightbox[hidden]{display:none}
.lightbox-img{max-width:100%;max-height:100%;object-fit:contain;display:block}
.lightbox-prev,.lightbox-next{position:absolute;top:0;bottom:0;width:36%;
  display:flex;align-items:center;padding:0 30px;background:none;border:0}
.lightbox-prev{left:0;justify-content:flex-start;cursor:w-resize}
.lightbox-next{right:0;justify-content:flex-end;cursor:e-resize}
.lightbox-prev svg,.lightbox-next svg{width:20px;height:36px;color:var(--ink);opacity:.3}
.lightbox-prev:hover svg,.lightbox-next:hover svg{opacity:1}
.lightbox-close{color:var(--grey);display:none}
body[data-lightbox="open"]{overflow:hidden}
body[data-lightbox="open"] .lightbox-close{display:inline}
body[data-lightbox="open"] nav a:not([aria-current]),
body[data-lightbox="open"] .lang{display:none}
/* Vidéo : toute la largeur du site, quitte à dépasser la hauteur visible.
   `--video-ratio` porte le ratio réel du film — un conteneur en 16/9 pour un
   film qui ne l'est pas laisserait Vimeo border la vignette de gris. */
.video{position:relative;aspect-ratio:var(--video-ratio,16/9);background:var(--placeholder);
  margin:0 0 56px;width:100%}
.video iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
/* Un projet sans film ouvre sur une image, au même cadre que la vidéo. */
.video img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.project-text{font-size:var(--fs-base);line-height:1.45;margin-bottom:50px;
  columns:2;column-gap:calc(var(--gap) * 3)}
.project-text[data-single]{columns:auto;max-width:62ch}
.project-text p{margin:0 0 1em;break-inside:avoid}
.project-text .rule-label{break-after:avoid;break-inside:avoid;margin-bottom:10px}
.project-text > :first-child{margin-top:0}

/* Solidaritude : la rubrique Extraits rejoue la mise en page imprimée du livre.
   Une `.spread` est une double page — une `.spread-page` par page, ou une seule
   qui court sur les deux — et se lit comme un écran : sa hauteur minimale donne
   au défilement la cadence du feuilletage. `pre-line` garde les retours à la
   ligne de l'œuvre, ils en font partie. Ce texte n'est pas traduit (§6). */
.spread{display:grid;grid-template-columns:var(--pages, 1fr 1fr);
  gap:calc(var(--gap) * 3);align-items:start;
  min-height:calc(100dvh - var(--head-h, 58px) - 90px);margin:0 0 90px}
.spread-page{min-width:0}
.spread-page:only-child{grid-column:1 / -1}
.spread .drawings{margin-bottom:0}
.book-text{font-size:var(--fs-base);line-height:1.5;white-space:pre-line;
  margin-bottom:34px}
.book-title{font-size:var(--fs-base);line-height:1.5;
  margin:0 0 clamp(60px, 14vh, 150px)}
.book-file{margin:0 0 46px;color:var(--grey)}
.book-file a{border-bottom:var(--rule) solid var(--grey)}

/* Plein écran d'une vidéo depuis la grille (Showreel). Contrairement à la
   vidéo d'une page projet, elle tient ici dans la hauteur visible. */
#player{position:fixed;inset:0;z-index:25;background:var(--bg);
  display:flex;align-items:center;justify-content:center;padding:92px var(--pad) 40px}
#player[hidden]{display:none}
.player-frame{position:relative;aspect-ratio:var(--video-ratio,16/9);
  width:min(100%, (100vh - 132px) * var(--video-ratio,16/9))}
.player-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}

/* --- 8. responsive --- */
@media(max-width:900px){
  #grid,#backdrop .ghost-grid{grid-template-columns:repeat(2,1fr)}
  .card[data-cols="3"]{grid-column:span 2}
  .diffusion-list:has(> :nth-child(6)),.links-list:has(> :nth-child(6)),
  .credits-list:has(> :nth-child(6)){grid-template-columns:1fr;max-width:none}
  .spread{grid-template-columns:1fr;gap:34px;min-height:0}
  .drawings [data-start]{grid-column-start:auto}
  .drawings [data-drop]{margin-top:0}
  .project-meta{grid-template-columns:repeat(2,1fr)}
  .project-text{columns:1}
  .entry-abstract{columns:1}
  .text-index[data-fold] .entry-abstract:not([data-open]){max-width:none}
  .drawings{grid-template-columns:repeat(6,1fr)}
  .drawings [data-cols]{grid-column-start:auto;grid-column-end:span 2}
  .drawings [data-cols="4"],.drawings [data-cols="5"]{grid-column-end:span 3}
  .drawings [data-cols="6"],.drawings [data-cols="7"],.drawings [data-cols="8"],
  .drawings [data-cols="9"],.drawings [data-cols="10"],.drawings [data-cols="11"],
  .drawings [data-cols="12"]{grid-column-end:span 6}
  .info-top{grid-template-columns:1fr;gap:34px;padding:0 0 40px;height:auto;min-height:0}
  .scan{max-height:none}
  .info-foot{grid-template-columns:1fr;gap:34px}
}
/* Téléphone. La deuxième condition attrape le paysage, où la largeur repasse
   au-dessus de 560px mais où l'on est toujours sur un téléphone : la règle est
   la hauteur, pas la largeur. Une image par ligne, pleine largeur, dans les
   deux orientations — c'est la mise en page d'adeus sur mobile (_refs/). */
@media(max-width:560px), (max-width:1024px) and (max-height:520px){
  #grid{grid-template-columns:1fr}
  .card[data-cols]{grid-column:span 1}
  .diffusion-list,.links-list,.credits-list{max-width:none}
  .project-meta{grid-template-columns:1fr}
  .project-text{columns:1}
  .entry-abstract{columns:1}
  .text-index[data-fold] .entry-abstract:not([data-open]){max-width:none}
  .spread{grid-template-columns:1fr;gap:34px;min-height:0}
  .info-top{grid-template-columns:1fr;gap:34px;padding:0 0 40px;height:auto;min-height:0}
  .scan{max-height:none}
  .info-foot{grid-template-columns:1fr;gap:34px}
  .diffusion-list:has(> :nth-child(6)),.links-list:has(> :nth-child(6)),
  .credits-list:has(> :nth-child(6)){grid-template-columns:1fr;max-width:none}
  /* Mosaïque : une image par ligne. Les largeurs restent écrites en
     `grid-column-end:span N` — js/fold.js les relit pour couper les rangées. */
  .drawings{grid-template-columns:1fr}
  .drawings [data-cols],
  .drawings [data-cols="2"],.drawings [data-cols="3"],.drawings [data-cols="4"],
  .drawings [data-cols="5"],.drawings [data-cols="6"],.drawings [data-cols="7"],
  .drawings [data-cols="8"],.drawings [data-cols="9"],.drawings [data-cols="10"],
  .drawings [data-cols="11"],.drawings [data-cols="12"]{
    grid-column-start:auto;grid-column-end:span 1}
  .drawings [data-start]{grid-column-start:auto}
  .drawings [data-drop]{margin-top:0}
  header{flex-wrap:wrap;justify-content:flex-start}
  .lang{position:static;margin-left:auto}
  /* Plein écran : sur un écran court, 132px de marge verticale ne laissaient
     presque rien à l'image. */
  #lightbox,#player{padding:76px var(--pad) 24px}
  .player-frame{width:min(100%, (100dvh - 100px) * var(--video-ratio,16/9))}
  .lightbox-prev,.lightbox-next{width:28%;padding:0 12px}
}
@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
