/*
  Couche interactive, barre méta, curseur de mise au point, vitrine projets à
  molette, micro-animations.

  Cette feuille s'ajoute aux précédentes sans rien remplacer : elle n'introduit
  aucune couleur ni aucune graisse qui ne soit déjà dans tokens.css. Tout ce qui
  bouge ici est un enrichissement, si le JS ne s'exécute pas, la page reste
  celle d'avant, en état lisible (voir les classes .no-js ci-dessous).
*/

/* ---------- Ajouts au vocabulaire existant ---------- */

/*
  [hidden] ne vient que de la feuille de style du navigateur : la moindre classe
  qui pose un display la neutralise. .grid le faisait, la grille de repli
  restait affichée sous la vitrine, et la page montrait deux fois les mêmes
  projets. On rend l'attribut réellement contraignant.
*/
[hidden] { display: none !important; }

/*
  Fondu d'ouverture. Délibérément en CSS et pas en JS : une animation CSS se
  termine quoi qu'il arrive, alors qu'un fondu piloté par le rAF laisse la page
  à opacité nulle tant que l'onglet reste en arrière-plan. Le contenu ne doit
  jamais dépendre d'une boucle d'animation pour devenir visible.
*/
@keyframes page-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

body {
  animation: page-in 380ms var(--ease-standard) backwards;
}

@media (prefers-reduced-motion: reduce) {
  body { animation: none; }
}

:root {
  --meta-size: 0.6875rem;        /* 11px, l'échelle « technique » de la barre méta */
  --meta-tracking: 0.09em;
  --rule: #E7E2DE;               /* filet clair, sur fond blanc comme sur fond crème */
  --tick: #CFC7C1;
}

/* ---------- Barre méta ---------- */

.meta-bar {
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-body);
  font-size: var(--meta-size);
  font-weight: 500;
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--color-meta);
}

.meta-bar__inner {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 2.25rem;
}

.meta-bar__sep,
.meta-bar__focus {
  color: var(--tick);
}

/* Pousse le statut à droite ; il disparaît avant que la ligne ne se casse. */
.meta-bar__status {
  margin-left: auto;
}

.meta-bar__time {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  /* Les chiffres changent chaque seconde : sans chasse fixe, toute la ligne
     tressaute. tabular-nums d'abord, largeur plancher en secours si la police
     ne fournit pas la variante. */
  font-variant-numeric: tabular-nums;
}

.meta-bar__time time {
  display: inline-block;
  min-width: 7.5ch;
}

.meta-bar__dot {
  width: 0.4em;
  height: 0.4em;
  border-radius: 50%;
  background: var(--color-accent);
}

@media (prefers-reduced-motion: no-preference) {
  .meta-bar__dot { animation: meta-pulse 2.4s var(--ease-standard) infinite; }
}

@keyframes meta-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.35; transform: scale(0.75); }
}

.meta-bar__focus svg {
  display: block;
  width: 0.9rem;
  height: 0.9rem;
}

/* Sous 780px il ne reste que la ville et l'heure : le reste ne tiendrait pas
   sans réduire la typo sous le seuil de lisibilité. */
@media (max-width: 779px) {
  .meta-bar__status,
  .meta-bar__focus { display: none; }
}

/* Compteur en exposant sur la navigation ("Mon travail³") */
.site-nav__count {
  font-size: 0.65em;
  vertical-align: super;
  letter-spacing: 0;
  color: var(--color-accent-text);
}

/* ---------- Curseur de mise au point ---------- */

/*
  Quatre équerres qui suivent le pointeur et se verrouillent sur l'élément
  survolé, à la manière d'un collimateur d'autofocus. Réservé aux pointeurs
  fins : au doigt il n'y a pas de survol, et sur un écran tactile le curseur
  resterait figé dans un coin. Le curseur natif n'est jamais masqué, si le
  script tombe, on ne se retrouve pas sans pointeur.
*/

.focus-ring {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 900;
  width: 0;
  height: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-standard);
}

.focus-ring.is-active { opacity: 1; }

.focus-ring__corner {
  position: absolute;
  width: 10px;
  height: 10px;
  border: 1.5px solid var(--color-accent);
  transition: border-color var(--duration-fast) var(--ease-standard);
}

.focus-ring__corner--tl { border-right: 0; border-bottom: 0; }
.focus-ring__corner--tr { border-left: 0;  border-bottom: 0; }
.focus-ring__corner--bl { border-right: 0; border-top: 0; }
.focus-ring__corner--br { border-left: 0;  border-top: 0; }

/* Verrouillé sur une cible : les équerres passent en noir d'encre, comme un
   AF qui confirme. */
.focus-ring.is-locked .focus-ring__corner {
  border-color: var(--color-headline);
}

.focus-ring__label {
  position: absolute;
  left: 50%;
  transform: translate(-50%, 0.75rem);
  font-family: var(--font-body);
  font-size: var(--meta-size);
  font-weight: 700;
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--color-headline);
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-standard);
}

.focus-ring.is-locked .focus-ring__label { opacity: 1; }

@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .focus-ring { display: none; }
}

/* ---------- Menu mobile : le panneau ---------- */

/*
  Le panneau descend comme un volet sur un fond sombre nu, les entrées sont
  numérotées comme des plans, et le pied reprend les informations techniques de
  la barre méta, masquée derrière le panneau une fois celui-ci ouvert.

  Numéros et pied sont injectés par nav.js : le même bloc <nav> est répété dans
  les sept pages, le dupliquer sept fois le condamnait à diverger.
*/

.is-nav-open {
  overflow: hidden;
}

/*
  Le header reste au-dessus du panneau (z-index 100 contre 90) pour que le
  bouton de fermeture demeure atteignable, mais son fond blanc poserait alors
  un bandeau clair en travers du panneau sombre. On le rend transparent, et on
  efface la barre méta : son contenu est repris au pied du panneau.
*/
.is-nav-open .site-header {
  background: transparent;
}

.is-nav-open .meta-bar {
  opacity: 0;
  pointer-events: none;
  border-bottom-color: transparent;
}

.mobile-nav {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--color-contact-bg);
  color: var(--color-contact-heading);
  border-top: 0;
  overflow-y: auto;
  overscroll-behavior: contain;

  /* Le volet descend. visibility retire le panneau de l'ordre de tabulation
     quand il est fermé, clip-path seul le masque sans le rendre inatteignable. */
  visibility: hidden;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 560ms var(--ease-out-expo),
              visibility 0s linear 560ms;
}

.mobile-nav[data-open="true"] {
  visibility: visible;
  clip-path: inset(0 0 0 0);
  transition: clip-path 560ms var(--ease-out-expo),
              visibility 0s;
}

.mobile-nav__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-height: 100%;
  justify-content: center;
  /* Dégage le header en surimpression au-dessus, et le pied en dessous. Le
     retrait latéral vient de .container : le menu s'aligne ainsi sur le bord
     gauche du reste du site. */
  padding-block: 8rem 9rem;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.25rem, 1.3rem + 5.2vw, 3.5rem);
}

.mobile-nav__item a {
  display: flex;
  align-items: baseline;
  gap: 0.55em;
  padding: 0.12em 0;
  color: var(--color-contact-heading);
  line-height: 1;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
  transition: color var(--duration-fast) var(--ease-standard);
}

.mobile-nav__item a[aria-current="page"] {
  color: var(--color-accent);
  font-weight: 400;
}

.mobile-nav__item a:active {
  color: var(--color-accent);
}

.mobile-nav__num {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.6875rem;
  letter-spacing: var(--meta-tracking);
  color: var(--color-accent);
  font-variant-numeric: tabular-nums;
}

/*
  Chaque entrée s'expose de gauche à droite, comme une image qui vient au
  révélateur. Le rang vient de --rank, posé par nav.js : ajouter une entrée au
  menu ne demande aucune règle supplémentaire ici.
*/
@keyframes frame-in {
  from {
    opacity: 0;
    clip-path: inset(0 100% 0 0);
    transform: translateX(-10px);
  }
  to {
    opacity: 1;
    clip-path: inset(0 -5% 0 0);
    transform: none;
  }
}

.mobile-nav[data-open="true"] .mobile-nav__item {
  animation: frame-in 620ms var(--ease-out-expo) both;
  animation-delay: calc(180ms + var(--rank, 0) * 75ms);
}

.mobile-nav__foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--space-5);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--meta-size);
  font-weight: 500;
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  /* Atténué à partir de la couleur du panneau plutôt qu'avec un gris inventé :
     un ton de plus dans la palette serait un ton à maintenir. */
  color: var(--color-contact-heading);
  opacity: 0.55;
  font-variant-numeric: tabular-nums;
}

.mobile-nav__time {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
}

.mobile-nav__foot-end { margin-left: auto; }

/* Trois informations sur une ligne sans retour : sous 480px le statut saute,
   il est déjà visible dans la barre méta une fois le panneau refermé. */
@media (max-width: 479px) {
  .mobile-nav__foot-end { display: none; }
}

/*
  Le panneau est un enfant de <header> avec z-index:90. La rangée logo + bouton,
  elle, n'est pas positionnée : elle se peint donc SOUS lui, et le logo
  disparaissait derrière le panneau ouvert. On positionne la rangée pour la
  faire remonter au-dessus.
*/
.site-header__inner {
  position: relative;
  z-index: 100;
}

/* Bouton : hamburger fermé, croix ouverte. Les deux icônes sont superposées et
   pivotent l'une dans l'autre. `position: relative` sert aussi d'ancrage à la
   croix, qui est en absolu. */
.nav-toggle {
  position: relative;
}

.nav-toggle__open,
.nav-toggle__close {
  transition: opacity var(--duration-fast) var(--ease-standard),
              transform var(--duration-base) var(--ease-out-expo);
}

.nav-toggle__close {
  position: absolute;
  inset: 0;
  margin: auto;
  opacity: 0;
  transform: rotate(-90deg);
}

.nav-toggle[aria-expanded="true"] {
  color: var(--color-contact-heading);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__open {
  opacity: 0;
  transform: rotate(90deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__close {
  opacity: 1;
  transform: rotate(0deg);
}

@media (prefers-reduced-motion: reduce) {
  .mobile-nav,
  .mobile-nav[data-open="true"] {
    transition: none;
  }

  .mobile-nav[data-open="true"] .mobile-nav__item {
    animation: none;
  }
}

/* ---------- Vitrine projets ---------- */

.showcase {
  position: relative;
}

.showcase__stage {
  display: grid;
  gap: var(--space-5);
  align-items: start;
}

@media (min-width: 860px) {
  .showcase__stage {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: var(--space-7);
  }
}

.showcase__media {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--color-placeholder);
}

.showcase__media img,
.showcase__media canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Le canvas prend le relais de l'image une fois la texture chargée. L'image
   reste dans le DOM : c'est elle qui porte le alt et qui s'affiche si WebGL
   n'est pas disponible. */
.showcase__media canvas {
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-standard);
}

.showcase__media.is-gl canvas { opacity: 1; }
.showcase__media.is-gl img { opacity: 0; }

.showcase__media img {
  transition: opacity var(--duration-base) var(--ease-standard);
}

.showcase__index {
  font-family: var(--font-display);
  font-size: var(--step-md);
  letter-spacing: var(--tracking-display);
  color: var(--color-accent);
}

.showcase__title {
  margin-top: 0.1em;
  font-family: var(--font-display);
  font-size: var(--step-xl);
  line-height: 1;
  letter-spacing: var(--tracking-display);
  color: var(--color-headline);
  text-transform: uppercase;
}

.showcase__desc {
  margin-top: var(--space-3);
  font-size: var(--step-body);
  color: var(--color-body);
  max-width: 34ch;
}

.showcase__cta {
  margin-top: var(--space-4);
}

/*
  Un panneau par projet, tous présents dans le DOM, seul l'actif est affiché.
  On ne réécrit pas le texte d'un panneau unique : le contenu des autres projets
  reste ainsi indexable, et la bascule se réduit à un changement de visibilité.
*/
.showcase__panel[hidden] { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .showcase__panel:not([hidden]) {
    animation: showcase-panel-in var(--duration-base) var(--ease-out-expo) both;
  }
}

@keyframes showcase-panel-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Molette graduée ---------- */

.dial {
  position: relative;
  margin-top: var(--space-6);
  padding-block: var(--space-4);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  overflow: hidden;
  user-select: none;
  touch-action: pan-y;   /* le doigt continue de faire défiler la page */
}

@media (pointer: fine) {
  .dial { cursor: ew-resize; }
  .dial.is-dragging { cursor: grabbing; }
}

/*
  Les graduations sont un dégradé répété dont on décale la position : c'est un
  seul élément et une seule propriété animée, là où des centaines de <span>
  coûteraient un layout à chaque frame.
*/
.dial__ticks {
  height: 0.75rem;
  background-image: repeating-linear-gradient(
    to right,
    var(--tick) 0 1px,
    transparent 1px 10px
  );
  background-position-x: 0;
  opacity: 0.85;
}

.dial__ticks--major {
  height: 1.25rem;
  background-image: repeating-linear-gradient(
    to right,
    var(--tick) 0 1px,
    transparent 1px 50px
  );
}

.dial__track {
  position: relative;
  height: 4.5rem;
  margin-block: var(--space-2);
}

.dial__item {
  position: absolute;
  top: 50%;
  left: 0;
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1.2rem + 2.4vw, 3.25rem);
  line-height: 1;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
  color: var(--color-placeholder);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  will-change: transform, opacity;
  transition: color var(--duration-base) var(--ease-standard);
}

.dial__item.is-current { color: var(--color-headline); }

.dial__item:hover { color: var(--color-accent-text); }

/* Repère central : c'est lui qui matérialise « le projet sélectionné ». */
.dial__needle {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--color-headline);
  transform: translateX(-50%);
  pointer-events: none;
}

.dial__needle::before,
.dial__needle::after {
  content: "";
  position: absolute;
  left: 50%;
  width: 5px;
  height: 5px;
  background: var(--color-accent);
  transform: translateX(-50%) rotate(45deg);
}

.dial__needle::before { top: -2px; }
.dial__needle::after  { bottom: -2px; }

/* ---------- Barre de transport (01 // 03, flèches) ---------- */

.transport {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  font-family: var(--font-body);
  font-size: var(--meta-size);
  font-weight: 700;
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--color-meta);
  font-variant-numeric: tabular-nums;
}

.transport__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--rule);
  color: var(--color-headline);
  transition: border-color var(--duration-fast) var(--ease-standard),
              background-color var(--duration-fast) var(--ease-standard);
}

.transport__btn:hover,
.transport__btn:focus-visible {
  border-color: var(--color-headline);
  background: var(--color-bg-muted);
}

.transport__btn[disabled] {
  opacity: 0.3;
  cursor: default;
}

.transport__count { min-width: 2.5ch; text-align: center; }

.transport__total { color: var(--color-placeholder); }

/* ---------- Frise du parcours ---------- */

.timeline {
  position: relative;
  margin-top: var(--space-6);
  padding-left: 3.25rem;
}

@media (min-width: 780px) {
  .timeline { padding-left: 5rem; }
}

/*
  Rail en pointillés, repris du vocabulaire gradué de la molette. Le trait plein
  qui le recouvre se remplit à mesure qu'on descend (voir timeline() dans
  motion.js) ; sans JS, il reste à zéro et le pointillé suffit à tenir la
  colonne.
*/
.timeline__rail {
  position: absolute;
  left: 0.75rem;
  top: 0.5rem;
  bottom: 0.5rem;
  width: 1px;
  background-image: repeating-linear-gradient(
    to bottom,
    var(--tick) 0 4px,
    transparent 4px 11px
  );
}

@media (min-width: 780px) {
  .timeline__rail { left: 1.5rem; }
}

.timeline__progress {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 0;
  background: var(--color-accent);
}

.timeline__list {
  display: grid;
  gap: var(--space-5);
}

/*
  Une entrée = trois informations et rien d'autre : années, intitulé,
  entreprise. Empilées sur mobile ; à partir de 780px les années passent dans
  une colonne fixe à gauche, comme sur un CV, pour que l'œil puisse descendre
  la chronologie sans relire les intitulés.
*/
.timeline__entry {
  position: relative;
  display: grid;
  gap: 0.15rem;
}

@media (min-width: 780px) {
  .timeline__entry {
    /* Calée sur le libellé le plus long, « 2020 – aujourd'hui », point de
       mission en cours compris. Plus étroite, c'est la seule ligne de la frise
       qui passerait sur deux niveaux. */
    grid-template-columns: 10.5rem minmax(0, 1fr);
    column-gap: var(--space-4);
    row-gap: 0.15rem;
    align-items: baseline;
  }

  .timeline__when  { grid-column: 1; grid-row: 1 / span 2; }
  .timeline__title { grid-column: 2; grid-row: 1; }
  .timeline__org   { grid-column: 2; grid-row: 2; }
}

/* Pastille sur le rail. Recentrée sur le trait via translateX(-50%), pour ne
   pas avoir à corriger à la main quand le retrait change au point de rupture. */
.timeline__entry::before {
  content: "";
  position: absolute;
  left: -2.5rem;
  top: 0.5rem;
  width: 9px;
  height: 9px;
  border: 1.5px solid var(--tick);
  border-radius: 50%;
  background: var(--color-bg-muted);
  transform: translateX(-50%);
  transition: border-color var(--duration-base) var(--ease-standard),
              background-color var(--duration-base) var(--ease-standard);
}

@media (min-width: 780px) {
  .timeline__entry::before { left: -3.5rem; }
}

.timeline__entry.is-passed::before {
  border-color: var(--color-accent);
  background: var(--color-accent);
}

.timeline__when {
  font-family: var(--font-body);
  font-size: var(--meta-size);
  font-weight: 700;
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--color-accent-text);
  /* Chasse fixe : les colonnes d'années doivent s'aligner verticalement. */
  font-variant-numeric: tabular-nums;
}

/*
  Mission en cours. Le point reprend celui de la barre méta, où il signale la
  disponibilité : même signe, même sens, « ceci est vrai maintenant ».
*/
.timeline__when--live {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
}

.timeline__live {
  width: 0.4em;
  height: 0.4em;
  border-radius: 50%;
  background: var(--color-accent);
  flex-shrink: 0;
  /* Aligné sur l'œil des capitales plutôt que sur la ligne de base, où il
     paraîtrait posé trop bas. */
  transform: translateY(-0.15em);
}

@media (prefers-reduced-motion: no-preference) {
  .timeline__live { animation: meta-pulse 2.4s var(--ease-standard) infinite; }
}

.timeline__title {
  font-family: var(--font-display);
  font-size: var(--step-md);
  line-height: 1.05;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
  color: var(--color-headline);
}

.timeline__org {
  font-family: var(--font-body);
  font-size: var(--step-ui);
  font-weight: 500;
  color: var(--color-meta);
  max-width: 46ch;
}

/* ---------- Hobbies ---------- */

/*
  Cinq entrées courtes, traitées comme une fiche technique : un filet, un
  numéro, un nom. Pas d'effet au survol, rien ici n'est cliquable, et un
  changement d'état laisserait croire le contraire.
*/
.hobbies {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-5);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 700px) {
  .hobbies { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Au-delà de 980px les cinq tiennent sur une seule ligne. */
@media (min-width: 980px) {
  .hobbies {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--space-3);
  }
}

.hobbies__item {
  padding-top: var(--space-3);
  border-top: 1px solid var(--rule);
}

.hobbies__num {
  display: block;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--meta-size);
  letter-spacing: var(--meta-tracking);
  color: var(--color-accent);
  font-variant-numeric: tabular-nums;
}

.hobbies__name {
  display: block;
  margin-top: 0.35em;
  font-family: var(--font-display);
  font-size: var(--step-md);
  line-height: 1.05;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
  color: var(--color-headline);
}

.hobbies__note {
  display: block;
  margin-top: 0.25em;
  font-family: var(--font-body);
  font-size: var(--step-ui);
  font-weight: 500;
  color: var(--color-meta);
}

/* ---------- Liste de lectures ---------- */

/*
  Un registre plutôt qu'une grille de cartes : l'étagère illustrée au-dessus
  porte déjà la charge visuelle de la page, une seconde série de visuels la
  ferait basculer dans le catalogue. Ici, des lignes réglées, un numéro d'ordre,
  et la place laissée à la typographie.
*/
.reading-list {
  margin-top: var(--space-5);
  border-top: 1px solid var(--rule);
}

.reading-list__item {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  align-items: baseline;
  column-gap: var(--space-3);
  row-gap: 0.15rem;
  padding-block: var(--space-4);
  border-bottom: 1px solid var(--rule);
  transition: background-color var(--duration-fast) var(--ease-standard),
              padding-left var(--duration-base) var(--ease-out-expo);
}

@media (min-width: 700px) {
  .reading-list__item {
    grid-template-columns: 3.5rem minmax(0, 1fr) auto;
    column-gap: var(--space-4);
  }
}

/* Le survol décale la ligne vers la droite, comme un tiroir qu'on ouvre. */
@media (hover: hover) {
  .reading-list__item:hover {
    background: var(--color-bg-muted);
    padding-left: var(--space-3);
  }
}

.reading-list__num {
  font-family: var(--font-display);
  font-size: var(--step-md);
  letter-spacing: var(--tracking-display);
  color: var(--color-accent);
  font-variant-numeric: tabular-nums;
}

.reading-list__title {
  font-family: var(--font-display);
  font-size: var(--step-lg);
  line-height: 1.05;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
  color: var(--color-headline);
}

.reading-list__author {
  grid-column: 2;
  font-family: var(--font-body);
  font-size: var(--step-ui);
  font-weight: 500;
  color: var(--color-meta);
}

@media (min-width: 700px) {
  .reading-list__author {
    grid-column: 3;
    grid-row: 1;
    text-align: right;
    white-space: nowrap;
  }
}

/* ---------- Mise au point des titres ---------- */

/*
  Le titre arrive flou et vient accrocher la netteté, avec le bref dépassement
  d'un autofocus qui verrouille sa cible (le pic de netteté à 55%, le léger
  retour de flou à 72%, puis le calage). Même grammaire que le curseur
  collimateur et l'icône de la barre méta.

  Trois raisons de le faire en CSS plutôt qu'en JS :
  - une animation CSS se termine toujours, même onglet en arrière-plan, alors
    qu'un tween piloté par le rAF laisserait le titre invisible ;
  - sans JavaScript, la classe n'est jamais posée et le titre s'affiche
    simplement, le texte ne dépend d'aucune animation pour exister ;
  - rien n'est découpé en <span>, donc le titre reste un nœud de texte unique
    pour les lecteurs d'écran, sans aria-label de rattrapage.
*/
@keyframes rack-focus {
  0% {
    opacity: 0;
    filter: blur(14px);
    transform: scale(1.028) translateY(5px);
  }
  55% {
    opacity: 1;
    filter: blur(0);
    transform: none;
  }
  72% {
    filter: blur(2.4px);
  }
  100% {
    opacity: 1;
    filter: blur(0);
    transform: none;
  }
}

[data-focus-in].is-focusing {
  animation: rack-focus 1.15s var(--ease-out-expo) both;
}

@media (prefers-reduced-motion: reduce) {
  [data-focus-in].is-focusing { animation: none; }
}

/* ---------- Repli sans JavaScript ---------- */

/*
  La vitrine est rendue par showcase.js. Tant qu'elle ne l'est pas, script en
  échec, JS coupé , c'est la liste statique qui reste visible ; showcase.js la
  masque lui-même une fois qu'il a pris la main.
*/
.showcase[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .showcase__media canvas { display: none; }
  .showcase__media img { opacity: 1 !important; }
  .dial__item { transition: none; }
}
