/* ==========================================================================
   TAYEBOOKS — Carte livre et rangées (v2)
   Une rangée se balaie d'un regard : couvertures à plat, 20px d'écart,
   le prix en gras. Pas de survol qui déplace quoi que ce soit.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Rangée défilable horizontalement — le motif de base du catalogue.

   UNE seule définition pour toutes les rangées du site : accueil, produits
   associés, ventes additionnelles. Elles étaient décrites en double, ici et
   dans product.css, et elles ont divergé — c'est ainsi que les produits
   associés ont fini par ne plus ressembler au reste du site.

   Le plancher de 9.5rem est ce qui rend le débordement possible : avec
   `minmax(0, 1fr)`, quinze livres se comprimaient à 90px chacun et la rangée
   ne débordait jamais, donc ne défilait jamais.
   -------------------------------------------------------------------------- */
.tb-strip,
.related.products ul.products,
.upsells.products ul.products {
  display: grid;

  /*
     `grid-template-columns: none` est INDISPENSABLE ici.

     Les rangées de produits associés sont aussi des `ul.products`, donc la
     règle générique ci-dessous leur imposait cinq colonnes explicites. Une
     grille qui a des colonnes explicites ignore `grid-auto-columns` : sur
     bureau, quatre livres s'étalaient dans cinq colonnes de 262px — des
     couvertures de 154px flottant au milieu du vide ; sous 620px, la règle
     mobile donnait DEUX colonnes explicites et deux implicites, et les deux
     premières cartes étaient écrasées à 4px de large, une lettre par ligne.
     Le défaut ne venait ni du JavaScript ni des couvertures, mais de cette
     collision de règles. §104
  */
  grid-template-columns: none;
  grid-auto-flow: column;

  /*
     Plancher : une couverture reste lisible (152px).
     Plafond : une tuile ne s'étire jamais au-delà de 176px, sinon une rangée
     de quatre livres occuperait toute la largeur avec des couvertures
     perdues au milieu de leur case.
  */
  grid-auto-columns: minmax(9.5rem, 11rem);

  gap: var(--grid-gap);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  padding-block-end: var(--space-1);
}

/*
   Grille classique — boutique, catégories, produits associés, ventes
   additionnelles, shortcode [products].

   `ul.products` est le conteneur que WooCommerce produit PARTOUT où il
   affiche une liste de produits. La règle vit donc ici, dans la feuille des
   cartes, et non dans celle de la boutique : `shop.css` n'est pas chargée sur
   une fiche produit, et les « Produits similaires » retombaient alors en
   liste à puces pleine largeur. Défaut relevé en recette.
*/
.tb-grid,
ul.products {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--space-7) var(--grid-gap);
  list-style: none;
  margin: 0;
  padding: 0;
}

ul.products::before,
ul.products::after { content: none; }

ul.products > li { margin: 0; min-inline-size: 0; }

.tb-card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
  scroll-snap-align: start;
}

.tb-card__cover { position: relative; }

.tb-card__fmt {
  margin-block-start: var(--space-2);
  font-size: var(--fs-meta);
  color: var(--color-text-soft);
}

.tb-card__title {
  margin-block-start: 2px;
  font-size: var(--fs-title);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
}

.tb-card__title a {
  color: var(--color-link);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tb-card:hover .tb-card__title a { text-decoration: underline; }

.tb-card__author {
  margin-block-start: 2px;
  font-size: var(--fs-meta);
  color: var(--color-text-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tb-card__price { margin-block-start: var(--space-2); }

.tb-card__stock {
  margin-block-start: var(--space-1);
  font-size: var(--fs-meta);
  color: var(--color-deal);
}

/* Lien étiré : toute la carte est cliquable, sans imbriquer d'interactifs. */
.tb-card__link::after { content: ""; position: absolute; inset: 0; z-index: 1; }

.tb-card.outofstock .tb-cover img { opacity: 0.5; }

@media (max-width: 1100px) { .tb-grid, ul.products { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

@media (max-width: 860px) {
  .tb-grid,
  ul.products { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  :root { --cover-height: 12rem; }
}

@media (max-width: 620px) {
  .tb-grid,
  ul.products { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6) var(--space-4); }
  /* La rangée devient défilable au doigt : ~2,5 couvertures visibles. */
  .tb-strip,
  .related.products ul.products,
  .upsells.products ul.products { grid-auto-columns: minmax(8rem, 40%); }
  :root { --cover-height: 10.625rem; }
}


/* ==========================================================================
   Flèches de défilement des rangées
   --------------------------------------------------------------------------
   Injectées par assets/js/rows.js, uniquement sur les appareils à pointeur
   fin et uniquement si la rangée déborde vraiment.
   ========================================================================== */

.tb-strip-wrap { position: relative; }

/* La barre de défilement native n'a plus lieu d'être quand on donne des
   flèches : elle doublerait le contrôle et mangerait 12px sous la rangée. */
/*
   Pas de `scroll-behavior: smooth` ici : le défilement continu écrit
   `scrollLeft` à chaque image, et le lissage natif du navigateur
   ré-animerait chacune de ces écritures — la rangée avancerait par à-coups.
   Le saut au clavier demande son propre lissage, image par image (rows.js).
*/
/*
   Et pas d'accrochage non plus. `scroll-snap-type: x proximity` sert au
   doigt : on lance la rangée, elle se repose sur une couverture. Combiné au
   défilement continu, il l'annulait purement et simplement — chaque image
   avançait de cinq pixels, l'accrochage ramenait aussitôt la rangée sur la
   couverture la plus proche, et la rangée restait immobile. Cause réelle
   d'un « rien ne bouge » qui n'avait rien à voir avec le JavaScript. §104

   L'accrochage reste actif partout ailleurs : ces règles ne s'appliquent
   qu'aux rangées équipées de flèches, donc aux pointeurs fins.
*/
.tb-strip-wrap > .tb-strip,
.tb-strip-wrap > ul.products {
  scrollbar-width: none;
  scroll-snap-type: none;
}

.tb-strip-wrap > .tb-strip::-webkit-scrollbar,
.tb-strip-wrap > ul.products::-webkit-scrollbar { display: none; }

.tb-strip__nav {
  position: absolute;
  inset-block-start: calc(var(--cover-height) / 2);
  transform: translateY(-50%);

  /*
     Au-dessus du lien étiré de la carte (`.tb-card__link::after`, z-index 1).
     À égalité, c'est l'ordre du document qui tranchait, et la couverture
     recouvrait la flèche par endroits : le clic partait sur le livre.
  */
  z-index: var(--z-sticky);

  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 36px;
  block-size: 36px;

  border: 1px solid var(--color-border);
  border-radius: 50%;
  background-color: var(--color-background);
  color: var(--color-text);
  box-shadow: var(--shadow-md);
  cursor: pointer;

  /*
     Révélées au survol de la rangée : au repos, rien ne recouvre une
     couverture.

     Elles restent RÉCEPTIVES au pointeur même invisibles. Les couper avec
     `pointer-events: none` paraissait plus propre, mais rendait le survol
     inopérant : un bouton hors du flux d'événements ne reçoit pas
     `pointerenter`, donc le défilement continu ne démarrait jamais — il
     fallait bouger la souris une seconde fois, après que le survol de la
     rangée ait rétabli les événements. Ce n'est pas gênant : le pointeur ne
     peut atteindre le bouton qu'en survolant la rangée, donc au moment où
     il l'atteint, la flèche est déjà visible.
  */
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease);
}

.tb-strip-wrap:hover .tb-strip__nav,
.tb-strip__nav:hover,
.tb-strip__nav:focus-visible {
  opacity: 1;
}

.tb-strip__nav:hover { background-color: var(--color-surface); }

/*
   Zone de survol.

   Le disque ne fait que 36px : viser 36px pour maintenir un défilement
   serait un exercice d'adresse. Cette zone invisible porte le survol sur
   toute la hauteur de la couverture et déborde un peu en largeur, si bien
   qu'« approcher du bord » suffit. Elle s'efface avec la flèche en bout de
   course (`.is-hidden` coupe les événements de pointeur).
*/
.tb-strip__nav::before {
  content: "";
  position: absolute;
  inset-block: calc(var(--cover-height) / -2 + 18px);
  inset-inline: -8px;
}

/*
   Masquée en bout de course : une flèche qui ne mène nulle part ment.
   `visibility: hidden` et non `opacity: 0` seule — sinon le bouton resterait
   dans l'ordre de tabulation, et le clavier s'arrêterait sur un contrôle
   invisible et sans effet. §53
*/
.tb-strip__nav.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.tb-strip__nav--prev {
  inset-inline-start: -6px;
  transform: translateY(-50%) scaleX(-1);
}

.tb-strip__nav--next { inset-inline-end: -6px; }

/* En écriture arabe, le chevron pointe dans l'autre sens. */
:dir(rtl) .tb-strip__nav--prev { transform: translateY(-50%); }
:dir(rtl) .tb-strip__nav--next { transform: translateY(-50%) scaleX(-1); }
