/* ============================================================================
   LES FONDATIONS
   Remise à zéro du navigateur, réglages de texte, et la poignée de classes
   utilitaires employées partout dans le site.
   ============================================================================ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Une ancre ne doit jamais atterrir sous l'en-tête fixe. */
  scroll-padding-top: var(--ancre-haut);
}

body {
  margin: 0;
  padding-top: var(--entete-h);
  background-color: var(--creme);
  color: var(--texte-1);
  font-family: var(--sans);
  font-size: var(--fs-corps);
  line-height: 1.65;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

@media (min-width: 1024px) {
  body {
    padding-top: var(--entete-h-lg);
  }
}

/* ---------------------------------------------------------------------------
   LES TITRES

   Tout ce qui est en Newsreader demande son échelle optique. Sans elle, le
   navigateur applique la valeur par défaut — celle d'un texte de labeur — et le
   caractère perd le contraste qui fait tout son intérêt en grand. L'axe « opsz »
   de Newsreader va de 6 à 72 : les titres sont donc réglés tout en haut.
   --------------------------------------------------------------------------- */
h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: var(--serif);
  font-variation-settings: "opsz" 72;
  text-wrap: balance;
}

/* ON SE SERT ENFIN DE L'AXE QU'ON TÉLÉCHARGE. Newsreader est chargée en 200–800
   et le site n'employait que le 400 et le 500 : on paie une police variable
   pour l'utiliser comme une police statique.

   Un serif se porte d'autant plus léger qu'il est grand — à soixante pixels, le
   400 est déjà lourd. La graisse descend donc quand la taille monte, ce qui est
   exactement l'inverse de ce qu'on fait d'instinct. */
h1 {
  font-weight: 350;
}

h2 {
  font-weight: 400;
}

h3 {
  font-weight: 500;
}

/*
  Le mot mis en avant passe en italique — le vrai, celui que Newsreader dessine
  à part, pas une inclinaison calculée par le navigateur. C'est le seul ornement
  typographique que s'autorise le site, et il ne sert qu'une fois par titre.

  (Cette distinction était auparavant portée par l'axe optique poussé à son
  maximum ; Newsreader a un italique trop beau pour s'en priver.)
*/
h1 em,
h2 em,
h3 em,
.italique {
  font-style: italic;
  font-variation-settings: "opsz" 72;
}

p {
  margin: 0;
  text-wrap: pretty;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Les listes de définitions et les figures gardaient les marges du navigateur —
   un « 1em » en bas de chaque <dl>, un retrait de 40 px sur chaque <dd>. Ce sont
   des vides que personne n'a décidés : ils s'ajoutaient aux joints de la page
   (19 px de trop sous les horaires de la page contact) et se déplaçaient avec
   la taille du texte. */
dl,
dd,
figure,
blockquote {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
}

a,
button,
summary,
[role="button"] {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

img,
svg,
picture,
video {
  display: block;
  max-width: 100%;
}

address {
  font-style: normal;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* Le fond de la sélection est écrit en dur, et il doit l'être : `--accent`
   change de valeur sur chaque surface, et sur l'olive il vaudrait la balle —
   du jaune sous du texte crème, à 1,3:1. C'est donc `--creme` pour l'encre, et
   surtout pas `--btn-texte`, qui tomberait à 2,5:1 sur le pied de page. */
::selection {
  background-color: var(--terre-600);
  color: var(--creme);
}

/* ---------------------------------------------------------------------------
   LES COLONNES
   --------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--colonne);
  margin-inline: auto;
  padding-inline: var(--marge);
}

.wrapLarge {
  width: 100%;
  max-width: var(--colonne-large);
  margin-inline: auto;
  padding-inline: var(--marge);
}

/* Chaque section porte UN demi-joint de chaque côté. Le vide entre deux
   sections est donc toujours le même — un joint courant — sans que ni l'une ni
   l'autre ait à savoir ce qu'elle a pour voisine. Les exceptions se déclarent
   une par une, plus bas, et se lisent comme des exceptions. */
/* AU DOIGT, CERTAINES PHOTOGRAPHIES TOUCHENT LE BORD DE L'ÉCRAN.

   La règle du site était l'inverse : aucune photographie ne va d'un bord à
   l'autre, sauf le ruban de l'accueil. Le client a regardé la carte et la page
   contact sur son téléphone : « je n'aime pas qu'il y ait des bordures vides,
   tu les colles au côté ».

   Il a raison sur ces deux-là, et pour une raison qui n'est pas une question de
   goût : ce sont les seules photographies du site qui ne partagent PAS leur
   bord gauche avec un texte. Celles des blocs à deux colonnes s'alignent sur
   leur paragraphe, et la marge se lit comme une colonne. Celles-ci sont seules
   sur leur ligne : la marge n'y aligne plus rien, elle ne fait qu'un liseré.

   Le débordement vaut exactement la marge du site, prise à la source : la
   photographie touche donc le bord de l'écran, encoche comprise, sans jamais le
   dépasser. Au-delà de 900 px, elle rentre dans sa colonne. */
@media (max-width: 899px) {
  .duo-visuel--bordABord {
    margin-inline: calc(-1 * var(--marge));
  }
}

.section {
  position: relative;
  padding-block: var(--demi-joint);
}

/* Deux sections de même surface qui se suivent ne sont plus séparées par un
   filet. Avec l'espacement d'aujourd'hui, le vide sépare mieux qu'un trait, et
   un trait de plus ferait grille. */

/* ---------------------------------------------------------------------------
   LES BLOCS DE TEXTE COURANTS
   --------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   LA MARQUE DE SECTION

   Chaque section s'ouvre sur UN DESSIN, et chaque section a le sien.

   Avant, elles s'ouvraient toutes sur le même petit intertitre en capitales
   espacées, couleur terre battue, précédé d'un filet. Sept fois sur la page
   d'accueil, quatre fois sur la page contact. Ce qui devait être une signature
   était devenu une grammaire : on ne la lisait plus, on la sautait — et
   surtout, elle annonçait sept fois de suite la même chose, alors que le texte
   qui suit change à chaque fois.

   Le premier écran a introduit un troisième matériau à côté de la crème et de
   la typographie : le dessin en terre battue. La marque de section est ce qui
   le fait descendre dans la page.

   LA TAILLE EST DONNÉE EN HAUTEUR, jamais en largeur : c'est la seule façon
   d'obtenir le même poids optique d'une section à l'autre, avec des dessins
   dont les proportions vont du couvert (presque trois fois plus haut que large)
   à l'assiette (presque deux fois plus large que haute). Trois d'entre eux
   demandent un ajustement, écrit plus bas.
   --------------------------------------------------------------------------- */
.marque {
  display: block;
  width: auto;
  height: var(--marque-h, clamp(4.75rem, 6.6vw, 7.75rem));
  /* IL EST EN RETRAIT DU TEXTE, ET C'EST VOULU. Il était calé sur le bord
     gauche de la colonne, exactement comme le titre dessous : « les balles de
     tennis sont un peu trop collées à gauche, il ne faut pas que ce soit
     autant collé ». Un dessin n'est pas une ligne de texte — il n'a pas de
     bord franc, et aligné au pixel près sur un titre il a l'air tombé là.
     Le retrait vaut de seize pixels sur un téléphone à trente-deux sur un
     grand écran : assez pour qu'on voie que c'est un choix. */
  margin-left: clamp(1rem, 2.5vw, 2rem);
  margin-bottom: var(--sp-6);
  /* Aucun n'est parfaitement d'aplomb : c'est ce qui les empêche d'avoir l'air
     posés par une machine. */
  transform: rotate(var(--marque-r, -4deg));
  transform-origin: 30% 80%;
}

/* Chaque dessin a ses proportions, et elles vont du tube de balles (près de
   trois fois plus haut que large) aux verres (plus de trois fois plus larges
   que hauts). À hauteur égale, ils ne pèseraient pas du tout le même poids :
   chacun porte donc la sienne, réglée pour qu'ils fassent tous la même tache.

   Les deux dessins de table sont les plus couchés des huit, et ce n'est pas un
   hasard : ce sont des dessins au trait continu, une seule ligne d'un bout à
   l'autre, et une telle ligne s'étale. */
.marque--verres {
  --marque-h: clamp(2.75rem, 3.8vw, 4.25rem);
  --marque-r: 4deg;
}

.marque--couvert {
  --marque-h: clamp(3.5rem, 4.8vw, 5.5rem);
  --marque-r: -5deg;
}

.marque--balles {
  --marque-h: clamp(6rem, 8.4vw, 9.75rem);
  --marque-r: 5deg;
}

.marque--service {
  --marque-h: clamp(6rem, 8.4vw, 9.75rem);
  --marque-r: -4deg;
}

.marque--raquette {
  --marque-h: clamp(5.5rem, 7.6vw, 8.75rem);
  --marque-r: 6deg;
}

.marque--joueur {
  --marque-h: clamp(3.75rem, 5.2vw, 6rem);
  --marque-r: -3deg;
}

.marque--filet {
  --marque-h: clamp(4rem, 5.6vw, 6.5rem);
  --marque-r: 3deg;
}

.marque--baskets {
  --marque-h: clamp(3.5rem, 4.9vw, 5.75rem);
  --marque-r: -6deg;
}

/* ---------------------------------------------------------------------------
   LA DÉRIVE

   Les marques et les grands dessins des paires descendent lentement pendant
   qu'on les dépasse, et se redressent en chemin — c'est le mouvement du premier
   écran, en beaucoup plus discret : deux centimètres et huit degrés sur toute
   la traversée de l'écran, contre deux cents pixels là-haut.

   Elle est tenue par le défilement lui-même (`animation-timeline: view()`), pas
   par du JavaScript : rien ne tourne sur le fil principal, le navigateur
   compose tout seul. Là où cette mécanique n'existe pas encore — Firefox à ce
   jour — les dessins sont simplement immobiles, penchés comme au repos. Rien à
   charger, rien à rattraper.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .marque,
    .trait-dessin {
      animation: derive-dessin linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
  }
}

@keyframes derive-dessin {
  from {
    transform: translateY(1.5rem) rotate(calc(var(--marque-r, -4deg) - 4deg));
  }
  to {
    transform: translateY(-1.5rem) rotate(calc(var(--marque-r, -4deg) + 4deg));
  }
}

.titreSection {
  font-size: var(--fs-h2);
  letter-spacing: -0.02em;
  line-height: 1.06;
}

/* ---------------------------------------------------------------------------
   LA PROSE

   Tout ce qui se lit en phrases — et rien d'autre — est composé dans le serif,
   à une échelle optique basse. C'est la même police que les titres, mais à
   « opsz 16 » Newsreader change de dessin : ses déliés s'épaississent, ses
   contreformes s'ouvrent, et elle devient un caractère de labeur plutôt que
   d'affiche.

   C'est le changement le plus lourd de conséquence de toute la refonte. Mesuré
   sur le site de référence, son corps de texte est un serif de 20 px sur 30 —
   pas une grotesque. C'est de là que vient son allure de livre.

   Les listes, les horaires, la carte et les formulaires restent en Instrument
   Sans : ce sont des données qu'on parcourt, pas des phrases qu'on lit.
   --------------------------------------------------------------------------- */
.chapo,
.duo-texte > p {
  font-family: var(--serif);
  font-variation-settings: "opsz" 16;
  font-weight: 400;
  line-height: 1.55;
}

/* LA HIÉRARCHIE ÉTAIT INVERSÉE. Le chapô était peint en encre secondaire et le
   paragraphe de détail qui le SUIT héritait de l'encre principale : la phrase
   d'accroche était donc plus pâle que le détail. Deux fois sur l'accueil, et
   repris sur les trois autres pages. Le chapô reprend l'encre pleine, et c'est
   au paragraphe suivant de reculer — voir `.duo-texte > p + p`. */
.chapo {
  max-width: 56ch;
  margin-top: var(--sp-5);
  color: var(--encre);
  font-size: var(--fs-chapo);
  /* À vingt-six pixels, un interlignage de 1,55 dessine une grille : on le
     resserre à mesure que le corps grandit. */
  line-height: 1.4;
}

.mention {
  max-width: 66ch;
  color: var(--encre-3);
  font-size: var(--fs-legende);
  line-height: 1.5;
}

/* ---------------------------------------------------------------------------
   L'ACCESSIBILITÉ
   --------------------------------------------------------------------------- */
.visuallyHidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  white-space: nowrap;
  border: 0;
  clip-path: inset(50%);
}

.lienEvitement {
  position: absolute;
  top: var(--sp-4);
  left: var(--sp-4);
  z-index: 100;
  padding: var(--sp-3) var(--sp-5);
  background-color: var(--sapin);
  color: var(--texte-1-sombre);
  font-size: var(--fs-legende);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transform: translateY(-200%);
  transition: transform var(--dur) var(--sortie);
}

.lienEvitement:focus {
  transform: translateY(0);
}

/* ---------------------------------------------------------------------------
   LES APPARITIONS AU DÉFILEMENT

   Un bloc entre par le bas — trente pixels — en même temps qu'il apparaît, une
   seule fois, quand son haut atteint le bas de l'écran. Rien ne rejoue au
   retour : une animation qu'on remarque deux fois est une animation ratée.

   Le mouvement est volontairement très long et très mou (voir le commentaire
   des réglages dans `tokens.css`). C'est ce qui sépare une page qui se pose
   d'une page qui s'affiche.

   Sans JavaScript, `data-js` n'est jamais posé et tout s'affiche normalement.
   --------------------------------------------------------------------------- */
[data-js] [data-reveal] {
  opacity: 0;
  transform: translateY(var(--montee-apparition));
}

[data-js] [data-reveal][data-vu] {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--dur-apparition) var(--sortie-expo),
    transform var(--dur-apparition) var(--sortie-expo);
  /* Le retard commun laisse le temps à l'œil d'arriver sur le bloc ; le retard
     particulier, posé au cas par cas, échelonne les séries. */
  transition-delay: calc(var(--retard-apparition) + var(--reveal-delai, 0s));
}

/* ---------------------------------------------------------------------------
   MOUVEMENT RÉDUIT

   Quand le système le demande, il ne reste que les changements de couleur.
   Aucun déplacement, aucun fondu d'entrée.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    transition-property:
      opacity, color, background-color, border-color, box-shadow, text-decoration-color,
      text-decoration-thickness !important;
    transition-duration: 0.12s !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }

  html {
    scroll-behavior: auto;
  }

  [data-js] [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}
