/* ============================================================
   Delvigne Lab — Responsive layer (shared across all pages)
   Breakpoints:  phone < 640px · tablet 640–1024px · desktop > 1024px
   Loaded AFTER each page's inline <style>, so it adapts the existing
   desktop design down to tablet and phone. Mobile-first in spirit:
   the base (desktop) is progressively simplified as the screen shrinks.
   ============================================================ */

/* ---- Global safety: never scroll sideways, media stays fluid ---- */
/* ⚠️ `clip`, PAS `hidden` — et les deux lignes sont nécessaires.
   `overflow-x:hidden` fait de <body> un conteneur de défilement, ce qui casse
   silencieusement tout `position:sticky` du site : la .toolbar de
   /publications/ ne collait pas (mesuré à -1028px au lieu de 0). `clip` coupe
   le débordement latéral — ce pour quoi la règle existe, les blocs en marge
   négative type `margin-right:calc(-50vw + 50%)` — SANS créer de conteneur de
   défilement, donc sticky refonctionne.
   La 1re ligne est le repli des navigateurs sans `clip` (Safari < 16) ; ils
   ignorent la 2de. Garder les deux, dans cet ordre.
   ⚠️ Cette feuille est chargée APRÈS le <style> inline de chaque page : une
   page qui redéfinit overflow-x de son côté est écrasée ici sans avertissement.
   C'est le seul endroit où régler ça. */
html, body { overflow-x: hidden; overflow-x: clip; }
img, svg, video, canvas, iframe, table { max-width: 100%; }
img { height: auto; }
*   { min-width: 0; }   /* let flex/grid children shrink instead of overflowing */

/* ---- En-tête : mêmes marges latérales que le contenu des pages ----
   Les 9 pages déclarent `header.site .wrap{padding:16px 0}`, donc l'en-tête
   desktop n'avait aucune marge latérale : logo et nav collaient au bord de la
   fenêtre dès qu'elle passait sous 1280px (au-dessus, le max-width de .wrap
   recréait des marges, ce qui masquait le défaut). On s'aligne sur les 56px de
   .wrap : le logo tombe enfin sur la même colonne que les titres des pages.
   Une seule écriture ici couvre les 9 pages — cette feuille est chargée après
   leurs <style> inline. Sous 1024px, les règles !important plus bas gagnent et
   ramènent l'en-tête à 40px puis 24px, en phase avec .wrap à chaque palier. */
header.site .wrap { padding-left: 56px; padding-right: 56px; }

/* ---- Burger button (hidden on desktop, shown ≤1024px) ---- */
.nav-toggle {
  display: none;                     /* desktop: hidden */
  width: 44px; height: 44px;         /* ≥44px touch target */
  padding: 10px; border: 0; margin: 0;
  background: transparent; cursor: pointer;
  flex-direction: column; align-items: flex-end; justify-content: center; gap: 5px;
}
.nav-toggle-bar {
  display: block; width: 24px; height: 2px; border-radius: 2px;
  background: var(--ink, #101a1e);
  transition: transform .25s ease, opacity .2s ease;
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.nav-toggle:focus-visible { outline: 2px solid var(--cyan, #0c8c99); outline-offset: 3px; }

/* ==================== TABLET & PHONE  (≤ 1024px) ==================== */
@media (max-width: 1024px) {
  /* 24px était trop serré dès qu'une page devient dense (liste Publications :
     le texte tombait à 26px du bord de fenêtre). Toute marge latérale se règle
     ICI et nulle part ailleurs : cette feuille est chargée après les <style>
     inline des pages, donc elle gagne — une page qui redéfinit .wrap de son côté
     est écrasée sans bruit. */
  .wrap { padding-left: 40px; padding-right: 40px; }

  /* --- Header becomes a burger menu --- */
  header.site .wrap {
    align-items: center !important;          /* override inline flex-end */
    padding: 14px 40px !important;           /* override inline 26/18 ; suit le .wrap ci-dessus */
    flex-wrap: wrap; position: relative; gap: 16px;
  }
  .nav-toggle { display: flex; }
  nav.main {
    display: none;                           /* collapsed by default */
    position: absolute; top: 100%; left: 0; right: 0; z-index: 50;
    flex-direction: column; gap: 0; padding: 6px 0;
    background: var(--paper, #fff);
    border-bottom: 1px solid var(--ink, #101a1e);
    box-shadow: 0 18px 30px rgba(16, 26, 30, .10);
  }
  nav.main.open { display: flex; }           /* toggled open by menu.js */
  nav.main a {
    display: flex; align-items: center;
    min-height: 44px; padding: 6px 24px; font-size: 18px;
  }
  nav.main a::after { display: none; }        /* no slide-underline on touch */
  nav.main a.active { border-bottom: 0; color: var(--cyan, #0c8c99); }

  /* --- Card grids: 4/3-up → 2-up --- */
  .explore, .stats, .people, .grid, .news-grid { grid-template-columns: repeat(2, 1fr); }

  /* Explore cyan cards: swap the vertical divider for a horizontal one once stacked */
  .explore .card { border-right: 0; border-bottom: 1px solid rgba(255, 255, 255, .14); }
  .explore .card:last-child { border-bottom: 0; }

  /* Arrondi des coins du bandeau une fois en 2×2 (cf. index.php pour le 4-en-ligne).
     :not(:hover) → au survol c'est le border-radius:16px complet qui doit gagner,
     quel que soit l'ordre de chargement des feuilles. */
  .explore .card:nth-child(1):not(:hover):not(:focus-visible) { border-radius: 16px 0 0 0; }
  .explore .card:nth-child(2):not(:hover):not(:focus-visible) { border-radius: 0 16px 0 0; }
  .explore .card:nth-child(3):not(:hover):not(:focus-visible) { border-radius: 0 0 0 16px; }
  .explore .card:nth-child(4):not(:hover):not(:focus-visible) { border-radius: 0 0 16px 0; }

  /* Survol (fenêtre desktop étroite) : re-découpe le dégradé pour 2 colonnes × 2 rangées,
     sinon la carte soulevée afficherait la mauvaise tranche. Cf. .card:hover dans index.php. */
  .explore .card:hover, .explore .card:focus-visible { border-bottom-color: transparent; background-size: 200% 200%; }
  .explore .card:nth-child(1):hover, .explore .card:nth-child(1):focus-visible { background-position: 0 0; }
  .explore .card:nth-child(2):hover, .explore .card:nth-child(2):focus-visible { background-position: 100% 0; }
  .explore .card:nth-child(3):hover, .explore .card:nth-child(3):focus-visible { background-position: 0 100%; }
  .explore .card:nth-child(4):hover, .explore .card:nth-child(4):focus-visible { background-position: 100% 100%; }

  /* --- Content / media splits → stacked --- */
  .themes, .statement, .approach, .cgrid, .pi, .proj { grid-template-columns: 1fr; }
  .themes::before { display: none; }          /* central divider */

  /* --- Hero : ici on n'empile plus le texte SUR la vidéo -----------------
     En pleine largeur avec le texte par-dessus, la bande devient carrée sur un
     téléphone (mesuré à 560px : 560×558, ratio 1.00) et il ne reste que 50 % de
     la largeur de la vidéo — pire que l'ancienne mise en page. Et le voile est
     un dégradé HORIZONTAL : dès que le texte occupe toute la largeur, il ne
     protège plus rien, l'eyebrow et les liens passent sur l'image nue.
     On repasse donc en texte sur fond clair + bande vidéo.
     Le 16/9 laisse 89 % × 95 % de la vidéo visible ; à 16/10 on tombe à 80 %,
     pile sur le seuil, sans aucune marge.
     ⚠️ ORDRE : le texte AU-DESSUS de la vidéo, comme dans le DOM — donc pas
     d'`order` ici. On arrive sur le nom du labo et le h1, pas sur une vidéo qui
     repousse le premier texte utile sous la ligne de flottaison. Une version
     intermédiaire mettait la vidéo en premier (`order:-1`) ; c'est ce défaut
     qui l'a fait retirer. Ne pas le réintroduire. */
  .hero          { flex-direction: column; min-height: 0; background: var(--paper); }
  .hero-media    { position: relative; width: 100%; aspect-ratio: 16 / 9; }
  .hero-scrim    { display: none; }
  /* plus d'ombre portée : le texte est sur fond clair, elle le salirait */
  .hero-copy .in { text-shadow: none; }
  .hero-copy .in { max-width: none; padding: 28px 0 36px; }
  /* Le texte n'est plus sur l'image → retour aux couleurs du site. Elles sont
     toutes dérivées de ces cinq variables, définies dans index.php : en
     redéfinir une seule ici suffit, impossible d'en oublier une au passage. */
  .hero { --accent: var(--cyan); --fg: var(--ink); --fg-mut: var(--mut);
          --fg-dim: var(--mut); --fg-rule: var(--rule); }

}

/* ======================== PHONE  (≤ 640px) ======================== */
@media (max-width: 640px) {
  .wrap { padding-left: 24px; padding-right: 24px; }
  header.site .wrap { padding: 12px 24px !important; }

  /* Single column everywhere except the people/team grids (kept 2-up) */
  .explore, .stats, .news-grid { grid-template-columns: 1fr; }
  .people, .grid { grid-template-columns: repeat(2, 1fr); }

  /* Arrondi des coins du bandeau une fois en 1 colonne (cf. bloc ≤1024px) */
  .explore .card:nth-child(1):not(:hover):not(:focus-visible) { border-radius: 16px 16px 0 0; }
  .explore .card:nth-child(2):not(:hover):not(:focus-visible),
  .explore .card:nth-child(3):not(:hover):not(:focus-visible) { border-radius: 0; }
  .explore .card:nth-child(4):not(:hover):not(:focus-visible) { border-radius: 0 0 16px 16px; }

  /* Survol : tranche du dégradé pour 1 colonne × 4 rangées (cf. bloc ≤1024px) */
  .explore .card:hover, .explore .card:focus-visible { background-size: 100% 400%; }
  .explore .card:nth-child(1):hover, .explore .card:nth-child(1):focus-visible { background-position: 0 0; }
  .explore .card:nth-child(2):hover, .explore .card:nth-child(2):focus-visible { background-position: 0 33.3333%; }
  .explore .card:nth-child(3):hover, .explore .card:nth-child(3):focus-visible { background-position: 0 66.6667%; }
  .explore .card:nth-child(4):hover, .explore .card:nth-child(4):focus-visible { background-position: 0 100%; }
  .stats .s { border-right: 0; }

  /* Publication + preview rows stack, meta aligns left */
  .pub { grid-template-columns: 1fr; gap: 6px; }
  .pub .tag, .pub .right { text-align: left; align-items: flex-start; }

  /* CTA buttons get a comfortable 44px tap height */
  .btn { display: inline-flex; align-items: center; min-height: 44px; }

  /* Fluid display type */
  .hero .lab-name   { font-size: clamp(38px, 12vw, 52px); }
  .hero h1          { font-size: clamp(30px, 8.5vw, 42px); }
  .phead h1         { font-size: clamp(32px, 9vw, 46px); }
  .statement .q p   { font-size: clamp(22px, 6vw, 28px); }

  /* Tighter vertical rhythm */
  .secpad { padding-top: 36px; padding-bottom: 28px; }

  /* Article body: keep long tables readable */
  .article-body table { font-size: 14px; }
}

/* ===== Remove desktop asymmetric offsets once columns stack (≤1024px) ===== */
@media (max-width: 1024px) {
  .approach .txt, .approach .media,
  .approach.flip .txt, .approach.flip .media { padding-left: 0; padding-right: 0; }
  /* Stacked: always text → image (drop the desktop alternation) */
  .approach.flip .txt   { order: 0; }
  .approach.flip .media { order: 0; }
  /* No justified text in a narrow column — left-align (WCAG 1.4.8) */
  .approach p { text-align: left; hyphens: manual; }
  .themes .t.r    { padding-left: 0; }
  .statement .q   { padding-right: 0; }
  .statement .fig { padding-left: 0; }
}

/* ===== PHONE: centered, symmetric structure (no desktop offsets) ===== */
@media (max-width: 640px) {
  /* Center text blocks */
  .phead, .hero-copy .in, .explore .card, .themes .t, .statement .q,
  .statement .fig, .approach .txt, .approach .media, .approach.flip .txt,
  .approach.flip .media, .pi, .person, .proj, .cgrid > *, .partners,
  .ncard { text-align: center; }
  /* Short feature text stays centered */
  .themes .t p {
    text-align: center; max-width: none; margin-left: auto; margin-right: auto;
  }
  /* Long body prose reads better left-aligned (what well-built sites do) */
  .approach p, .pi p {
    text-align: left; max-width: none; hyphens: manual;
  }

  /* Flex containers → center their items */
  .hero .cta      { justify-content: center; flex-wrap: wrap; }
  .stats .s       { justify-content: center; }
  .sec-head       { flex-direction: column; align-items: center; gap: 6px; }
  .themes .t      { flex-direction: column; align-items: center; gap: 10px; }
  .statement .fig { align-items: center; }
  .approach .media{ align-items: center; justify-content: center; }
  .person         { flex-direction: column; align-items: center; }
  .partners       { flex-direction: column; align-items: center; }
  .partners .list { justify-content: center; }
  .toolbar        { justify-content: center; }
  .toolbar .count { margin-left: 0; }
  .shead          { justify-content: center; }  /* people team section headers */
  /* Index des anciens membres : 2 colonnes → 1. Sur un téléphone, deux colonnes
     de noms + « LinkedIn ↗ » ne tiennent pas sans que tout se coupe. */
  .former         { grid-template-columns: 1fr; }

  /* Center block images / icons / portraits / figures */
  .explore .card img, .person .ph, .person .disc, .pi .disc,
  .figure, .hero p.lede { margin-left: auto; margin-right: auto; }

  /* Explore cards: smaller footprint on phone (4 stacked full-width cards
     were needlessly tall, desktop sizing carried over unchanged). */
  .explore .card    { align-items: center; min-height: 0; padding: 20px 24px; }
  .explore .card .ico { width: 28px; height: 28px; margin-bottom: 0; }
  .explore .card h2   { font-size: 19px; margin-top: 12px; }
  .explore .card p    { font-size: 13.5px; margin-top: 6px; }
  .explore .card .more{ margin-top: 10px; }

  /* Pastille LinkedIn (/people/) : elle porte `align-self:flex-start` pour ne
     pas s'étirer sur la largeur de la carte en desktop. Une fois la carte
     centrée, ce même réglage la laisse collée à gauche — seul élément de la
     fiche à ne pas être centré. Cf. .li dans people.php. */
  .person .li { align-self: center; }
}

/* ===== Footer bottom row: copyright (left) + nav (right) on ONE line, no divider on desktop ===== */
footer.site .fbot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px 28px; flex-wrap: wrap; margin-top: 34px;
}
footer.site .fbot .copy { margin: 0; }
footer.site .fbot nav { margin: 0; padding: 0; border: 0; flex-wrap: wrap; justify-content: flex-end; }

/* Mobile: stack them — menu on top with a divider under it, copyright below */
@media (max-width: 640px) {
  footer.site .fbot { flex-direction: column; align-items: center; gap: 0; margin-top: 26px; }
  footer.site .fbot nav {
    order: -1; width: 100%; justify-content: center;
    padding-bottom: 18px; margin-bottom: 16px;
    border-bottom: 1px solid rgba(255, 255, 255, .12);
  }
}

/* ===== Footer: stack the brand/nav and wrap the links (tablet + phone) ===== */
@media (max-width: 1024px) {
  footer.site .top { flex-direction: column; gap: 26px; }
  footer.site nav  { flex-wrap: wrap; gap: 10px 22px; }
  footer.site nav a { display: inline-flex; align-items: center; min-height: 40px; }
  /* GitLab + logo ULiège : à droite en desktop (align-self:stretch dans le
     <style> de chaque page), centrés dès qu'on repasse en colonne ici. */
  footer.site .foot-right { align-self: center; align-items: center; }
}
@media (max-width: 640px) {
  footer.site .top  { align-items: center; text-align: center; }
  footer.site .inst { margin-left: auto; margin-right: auto; }
  footer.site nav   { justify-content: center; }
}

/* ===== "Back to top" button (Home + Publications) ===== */
.to-top {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 46px;
  height: 46px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--cyan);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(16, 26, 30, 0.22);
  z-index: 60;
  /* Hidden until scrolled down; JS toggles .show */
  visibility: hidden;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .25s ease, transform .25s ease, visibility 0s linear .25s;
}
.to-top.show {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition: opacity .25s ease, transform .25s ease, visibility 0s;
}
.to-top:hover { background: #0a7681; }
.to-top:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.to-top svg { display: block; }

@media (max-width: 640px) {
  .to-top { right: 16px; bottom: 16px; width: 44px; height: 44px; }
}
@media (prefers-reduced-motion: reduce) {
  .to-top { transition: opacity .25s ease, visibility 0s; transform: none; }
  .to-top.show { transform: none; }
  /* Cards News : pas de lift/zoom animés */
  .ncard, .ncard .thumb img, .ncard h2 { transition: none; }
  /* Cartes explore (home) : pas de soulèvement. Le tilt JS est déjà coupé côté
     script, mais le repli CSS `transform:scale()` du survol, lui, restait animé.
     Le fond, l'ombre et la lumière au curseur restent → le survol reste lisible. */
  .explore .card:hover, .explore .card:focus-visible { transition: none; transform: none; }
}

/* --- Blocs des articles News (syntaxe :::nom) -----------------------------
   Rapatrié ici depuis news.php : TOUT le responsive vit dans cette feuille,
   chargée après le <style> inline de chaque page. */
@media (max-width: 1200px) {
  /* .article fait 960px (élargi depuis 760px le 2026-08-15, voir news.php).
     Le jeu disponible de chaque côté vaut (fenêtre - 2×padding-.wrap - 960) / 2,
     avec un padding-.wrap de 56px au-dessus de 1024px et 40px en dessous : il
     n'atteint 64px qu'à partir de 1200px de fenêtre (pile ce palier). En
     dessous, le débordement sortirait de la fenêtre — on l'annule donc ici.
     ⚠️ Ce seuil DOIT être recalculé si .article change encore de largeur : ce
     n'est pas le palier générique 1024px utilisé ailleurs sur cette feuille. */
  .news-photo { margin: 34px 0; }
  .news-photo figcaption { padding: 0; }
}
@media (max-width: 700px) {
  .news-gallery { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .news-band { grid-template-columns: 1fr; padding: 28px; gap: 22px; }
  .news-band--left { grid-template-columns: 1fr; }
  .news-band--left .news-band-media { order: 0; }
  .news-band-media img { max-height: 340px; }
  .news-callout { padding: 24px 22px; }
}
