/* ==========================================================================
   Fiche PRODUIT — composants & organisation de la colonne droite (BAT V3).
   Complète catalog.css (qui gère déjà titre / prix / CTA / accordéon).
   Réutilise les variables de header.css : --shine-ink var(--shine-ink), --shine-race
   var(--shine-race), --shine-muted var(--shine-muted), --shine-line var(--shine-line),
   --shine-race-d var(--shine-race-d). Polices : charte Shine (BricolageGrotesque 600 pour les h*, Anek pour le texte,
   Saira 600 pour les prix) — déclarées dans custom.css.
   Tout est scopé à #product — aucun impact hors fiche produit.
   ========================================================================== */


/* ==========================================================================
   Rapatrié de header.css le 18/08/2026 — un composant, un fichier.
   ⚠ Placé en TÊTE de fichier : shine-product.css étant chargé APRÈS header.css,
   l'ordre relatif des déclarations est conservé et la cascade ne bouge pas.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Déclinaisons en PILULES (BAT V3) — surcharge product-variants.tpl, appliquée
   PARTOUT : fiche produit FO, quickview, et retour AJAX de changement de
   déclinaison (classes globales, pas de préfixe .shine-header/.shine-qv).
   -------------------------------------------------------------------------- */
.shine-variant {
  padding: 0;
  margin: 0 0 16px;
  border: 0;
}

.shine-variant__legend {
  display: block;
  margin-bottom: 9px;
  font-size: 11px;
  font-weight: 700;
  color: var(--shine-muted, var(--shine-muted));
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* Pleine largeur, toutes les pilules de MÊME taille (02/09/2026).
   Une grille et non un flex : `1fr` par colonne donne des largeurs strictement
   égales, alors qu'un flex les dimensionne sur leur contenu — « 5L » aurait fait
   la moitié de « 450mL + Pulvérisateur ».
   `auto-fit` + `minmax` gère le nombre de colonnes tout seul : autant que la
   largeur en autorise à 120 px minimum, puis retour à la ligne. Pas de point de
   rupture à maintenir, et jamais de pilule écrasée. */
/* UNE seule ligne, toujours, et un défilement quand la place manque (02/09/2026).
   `grid-auto-flow: column` empêche tout retour à la ligne, et `grid-auto-columns`
   donne à chaque pilule la MÊME largeur : `1fr` quand tout tient, le minimum de
   110 px sinon — c'est ce minimum qui crée le débordement, donc le défilement.
   Un flex n'aurait pas suffi : il dimensionne sur le contenu, et « 5 L » aurait
   fait la moitié de « 450 mL + Pulvérisateur ». */
.shine-variant__pills {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(110px, 1fr);
  gap: 9px;
  overflow-x: auto;
  padding-bottom: 2px;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}

.shine-variant__pills::-webkit-scrollbar {
  display: none;
}

.shine-variant__pills > * {
  scroll-snap-align: start;
}

/* input radio masqué mais focusable au clavier */
.shine-variant__pill-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.shine-variant__pill {
  display: flex;
  /* la grille impose la largeur : la pilule ne se dimensionne plus elle-même */
  align-items: center;
  justify-content: center;
  min-width: 0;
  padding: 13px 14px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--shine-dark);
  text-align: center;
  cursor: pointer;
  /* Fond BLANC PUR, comme la page : la pilule au repos ne se détache que par son
     filet, ce qui laisse toute la force visuelle à celle qui est sélectionnée. */
  background: #fff;
  border: 1.5px solid var(--shine-line, var(--shine-line));
  border-radius: 11px;
  transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.shine-variant__pill:hover {
  border-color: var(--shine-dark);
}

/* Sélection : aplat noir, texte blanc. Le liseré épais de l'ancienne version
   datait des vignettes — des dessins au trait noir qui disparaissaient sur fond
   noir. Sans vignette, plus rien n'empêche le remplissage plein, qui se repère
   d'un coup d'œil au lieu de se chercher. */
.shine-variant__pill-input:checked + .shine-variant__pill {
  color: var(--shine-white);
  background: var(--shine-dark);
  border-color: var(--shine-dark);
}

.shine-variant__pill-input:focus-visible + .shine-variant__pill {
  outline: 2px solid var(--shine-race, var(--shine-race));
  outline-offset: 2px;
}

/* --- groupes en LISTE DÉROULANTE (03/09/2026) ----------------------------
   Pour les groupes dont les libellés sont longs — « Nettoyant Jantes HARD +
   Accessoires » — les pilules découpaient la colonne en pavés de texte. Une
   ligne unique, refermée sur la valeur choisie, se lit d'un coup.
   Le `<select>` reste NATIF : `appearance: none` ne retire que la décoration,
   pas le comportement. */
.shine-variant__select {
  position: relative;
  display: block;
}

.shine-variant__select-input {
  width: 100%;
  padding: 14px 44px 14px 16px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--shine-ink);
  background: #fff;
  border: 1.5px solid var(--shine-line);
  border-radius: 11px;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  /* Un libellé trop long est coupé proprement plutôt que de pousser le chevron
     hors du cadre. Le nom entier reste disponible dans la liste ouverte. */
  text-overflow: ellipsis;
  transition: border-color 0.15s ease;
}

.shine-variant__select-input:hover {
  border-color: var(--shine-dark);
}

.shine-variant__select-input:focus-visible {
  outline: 2px solid var(--shine-race);
  outline-offset: 2px;
  border-color: var(--shine-dark);
}

/* Le chevron est décoratif et ne doit jamais intercepter le clic : sans
   `pointer-events: none`, cliquer dessus n'ouvrirait pas la liste. */
.shine-variant__select-chevron {
  position: absolute;
  top: 50%;
  right: 15px;
  transform: translateY(-50%);
  color: var(--shine-ink);
  pointer-events: none;
}

/* ==========================================================================
   Section rapatriée de catalog.css le 18/08/2026

   La fiche produit était décrite dans DEUX feuilles : catalog.css en posait
   l'ossature (colonnes, galerie, titre, prix, onglets) pendant que ce fichier
   en peaufinait les composants. Deux endroits pour un même écran, c'est ainsi
   qu'un `border-radius: 18px` a pu ne rien peindre pendant des semaines.

   ⚠ Ordre PRÉSERVÉ : ces règles arrivent en fin de fichier, donc toujours après
   celles qui les précédaient dans l'ancien catalog.css (chargé avant celui-ci).
   Les styles calculés sont identiques — vérifiés élément par élément.
   ========================================================================== */

/* la description longue peut être répétée en bas ; on ne l'affiche en clair
   que dans l'en-tête (le bloc SEO de bas de page garde son propre style) */

/* ----- Toolbar (compteur + tri) ----- */
#products .products__header,
#products #js-product-list-top {
  max-width: 1280px;
  padding-inline: 20px;
  margin-inline: auto;
}

#products .products__count,
#products .total-products p {
  font-size: 13px;
  color: var(--shine-muted, var(--shine-muted));
}

#products .products__sort-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--shine-muted, var(--shine-muted));
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

#products .products__sort-dropdown-button {
  font-family: "Anek", system-ui, sans-serif;
  font-size: 13px;
  font-weight: 400;
  color: var(--shine-ink, var(--shine-ink));
  background: var(--shine-white);
  border: 1.5px solid var(--shine-line, var(--shine-line));
  border-radius: 10px;
}

#products .products__sort-dropdown-button:hover {
  border-color: var(--shine-ink, var(--shine-ink));
}

#products .page-item.active .page-link {
  color: var(--shine-white);
  background: var(--shine-ink, var(--shine-ink));
  border-color: var(--shine-ink, var(--shine-ink));
}

#products .page-link:hover {
  border-color: var(--shine-ink, var(--shine-ink));
}

/* ==========================================================================
   Fiche PRODUIT (BAT V3) — page rendue par le THÈME (product.tpl, l'éditeur CE
   produit ayant été désactivé). Colonnes .product__left (galerie) /
   .product__right (buybox). Scopé body#product. Réutilise variables/polices/
   pilules de l'accueil (déclinaisons = .shine-variant__pill déjà stylées).
   ========================================================================== */

/* conteneur : un peu d'air entre galerie et buybox (BAT gap ~56px) */
#product .product__container {
  padding-top: 8px;
}

/* ⚠ ces deux règles sont bornées au desktop : sur mobile les colonnes sont
   empilées et le padding latéral creuserait un décalage. */
@media (min-width: 992px) {
  #product .product__left { padding-right: 28px; }
  #product .product__right { padding-left: 28px; }
}

/* fil d'ariane */
#product .breadcrumb {
  padding: 16px 0 6px;
  margin: 0;
  background: none;
}

#product .breadcrumb-item,
#product .breadcrumb-link {
  font-size: 12px;
  font-weight: 600;
  color: var(--shine-muted, var(--shine-muted));
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* Doublon plus spécifique de la règle de custom.css : c'est CELLE-CI qui gagnait
   sur la fiche produit, corriger l'autre seule n'aurait rien changé ici. */
#product .breadcrumb-link:hover { color: var(--shine-dark); }
#product .breadcrumb-item:last-child { color: var(--shine-ink, var(--shine-ink)); }

/* Cadre de galerie et miniatures : voir shine-product.css. Ces règles étaient
   DOUBLÉES ici (18 px) et là-bas (16 px) — c'est la seconde qui gagnait, donc le
   18 px n'a jamais rien peint. Un composant, un fichier (18/08/2026). */

#product .product__thumbnail.selected,
#product .product__thumbnail--active,
#product .product__thumbnails .active {
  outline: 2px solid var(--shine-race, var(--shine-race));
  outline-offset: 1px;
}

/* Titre produit → Anek 600 (13/08/2026). ⚠ Anek n'est chargée qu'en 300, 400 et 600 :
   demander 700 ferait fabriquer une fausse graisse par le navigateur. */
#product .product__name {
  font-family: "Anek", system-ui, sans-serif;
  font-size: clamp(30px, 4.5vw, 48px);
  font-weight: 600;
  line-height: 0.95;
  color: var(--shine-ink, var(--shine-ink));
  text-transform: uppercase;
}

/* Prix courant → Saira 600. ⚠ ESSAI #D6FF32 (13/08/2026) : la couleur de marque
   servait ici de couleur de TEXTE sur fond blanc ; en vert clair elle tombe à 1,15:1,
   soit illisible. Prix passé à l'encre. À reprendre si le rouge revient. */
#product .product__price,
#product .current-price,
#product .product__prices .price {
  font-family: "Saira", system-ui, sans-serif;
  font-size: 36px;
  font-weight: 600;
  line-height: 1;
  color: var(--shine-ink);
}

#product .regular-price,
#product .product__regular-price {
  font-size: 15px;
  color: var(--shine-muted, var(--shine-muted));
  text-decoration: line-through;
}

#product .product__discount--amount,
#product .product__discount-percentage,
#product .discount {
  padding: 4px 8px;
  font-size: 11px;
  font-weight: 800;
  color: var(--shine-dark);
  background: var(--shine-race, var(--shine-race));
  border-radius: 6px;
}

/* CTA ajouter au panier → pleine largeur. Les couleurs (rouge, survol noir) et le
   reflet viennent des variables --bs-btn-* de shine-buttons.css : ne rien mettre en
   dur ici, sinon le survol ne changerait plus de couleur. */
#product .product__add-to-cart-button.btn-primary {
  width: 100%;
  min-height: 54px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-radius: 12px;
}

/* stepper quantité — radius cohérent */
#product .quantity-button__group,
#product .product-quantity .input-group {
  overflow: hidden;
  border-radius: 12px;
}

/* onglets / accordéon description-caractéristiques → Anek 600 */
#product .accordion-button,
#product .tab-title,
#product .product-tab__title {
  font-family: "Anek", system-ui, sans-serif;
  font-weight: 600;
  font-size: 18px;
  text-transform: uppercase;
}

#product .accordion-button:not(.collapsed) {
  color: var(--shine-ink, var(--shine-ink));
  background: none;
  box-shadow: none;
}

/* réassurance (blockreassurance ou icon-boxes) — titres Anek 600 */
#product .blockreassurance__title,
#product .cyliumee-icob__title {
  font-family: "Anek", system-ui, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
}

/* ----- 3. Description courte (gris var(--shine-muted)) ----- */
#product .shine-short-desc,
#product .product__description-short {
  margin: 10px 0 6px;
}

/* ----- 2. Avis / notes sous le titre ----- */
#product .shine-product-reviews {
  margin: 6px 0 4px;
}

#product .shine-product-reviews:empty {
  display: none;
}

#product .shine-product-reviews .grade-stars {
  --star-color: var(--shine-star);
}

/* ==========================================================================
   4. BULLET POINTS — vraie liste à puces, cochée en rouge

   ⚠ Le champ « bullet-points » est passé du texte libre au type LISTE de
   cyliumproductfields (13/08/2026) : le module rend maintenant lui-même son
   <ul class="cpf-list__items"><li class="cpf-list__item">. Le carrousel maison
   qui redécoupait le texte en pilules n'avait donc plus lieu d'être — il a été
   retiré ici ET dans shine-product.js. On style directement le balisage du
   module, ce qui vaut aussi pour tout autre champ liste posé sur la fiche.
   ========================================================================== */
#product .shine-bullets {
  margin: 16px 0 18px;
  /* pas de filets haut/bas : la liste respire seule, décalée des deux côtés */
  padding: 0 18px;
}

/* les enveloppes du widget ne doivent rien imposer */
#product .shine-bullets .cpf-widget,
#product .shine-bullets .cpf-field-value,
#product .shine-bullets .cpf-list {
  margin: 0;
  padding: 0;
}

/* UNE colonne à toutes les largeurs (demande du 02/09/2026). En deux colonnes,
   les puces se lisaient en Z et les libellés de longueur inégale laissaient des
   trous ; empilées, elles se parcourent d'un seul mouvement de l'œil. */
#product .shine-bullets .cpf-list__items {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  padding: 0;
  margin: 0;
  list-style: none;
}

#product .shine-bullets .cpf-list__item {
  display: flex;
  /* Point centré sur TOUTE la puce, y compris quand le libellé passe sur deux
     lignes (02/09/2026). `flex-start` le collait à la première ligne, ce qui le
     faisait paraître décalé vers le haut dès qu'il y avait un retour. */
  align-items: center;
  gap: 8px;
  font-weight: 400;
  line-height: 1.35;
  /* Encre de charte : le point héritant de `currentColor`, texte et puce sont
     forcément de la même couleur — impossible qu'ils divergent à la retouche. */
  color: var(--shine-dark);
}

/* Un POINT et non une coche (02/09/2026), de la couleur du texte : une coche
   grise se lisait comme un état — « fait », « validé » — alors qu'il s'agit
   simplement d'énumérer des qualités. Le point ne raconte rien, il sépare.
   ⚠ Le masque est explicitement remis à `none` : sans cela, la coche SVG posée
   plus haut resterait et découperait le point en forme de coche. */
#product .shine-bullets .cpf-list__item::before {
  content: "";
  flex: 0 0 auto;
  width: 5px;
  height: 5px;
  /* 🔴 Remis à 0 EXPLICITEMENT : `list.css` du module pose
     `.cpf-list--ul .cpf-list__item::before { margin-top: 0.45em }`, qui décalait
     le point vers le bas malgré le centrage. Supprimer notre déclaration ne
     suffisait pas — il n'y avait alors plus rien pour couvrir celle du module. */
  margin-top: 0;
  background: currentColor;
  border-radius: 50%;
  -webkit-mask: none;
  mask: none;
}

/* une puce qui porte déjà son icône garde l'icône, pas la coche */
#product .shine-bullets .cpf-list__item:has(.cpf-list__icon)::before {
  display: none;
}

/* ==========================================================================
   5. STOCK — indicateur avec puce animée (pulse vert = en stock)
   ========================================================================== */
#product .shine-stock {
  display: flex;
  flex-wrap: wrap;
  align-items: start;
  gap: 6px 10px;
  margin: 4px 0 16px;
  font-family: "Anek", system-ui, sans-serif;
  font-weight: 400;
}

#product .shine-stock__status {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 13.5px;
  font-weight: 700;
}

/* on remplace l'icône material par une puce animée */
#product .shine-stock .product__availability-icon {
  display: none;
}

#product .shine-stock__dot {
  position: relative;
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  background: var(--shine-stock);
  border-radius: 50%;
  box-shadow: 0 0 6px rgb(var(--shine-stock-rgb) / 0.9);
}

/* anneau pulsant (uniquement quand en stock) */
#product .shine-stock__status.text-success .shine-stock__dot::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(var(--shine-stock-rgb) / 0.55) 0%, transparent 70%);
  animation: shineStockGlow 1.5s ease-out infinite;
}

/* couleurs par état (success/warning/danger portés par le core) */
#product .shine-stock__status.text-success {
  color: var(--shine-stock-d);
}

#product .shine-stock__status.text-success .shine-stock__dot {
  background: var(--shine-stock);
  box-shadow: 0 0 6px rgb(var(--shine-stock-rgb) / 0.9);
}

#product .shine-stock__status.text-warning {
  color: var(--shine-warn-d);
}

#product .shine-stock__status.text-warning .shine-stock__dot {
  background: var(--shine-warn);
  box-shadow: 0 0 6px rgb(var(--shine-warn-rgb) / 0.85);
}

#product .shine-stock__status.text-danger {
  color: var(--shine-race-sale);
}

/* 🔴 La pastille était peinte en vert de marque (--shine-race) à côté d'un texte
   rouge : le seul signal visible annonçait donc l'inverse du message (03/09/2026).
   `currentColor` la cale sur la couleur du statut, quelle que soit celle qui gagne
   la cascade — aujourd'hui le rouge Bootstrap #ff4657, demain le rouge de charte
   si on décide de reprendre la main sur `.text-danger`. */
#product .shine-stock__status.text-danger .shine-stock__dot {
  background: currentColor;
  box-shadow: none;
  box-shadow: 0 0 6px color-mix(in srgb, currentColor 70%, transparent);
}

#product .shine-stock__messages small {
  font-weight: 500;
  color: var(--shine-muted, var(--shine-muted));
}

#product .shine-stock__delivery {
  font-size: 12.5px;
  color: var(--shine-muted, var(--shine-muted));
}

@keyframes shineStockGlow {
  0% {
    transform: scale(0.6);
    opacity: 0.9;
  }
  70% {
    transform: scale(1.8);
    opacity: 0;
  }
  100% {
    transform: scale(1.8);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  #product .shine-stock__status.text-success .shine-stock__dot::after {
    animation: none;
  }
}

/* ==========================================================================
   7. PRIX — courant (rouge) + barré + badge remise, alignés proprement
   ========================================================================== */
#product .shine-prices {
  margin: 4px 0 14px;
}

#product .shine-prices__main {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

#product .shine-prices__discount {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 4px;
}

/* le prix courant hérite déjà du Saira 600 rouge via catalog.css (.product__price) */
#product .shine-prices__regular {
  font-size: 15px;
  color: var(--shine-muted, var(--shine-muted));
  text-decoration: line-through;
}

/* Badge de remise : la valeur seule (« 20% », « 3,70 € »), jamais « Economisez X »
   — le libelle complet reste en data-discount-label + visually-hidden
   (voir product-prices.tpl ; equivalent CE dans custom.css). */
#product .shine-prices__badge {
  display: inline-block;
  padding: 4px 9px;
  font-size: 11px;
  font-weight: 800;
  color: var(--shine-dark);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  background: var(--shine-race, var(--shine-race));
  border-radius: 6px;
}

/* libellé TTC/HT sur la même ligne que le prix courant (mockup) */
#product .shine-prices__main .shine-prices__tax {
  align-self: baseline;
  font-size: 13px;
  font-weight: 500;
  color: var(--shine-muted, var(--shine-muted));
}

/* la ligne infos-taxe résiduelle ne prend plus de place si vide */
#product .product__tax-infos:empty {
  display: none;
}

/* ==========================================================================
   8. FIDÉLITÉ — bloc « diamants gagnés » (hook displayProductAdditionalInfo)
   ========================================================================== */
#product .shine-loyalty {
  margin: 12px 0 16px;
}

#product .shine-loyalty:empty {
  display: none;
}

/* ==========================================================================
   9. QUANTITÉ + AJOUTER — même ligne (stepper compact à côté du CTA rouge)
   ========================================================================== */
#product .shine-buy-row {
  display: flex;
  /* ⚠ Le parent pose `flex-wrap: wrap` sur .product-quantity : sans cette
     annulation, le CTA passe sous le stepper dès que la colonne est étroite. */
  flex-wrap: nowrap;
  gap: 10px;
  align-items: stretch;
  margin-top: 4px;
}

#product .shine-buy-row .shine-qty {
  flex: 0 0 auto;
  /* ⚠ Le parent impose une largeur au bloc quantité en petite colonne : le stepper
     s'étalait alors sur toute la ligne et le CTA était compressé à 0 px — bouton
     invisible mais toujours cliquable, le pire des cas. */
  width: auto;
}

#product .shine-buy-row .shine-add {
  flex: 1 1 auto;
  min-width: 0;
}

/* stepper : cadre fin arrondi, boutons compacts (look BAT)
   🔴 Le groupe porte AUSSI la classe Bootstrap `.input-group`, qui impose
   `width: 100%` et `flex-wrap: wrap`. Le pourcentage se résout contre un parent
   de taille indéfinie (`.shine-qty` en `flex: 0 0 auto`) : le navigateur tranchait
   « contenu » en colonne large et « 100 % » en colonne étroite — d'où un sélecteur
   de quantité qui s'étalait sur toute la ligne et écrasait le CTA à zéro.
   `width: auto` lève l'ambiguïté. */
#product .shine-qty .quantity-button__group {
  display: flex;
  flex-wrap: nowrap;
  width: auto;
  align-items: stretch;
  height: 100%;
  overflow: hidden;
  /* blanc PUR et non `--shine-white` (#f9f9f9) : le stepper est posé sur la colonne
     d'achat, où le gris cassé se voyait comme une tache (13/08/2026). */
  background: #fff;
  border: 1.5px solid var(--shine-line, var(--shine-line-strong));
  border-radius: 12px;
}

#product .shine-qty .quantity-button__group .btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  min-height: 100%;
  padding: 0;
  color: var(--shine-ink, var(--shine-ink));
  background: none;
  border: 0;
  border-radius: 0;
}

#product .shine-qty .quantity-button__group .btn:hover {
  /* Le texte est DÉJÀ au plus foncé : l'assombrir ne signalerait rien. Le vert
     passe donc au fond, où il porte la marque sans seuil à tenir, et le signe
     s'inverse en foncé sur vert (16,5:1). */
  color: var(--shine-dark);
  background: var(--shine-race);
}

#product .shine-qty .quantity-button__group .btn .material-icons {
  font-size: 18px;
}

#product .shine-qty .quantity-button__group .form-control {
  width: 44px;
  min-width: 44px;
  padding: 0 2px;
  font-weight: 700;
  font-size: 15px;
  text-align: center;
  color: var(--shine-ink, var(--shine-ink));
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

#product .shine-qty .quantity-button__group .form-control:focus {
  outline: none;
  box-shadow: none;
}

/* le CTA rouge occupe toute la largeur restante (largeur/min-height via catalog.css) */
#product .shine-buy-row .product__add-to-cart-button.btn-primary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 100%;
}


/* Sous 380 px, le stepper et le CTA restaient bien sur une ligne mais en
   `flex: 1 1 100%` : le sélecteur de quantité s'étirait sur toute la largeur,
   ce qui n'a aucun sens pour trois caractères. Le stepper garde donc sa largeur
   naturelle partout, le CTA prend le reste ; seul le pas des boutons se resserre. */
@media (max-width: 380px) {
  #product .shine-qty .quantity-button__group .btn {
    width: 36px;
  }
  #product .shine-qty .quantity-button__group .form-control {
    width: 36px;
    min-width: 36px;
  }
}

/* ==========================================================================
   Onglets fiche produit — Description / Utilisation / Caractéristiques / FAQ
   (nav horizontale CENTRÉE, libellés majuscules, onglet actif souligné)
   ========================================================================== */
#product .shine-tabs { margin: 40px 0 8px; }

/* Onglets CENTRÉS (19/08/2026), sur le modèle de martinecosmetics.com : la barre
   ne court plus sur toute la largeur, elle se dimensionne sur ses onglets et se
   centre. `width: fit-content` + marges auto : le filet gris s'arrête donc avec
   le dernier onglet au lieu de traverser l'écran, ce qui est justement ce qui
   fait lire le groupe comme un objet et non comme un bord de section. */
#product .shine-tabs__nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 44px;
  width: fit-content;
  max-width: 100%;
  margin: 0 auto 30px;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--shine-line, var(--shine-line));
}

#product .shine-tabs__item { margin: 0; }

#product .shine-tabs__link {
  appearance: none;
  background: none;
  border: 0;
  padding: 12px 4px;
  margin-bottom: -1px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: 17px;
  color: var(--shine-muted, var(--shine-muted));
  /* 3 px et non 2 : le trait de l'onglet actif doit se distinguer du filet de
     1 px qui court sous toute la barre, sinon les deux se confondent. */
  border-bottom: 3px solid transparent;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

#product .shine-tabs__link:hover { color: var(--shine-ink, var(--shine-ink)); }

#product .shine-tabs__link.active {
  color: var(--shine-ink, var(--shine-ink));
  border-bottom-color: var(--shine-dark, var(--shine-dark));
}

/* Tablette ET mobile : la barre défile horizontalement plutôt que de passer à la
   ligne — le groupe reste une ligne et le geste est celui qu'on attend d'une
   barre d'onglets tactile. Le seuil est le `lg` de Bootstrap : en dessous de
   992 px la colonne d'onglets partage la largeur avec rien d'autre, mais trois
   libellés en majuscules y débordent dès que l'un d'eux s'allonge.
   `width: auto` annule le `fit-content` du desktop, sinon la barre se réduit à
   la largeur visible et le défilement n'a rien à parcourir.
   `scroll-snap` cale chaque onglet sur le bord : pas d'onglet coupé en deux. */
@media (max-width: 991.98px) {
  #product .shine-tabs__nav {
    flex-wrap: nowrap;
    justify-content: flex-start;
    width: auto;
    gap: 0 22px;
    overflow-x: auto;
    /* 🔴 iOS : `overflow-x: auto` seul crée AUSSI un conteneur de défilement
       vertical. Le doigt attrape alors la barre et la promène de haut en bas
       (effet élastique WebKit) avant qu'elle ne revienne en place. Les trois
       lignes qui suivent ferment cette porte : plus d'axe vertical, le geste
       vertical est rendu à la page, et le rebond ne se propage pas.
       `-webkit-overflow-scrolling: touch` est retiré : inutile depuis iOS 13
       (l'inertie y est native) et c'est lui qui arme le rebond. */
    overflow-y: hidden;
    touch-action: pan-x;
    overscroll-behavior: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }

  #product .shine-tabs__nav::-webkit-scrollbar { display: none; }

  #product .shine-tabs__item { scroll-snap-align: start; }

  #product .shine-tabs__link {
    padding: 10px 2px;
    white-space: nowrap;
  }
}

/* Sur téléphone les libellés restent à la taille du desktop : la barre défilant,
   rien n'oblige à les rapetisser, et un onglet de 17 px se vise mieux au doigt. */
@media (max-width: 575px) {
  #product .shine-tabs__nav { gap: 0 20px; }
  #product .shine-tabs__link { font-size: 17px; }
}
#product .shine-tabs__content .cpf-widget { margin: 0; }

/* ==========================================================================
   SECOND PART — onglets PLEINE LARGEUR + réassurance fixe + tuto vidéo
   ========================================================================== */
#product .product__bottom { display: block; }
#product .product__bottom .shine-tabs { width: 100%; max-width: 100%; }

/* Listes rich-text visibles dans les onglets (UL>LI / OL>LI) */
#product .shine-tabs__content ul,
#product .shine-tabs__content .rich-text ul,
#product .shine-tabs__content .cpf-field-richtext ul { list-style: disc; padding-left: 1.35em; margin: 0 0 1em; }
#product .shine-tabs__content ol,
#product .shine-tabs__content .rich-text ol,
#product .shine-tabs__content .cpf-field-richtext ol { list-style: decimal; padding-left: 1.5em; margin: 0 0 1em; }
#product .shine-tabs__content li { margin: 0 0 0.45em; line-height: 1.6; }

/* ----- « Lire plus » repliable + animé (Description) ----- */
#product .shine-readmore__content {
  position: relative;
  overflow: hidden;
  transition: max-height 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* la hauteur repliée/dépliée est pilotée en JS (inline max-height) pour animer
   dans LES DEUX sens ; ici on ne gère que le fondu de l'état replié. */
#product .shine-readmore.is-collapsible:not(.is-open) .shine-readmore__content::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4.5em;
  background: linear-gradient(to bottom, rgb(var(--shine-paper-rgb) / 0), var(--shine-paper));
  pointer-events: none;
}
#product .shine-readmore__toggle {
  appearance: none; background: none; border: 0;
  margin-top: 10px; padding: 0; cursor: pointer;
  font-weight: 800; text-transform: uppercase; letter-spacing: 0.02em;
  font-size: 12px; color: var(--shine-ink, var(--shine-ink));
}
/* Même cas que les boutons de quantité : le libellé est déjà au plus foncé, le
   survol se marque par le soulignement plutôt que par une couleur invisible. */
#product .shine-readmore__toggle:hover { color: var(--shine-dark); text-decoration: underline; }
#product .shine-readmore__label-less { display: none; }
#product .shine-readmore.is-open .shine-readmore__label-more { display: none; }
#product .shine-readmore.is-open .shine-readmore__label-less { display: inline; }

/* ----- Caractéristiques (table fixe 8 lignes) ----- */
/* ==========================================================================
   Conseils d'utilisation — étapes numérotées (modèle du 18/08/2026)

   Le contenu vient du champ « utilisation » en texte riche : c'est donc une <ol>
   ordinaire qu'on habille, sans imposer de balisage au rédacteur. Les numéros sont
   fabriqués par un compteur CSS — la numérotation reste juste même si une étape est
   ajoutée ou retirée au back-office, et rien n'est écrit en dur.
   ========================================================================== */
#product #shine-tab-util .rich-text ol {
  counter-reset: shine-etape;
  padding: 0;
  margin: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

#product #shine-tab-util .rich-text ol > li {
  counter-increment: shine-etape;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: 16px;
  /* Texte centré sur la pastille, y compris quand il tient sur plusieurs lignes :
     `start` accrochait la première ligne en haut et laissait la pastille flotter. */
  align-items: center;
  line-height: 1.5;
  color: var(--shine-dark);
}

#product #shine-tab-util .rich-text ol > li::before {
  content: counter(shine-etape);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: var(--shine-dark);
  background: var(--shine-paper-2);
  border-radius: 50%;
}

/* Le dernier paragraphe hors liste (« À éviter : … ») reste une note discrète.
   ⚠ `:last-child` seulement : les blocs nommés ci-dessous ne doivent PAS y tomber,
   sinon le tableau de dilution hériterait d'un texte gris de note de bas de page. */
#product #shine-tab-util .rich-text > p:last-child {
  margin: 10px 0 0;
  line-height: 1.5;
  color: var(--shine-muted);
}

/* ==========================================================================
   Blocs prédéfinis des conseils d'utilisation

   Trois classes, à poser dans le champ « Conseils d'utilisation » du produit.
   Le rédacteur n'a que la classe à écrire : la mise en forme est ici, une fois
   pour toutes, et changera pour toutes les fiches d'un seul endroit.

     <div class="shine-conseils-dilution">  → un tableau de dosages
     <div class="shine-conseils-asavoir">   → l'encadré des mises en garde
     <div class="shine-conseils-nb">        → la note courte « N.B. »

   Chacun peut porter un <h3> : il est mis en forme sans que le rédacteur ait à
   s'en occuper, et il reste un vrai titre pour le plan du document.
   ========================================================================== */
#product #shine-tab-util .shine-conseils-asavoir,
#product #shine-tab-util .shine-conseils-nb {
  margin: 26px 0 0;
}

/* Le bloc dilution respire davantage que les deux autres : un tableau serré
   contre le texte qui le précède se lit comme la suite du paragraphe. */
#product #shine-tab-util .shine-conseils-dilution {
  margin: 32px 0 0;
}

#product #shine-tab-util .shine-conseils-dilution > h3,
#product #shine-tab-util .shine-conseils-asavoir > h3,
#product #shine-tab-util .shine-conseils-nb > h3 {
  margin: 0 0 12px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 17px;
  font-weight: 600;
  color: var(--shine-dark);
}

/* ---- Dilutions : un vrai tableau, pas une liste déguisée ----
   Deux colonnes, la valeur alignée à droite pour que les dosages se comparent
   d'un coup d'œil. Le <thead> est masqué visuellement mais conservé pour les
   lecteurs d'écran : « Méthode / Dilution » se devine à l'œil, pas à l'oreille. */
#product #shine-tab-util .shine-conseils-dilution table {
  /* Bridé à 500 px : au-delà, deux colonnes de dosages laissent un vide au milieu
     et l'œil perd le lien entre la méthode et sa valeur.
     Aligné à GAUCHE, sur le fer du texte qui le précède : centré, il flottait sans
     rapport avec les étapes numérotées juste au-dessus. */
  width: 100%;
  max-width: 500px;
  margin-inline: 0;
  border-collapse: collapse;
}

#product #shine-tab-util .shine-conseils-dilution th,
#product #shine-tab-util .shine-conseils-dilution td {
  /* Marge latérale franche : la valeur est alignée à droite, elle touchait le bord
     des 500 px et la ligne paraissait coupée. 14 px lui rendent une respiration
     comparable à celle du haut et du bas. */
  padding: 16px 14px;
  line-height: 1.4;
  text-align: left;
  /* `border: 0` AVANT le filet du bas : le thème parent pose un cadre complet
     sur les cellules de tableau (`border-right` compris), d'où un quadrillage
     vertical qui coupait le tableau en deux. Seule la ligne horizontale doit
     rester — elle sépare des lignes, pas des colonnes. */
  border: 0;
  border-bottom: 1px solid var(--shine-line);
}

#product #shine-tab-util .shine-conseils-dilution thead th {
  padding-bottom: 12px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* Gris foncé plutôt que --shine-muted : en capitales à 12 px, le gris moyen
     passait derrière les valeurs du tableau alors que l'en-tête doit se lire en
     premier. */
  color: var(--shine-dark-gray);
}

#product #shine-tab-util .shine-conseils-dilution td:last-child,
#product #shine-tab-util .shine-conseils-dilution th:last-child {
  text-align: right;
  font-weight: 600;
  white-space: nowrap;
}

#product #shine-tab-util .shine-conseils-dilution tbody tr:last-child td {
  border-bottom: 0;
}

/* ---- N.B. : l'encadré gris ----
   Fond gris très clair et non un cadre : l'encadré isole sans découper, et ne
   rivalise pas avec les pastilles numérotées juste au-dessus. */
#product #shine-tab-util .shine-conseils-nb {
  padding: 18px 20px;
  background: var(--shine-paper-2);
  border-radius: 12px;
}

/* ---- « À savoir » : une carte bordée ----
   Un encadré, mais pas le MÊME que le N.B. : sa pastille d'icône est grise, elle
   disparaîtrait dans un fond gris. D'où un cadre au trait sur fond de page.
     N.B.       → aplat gris, pas de titre, pas d'icône
     À savoir   → carte bordée, pastille lampe
     Dilutions  → NI cadre NI padding : le tableau porte déjà ses propres filets,
                  un cadre autour aurait fait deux traits pour une seule frontière.
*/
#product #shine-tab-util .shine-conseils-asavoir {
  padding: 22px 24px;
  /* Alerte LÉGÈRE : l'ambre de charte, très dilué. 6 % de fond et 30 % de trait
     suffisent à teinter le bloc sans le transformer en avertissement criard — ce
     sont des conseils d'usage, pas un danger. La couleur vient du jeton existant,
     aucune teinte nouvelle n'est introduite. */
  background: rgb(var(--shine-warn-rgb) / 0.06);
  border: 1px solid rgb(var(--shine-warn-rgb) / 0.3);
  border-radius: 12px;
}



/* Titres à pastille : l'icône est un MASQUE, pas une image colorée. La forme
   vient du SVG, la couleur de `currentColor` — une recoloration de charte n'a
   donc aucun fichier à redessiner. */
#product #shine-tab-util .shine-conseils-asavoir > h3,
#product #shine-tab-util .shine-conseils-dilution > h3 {
  display: flex;
  align-items: center;
  gap: 12px;
}

#product #shine-tab-util .shine-conseils-asavoir > h3::before,
#product #shine-tab-util .shine-conseils-dilution > h3::before {
  content: "";
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  background: var(--shine-paper-2);
  border-radius: 50%;
  /* la pastille porte le fond, le pseudo-élément interne porte l'icône :
     un seul élément suffit avec un dégradé de masque centré. */
  -webkit-mask: none;
  mask: none;
}

#product #shine-tab-util .shine-conseils-asavoir > h3::before {
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M9%2018h6M10%2021h4%22%2F%3E%3Cpath%20d%3D%22M12%203a6%206%200%200%200-3.6%2010.8c.5.4.8%201%20.9%201.6l.1.6h5.2l.1-.6c.1-.6.4-1.2.9-1.6A6%206%200%200%200%2012%203Z%22%2F%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 19px 19px;
}

#product #shine-tab-util .shine-conseils-dilution > h3::before {
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M12%203.5c3.2%203.6%205.5%206.5%205.5%209.3A5.5%205.5%200%200%201%2012%2018.5a5.5%205.5%200%200%201-5.5-5.7c0-2.8%202.3-5.7%205.5-9.3Z%22%2F%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 18px 18px;
}

/* ⚠ Posé APRÈS le bloc ci-dessus : celui-ci écrit `background` en RACCOURCI, qui
   réinitialise `background-color`. Une teinte déclarée plus haut y serait effacée
   sans la moindre erreur — c'est la mécanique des raccourcis, pas une histoire de
   spécificité.
   La pastille suit donc la teinte du bloc : grise sur fond ambré, elle ferait tache. */
#product #shine-tab-util .shine-conseils-asavoir > h3 {
  color: var(--shine-warn-d);
}

/* La pastille suit la teinte du bloc : grise sur fond ambré, elle ferait tache. */
#product #shine-tab-util .shine-conseils-asavoir > h3::before {
  background-color: rgb(var(--shine-warn-rgb) / 0.16);
}

#product #shine-tab-util .shine-conseils-asavoir p,
#product #shine-tab-util .shine-conseils-nb p {
  margin: 0 0 10px;
  line-height: 1.6;
  color: var(--shine-dark);
}

#product #shine-tab-util .shine-conseils-asavoir p:last-child,
#product #shine-tab-util .shine-conseils-nb p:last-child {
  margin-bottom: 0;
}

#product #shine-tab-util .shine-conseils-asavoir ul {
  margin: 0;
  padding-left: 1.2em;
}

#product #shine-tab-util .shine-conseils-asavoir li {
  margin: 0 0 6px;
  line-height: 1.5;
}

#product #shine-tab-util .shine-conseils-asavoir li:last-child {
  margin-bottom: 0;
}

@media (max-width: 575px) {
  #product #shine-tab-util .shine-conseils-nb,
  #product #shine-tab-util .shine-conseils-asavoir {
    padding: 16px 15px;
  }

  /* Deux colonnes de dosages sur un téléphone : la valeur passe sous le libellé
     plutôt que de le comprimer sur trois lignes. */
  /* ...ce qui rend l'en-tête à deux colonnes absurde : « MÉTHODE / DILUTION »
     surplombait un corps devenu monocolonne, la seconde colonne restant vide.
     On le retire de l'affichage tout en le laissant au flux d'accessibilité :
     empilée, la paire libellé/valeur se comprend seule à l'œil, mais un lecteur
     d'écran a toujours besoin des en-têtes pour annoncer les cellules. */
  #product #shine-tab-util .shine-conseils-dilution thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  #product #shine-tab-util .shine-conseils-dilution td {
    display: block;
    /* Aucun retrait horizontal ici : empilée, la cellule doit s'aligner sur le
       texte courant de l'onglet, pas former une colonne décalée. */
    padding: 8px 0;
    border-bottom: 0;
  }

  #product #shine-tab-util .shine-conseils-dilution td:first-child {
    padding-bottom: 0;
    color: var(--shine-muted);
  }

  #product #shine-tab-util .shine-conseils-dilution td:last-child {
    padding-top: 2px;
    text-align: left;
    border-bottom: 1px solid var(--shine-line);
    padding-bottom: 10px;
  }

  #product #shine-tab-util .shine-conseils-dilution tbody tr:last-child td:last-child {
    border-bottom: 0;
  }
}

/* ==========================================================================
   Caractéristiques — deux colonnes en bureau et tablette, une en mobile

   ⚠ Le balisage reste un <table> : c'est un tableau de données, et le lecteur
   d'écran doit continuer à annoncer « intitulé / valeur ». On ne change que la
   MISE EN PAGE, via `display: contents` sur le <tbody> pour que les <tr>
   deviennent les cellules d'une grille à deux colonnes.
   ========================================================================== */
#product .shine-carac {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 60px;
  width: 100%;
  max-width: none;
  border-collapse: collapse;
}

#product .shine-carac tbody {
  display: contents;
}

#product .shine-carac__row {
  display: grid;
  grid-template-columns: minmax(120px, 200px) minmax(0, 1fr);
  gap: 20px;
  align-items: baseline;
  padding: 13px 0;
}

@media (max-width: 767px) {
  #product .shine-carac {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }
}

#product .shine-carac-legacy { width: 100%; max-width: 660px; border-collapse: collapse; }
#product .shine-carac__row { border-bottom: 1px solid var(--shine-line, var(--shine-line)); }
/* Intitulés en gris et en casse normale (18/08/2026) : ce sont des étiquettes, pas
   des titres — les majuscules leur donnaient plus de poids qu'à leur propre valeur. */
#product .shine-carac__key {
  padding: 0; text-align: left; vertical-align: top;
  font-weight: 400; text-transform: none; letter-spacing: 0;
  color: var(--shine-muted);
}
#product .shine-carac__val { padding: 0; font-weight: 500; color: var(--shine-ink, var(--shine-ink)); }
#product .shine-carac__row.is-empty .shine-carac__val { color: var(--shine-muted, var(--shine-muted)); }
#product .shine-carac__dash { color: var(--shine-line, rgb(var(--shine-ink-rgb) / 0.3)); }

/* ----- FAQ : stylée + accordéon dans l'override du template module
   (themes/shine/modules/cyliumproductfields/views/templates/hook/widget_faq.tpl,
   scope .shine-faq-widget, autonome). Rien à styliser ici. ----- */

/* ----- Réassurance fixe (pleine largeur) ----- */
#product .shine-reassurance {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: 14px 36px; margin: 34px 0; padding: 22px 0;
  border-top: 1px solid var(--shine-line, var(--shine-line));
  border-bottom: 1px solid var(--shine-line, var(--shine-line));
}
#product .shine-reassurance__item {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 14px; font-weight: 600; color: var(--shine-ink, var(--shine-ink));
}
#product .shine-reassurance__icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  /* Les vignettes sont des SVG monochromes servis depuis img/cms : elles portent
     déjà l'encre de charte, rien à recolorer ici. */
}

/* ----- Tuto vidéo (carte sombre) ----- */
/* Volet « Tuto vidéo ». Le module sort un <iframe> dans un cadre portant
   `aspect-ratio: 16/9` en style en ligne : brider la LARGEUR suffit donc, la
   hauteur suit toute seule — rien à recalculer, et le cadrage reste juste quelle
   que soit la place disponible. Marges automatiques pour le centrage. */
#product .shine-tab-video .cpf-video-embed {
  max-width: 400px;
  margin-inline: auto;
}

/* ==========================================================================
   Galerie image — colonne STICKY (descend dans son container) + cadre mockup
   ========================================================================== */
@media (min-width: 992px) {
  #product .product__left {
    position: sticky;
    top: 96px;              /* juste sous le header sticky */
    align-self: flex-start; /* n'étire pas la colonne → sticky effectif */
  }
}

/* cadre image arrondi (mockup ~16px), miniatures propres */
/* Cadre de la galerie (rapatrié de catalog.css le 18/08/2026, où un 18 px
   concurrent ne servait à rien : cette feuille est chargée après). */
#product .product__images,
#product .product__carousel { border-radius: 16px; overflow: hidden; }
#product .product__thumbnails { margin-top: 12px; }
#product .product__thumbnails-list {
  display: flex; flex-wrap: wrap; gap: 10px; padding: 0; margin: 0; list-style: none;
}
#product .product__thumbnails .thumbnail,
#product .product__thumbnail { border-radius: 10px; overflow: hidden; }

/* ==========================================================================
   Galerie image (mockup) — flèches rondes, points, loupe DANS l'image,
   badge promo en haut à gauche ; PAS de miniatures
   ========================================================================== */
#product .shine-gallery { position: relative; }

/* badge promo + flags superposés en haut à gauche */
/* Pastilles côte à côte (13/08/2026), comme sur la grille : la colonne les empilait
   sur trois lignes et déséquilibrait le coin de l'image. `flex-wrap` garde le repli
   si un libellé long fait déborder. */
#product .shine-gallery .shine-flags,
#product .shine-gallery .product-flags {
  position: absolute; top: 14px; left: 14px; right: 14px; z-index: 4;
  display: flex; flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: 6px;
  margin: 0; padding: 0; list-style: none;
}
/* ⚠ AUCUNE couleur ici : les pastilles de la fiche produit sont les mêmes que celles
   de la grille, et un seul fichier les colore — shine-miniature.css (`.shine-flag`
   et ses variantes). Les redéclarer ici, comme c'était le cas jusqu'au 13/08/2026,
   les faisait diverger silencieusement à chaque évolution de charte : « Exclu Web »
   en blanc sur noir d'un côté, noir sur vert de l'autre, et aucune règle pour
   « Pack ». On ne garde donc que la GÉOMÉTRIE, propre au bandeau de la galerie. */
#product .shine-gallery .shine-flag {
  display: inline-block; padding: 6px 12px; border-radius: 8px;
  font-size: 12px; font-weight: 800; line-height: 1.1; text-transform: uppercase; letter-spacing: 0.02em;
}

/* flèches dans des ronds blancs, centrées, superposées sur l'image */
#product .shine-gallery .shine-gallery__arrow {
  top: 50%; bottom: auto; transform: translateY(-50%);
  width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgb(var(--shine-white-rgb) / 0.9); opacity: 1;
  box-shadow: 0 2px 10px rgb(var(--shine-black-rgb) / 0.12); z-index: 4;
}
#product .shine-gallery .shine-gallery__arrow:hover { background: var(--shine-white); }
#product .shine-gallery .shine-gallery__arrow.carousel-control-prev { left: 14px; }
#product .shine-gallery .shine-gallery__arrow.carousel-control-next { right: 14px; }
#product .shine-gallery .shine-gallery__arrow .material-icons { color: var(--shine-ink); font-size: 24px; }

/* points de navigation en bas (actif = pilule blanche) */
#product .shine-gallery .shine-gallery__dots { bottom: 14px; margin: 0; gap: 6px; z-index: 4; }
#product .shine-gallery .shine-gallery__dots [data-bs-slide-to] {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgb(var(--shine-white-rgb) / 0.6); border: 0; opacity: 1;
  box-shadow: 0 1px 3px rgb(var(--shine-black-rgb) / 0.25);
  transition: width 0.2s ease, background 0.2s ease;
}
#product .shine-gallery .shine-gallery__dots [data-bs-slide-to].active {
  width: 22px; border-radius: 5px; background: var(--shine-white);
}

/* loupe DANS l'image, en bas à droite */
#product .shine-gallery .shine-gallery__zoom {
  position: absolute; right: 14px; bottom: 14px; z-index: 4;
  width: 40px; height: 40px; border-radius: 50%; border: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgb(var(--shine-white-rgb) / 0.9); box-shadow: 0 2px 10px rgb(var(--shine-black-rgb) / 0.12);
}
#product .shine-gallery .shine-gallery__zoom:hover { background: var(--shine-white); }
#product .shine-gallery .shine-gallery__zoom .material-icons { color: var(--shine-ink); font-size: 20px; }

/* pas de miniatures des autres images */
#product .product__thumbnails { display: none; }

/* ---------------------------------------------------------------------------
   FAQ produit (cyliumproductfields) — accordéon natif <details>/<summary>.
   Ces règles étaient dans un <style> inline du template, avec les couleurs en dur
   (#0b0b0c, #6e6e76, #e10600, rgba(11,11,12,.12)) ; elles utilisent désormais la
   palette et sont mises en cache comme le reste du CSS.
   --------------------------------------------------------------------------- */

.shine-faq-widget {
  border-top: 1px solid var(--shine-line);
}

.shine-faq-widget .shine-faq__item {
  border-bottom: 1px solid var(--shine-line);
}

.shine-faq-widget .shine-faq__q {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
  padding: 20px 2px;
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--shine-ink);
  list-style: none;
  cursor: pointer;
  outline: none;
}

.shine-faq-widget .shine-faq__q::-webkit-details-marker {
  display: none;
}

.shine-faq-widget .shine-faq__q::marker {
  content: "";
}

.shine-faq-widget .shine-faq__q h3 {
  margin: 0;
  font: inherit;
}

.shine-faq-widget .shine-faq__q::after {
  flex: 0 0 auto;
  width: 1em;
  font-size: 24px;
  font-weight: 400;
  line-height: 1;
  color: var(--shine-muted);
  text-align: center;
  content: "+";
}

/* Le signe passe de « + » à « − » à l'ouverture ; la COULEUR ne change pas
   (02/09/2026). Le vert de marque sur ce seul caractère faisait un point de
   couleur isolé dans une liste par ailleurs entièrement noire — l'état ouvert se
   lit déjà au signe et au panneau déplié. */
.shine-faq-widget details[open] > .shine-faq__q::after {
  content: "\2212";
}

.shine-faq-widget .shine-faq__a {
  padding: 0 2px 22px;
  color: var(--shine-muted);
}

.shine-faq-widget details[open] > .shine-faq__a {
  animation: shineFaqIn 0.28s ease;
}

.shine-faq-widget .shine-faq__a > div > *:first-child {
  margin-top: 0;
}

.shine-faq-widget .shine-faq__a ul {
  padding-left: 1.3em;
  margin: 0 0 0.8em;
  list-style: disc;
}

.shine-faq-widget .shine-faq__a ol {
  padding-left: 1.4em;
  margin: 0 0 0.8em;
  list-style: decimal;
}

@keyframes shineFaqIn {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .shine-faq-widget details[open] > .shine-faq__a {
    animation: none;
  }
}

/* ==========================================================================
   FAQ — section propre sous les onglets (07/08/2026)
   Elle était le quatrième onglet ; une question fréquente n'a d'intérêt que si on la
   voit sans avoir à la chercher.
   ========================================================================== */

.shine-faq-section {
  padding: clamp(32px, 4vw, 56px) 0 0;
}

/* ==========================================================================
   Réassurance en slider, sous le bloc fidélité (07/08/2026)
   La colonne d'achat est trop étroite pour quatre arguments de front. Le défilement
   est fait en CSS (scroll-snap) : tactile, utilisable au clavier, et affiché même si
   le JavaScript ne se charge pas — ce qu'un carrousel scripté ne garantit pas.
   ========================================================================== */

#product .shine-reassurance--slider {
  display: flex;
  /* ⚠ La règle de base pose `flex-wrap: wrap` : sans cette annulation, les pastilles
     passaient À LA LIGNE au lieu de défiler, et le bloc n'avait rien d'un slider.
     `justify-content` est remis à `flex-start` pour la même raison — centré, un contenu
     qui déborde se coupe des DEUX côtés. */
  flex-wrap: nowrap;
  justify-content: flex-start;
  gap: 30px;
  margin-top: 14px;
  /* ⚠ La règle de base pose `padding: 22px 0` ; on la redéclare ENTIÈREMENT,
     un simple `padding-bottom` laissait 22 px en haut pour 6 px en bas. */
  padding: 14px 0;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* la main saisissante n'est posée que si ça défile vraiment (JS) */
  cursor: default;
}

/* ⚠ Défilement automatique et scroll-snap ne peuvent pas cohabiter : le snap ramène
   la position sur une pastille à chaque image, et le mouvement se fige. Il est donc
   coupé dès que l'animation tourne — le calage n'a plus de sens sur un ruban continu. */
#product .shine-reassurance--slider.is-autoscroll {
  scroll-snap-type: none;
  scroll-behavior: auto;
  /* 🔴 iOS : avec `-webkit-overflow-scrolling: touch`, Safari confie le
     défilement à un fil séparé et IGNORE les écritures de `scrollLeft` faites
     image par image — le ruban restait donc immobile sur iPhone, sans erreur ni
     message. La cinétique n'a de toute façon aucun intérêt pendant une animation
     automatique : on la coupe le temps qu'elle tourne. */
  -webkit-overflow-scrolling: auto;
}

#product .shine-reassurance--slider::-webkit-scrollbar {
  display: none;
}

/* État posé par shine-product.js quand le contenu déborde : le bloc se saisit
   à la souris. `user-select: none` évite qu'un glissé sélectionne les libellés. */
#product .shine-reassurance--slider.is-draggable {
  cursor: grab;
  user-select: none;
}

#product .shine-reassurance--slider.is-dragging {
  cursor: grabbing;
  /* ⚠ Pendant le glissé, le scroll-snap doit céder : sinon chaque pixel de
     `scrollLeft` est ramené de force sur une pastille et le bloc tressaute. */
  scroll-snap-type: none;
  scroll-behavior: auto;
}

/* Arguments de réassurance : du texte et une icône, rien d'autre. Ni cadre, ni fond,
   ni arrondi (13/08/2026) — ces pastilles ressemblaient à des boutons cliquables. */
#product .shine-reassurance--slider .shine-reassurance__item {
  flex: 0 0 auto;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 0;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.2;
  color: var(--shine-ink);
  background: none;
  border: 0;
  border-radius: 0;
  white-space: nowrap;
}

#product .shine-reassurance--slider .material-icons {
  font-size: 18px;
  color: var(--shine-dark);
}

/* ==========================================================================
   Caractéristiques — Dangers / Conseils de prudence (phrases CLP)
   Rendues par le widget multiselect de cyliumproductfields : un <ul> dans la
   cellule. Ce sont des phrases entières, pas des valeurs courtes comme le pH :
   la puce disparaît quand il n'y en a qu'une, sinon une liste d'un seul élément
   ressemble à une coquille.
   ========================================================================== */
#product .shine-carac .cpf-widget {
  margin: 0;
}

#product .shine-carac .cpf-field-multiselect {
  margin: 0;
  padding: 0;
  list-style: none;
}

#product .shine-carac .cpf-field-multiselect > li {
  position: relative;
  padding-left: 14px;
}

#product .shine-carac .cpf-field-multiselect > li + li {
  margin-top: 4px;
}

#product .shine-carac .cpf-field-multiselect > li::before {
  position: absolute;
  left: 0;
  content: "·";
  color: var(--shine-muted);
}

#product .shine-carac .cpf-field-multiselect > li:only-child {
  padding-left: 0;
}

#product .shine-carac .cpf-field-multiselect > li:only-child::before {
  content: none;
}

/* Pictogrammes SGH — bande au-dessus des mentions de danger.
   Chaque pictogramme porte son nom : le losange seul ne dit rien à qui ne
   connaît pas la nomenclature, et l'attribut `title` ne se lit ni au toucher
   ni au clavier. */
#product .shine-ghs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin-bottom: 12px;
}

#product .shine-ghs__item {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

#product .shine-ghs__picto {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
}

#product .shine-ghs__label {
  font-family: "Anek", system-ui, sans-serif;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.25;
  color: var(--shine-dark-gray);
}

@media (max-width: 575px) {
  /* Les noms passent sous leur pictogramme : côte à côte, « Dangereux pour le
     milieu aquatique » à côté d'un losange de 44 px ne laisse plus rien au texte. */
  #product .shine-ghs {
    gap: 12px;
  }

  #product .shine-ghs__item {
    flex-direction: column;
    gap: 6px;
    max-width: 86px;
    text-align: center;
  }

  #product .shine-ghs__label {
    font-size: 11.5px;
  }
}

/* ==========================================================================
   Bloc social de la fiche produit (surcharge de ps_sharebuttons)
   Le widget ps_socialfollow apporte sa propre liste ; on ne règle ici que
   l'alignement avec le libellé et la couleur des icônes, qui arrivent en
   `currentColor`.
   ========================================================================== */
#product .shine-social {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
}

/* La classe réelle du widget est `ps-socialfollow__list` (tiret, pas tiret bas) :
   les deux variantes visées jusqu'ici ne mordaient sur rien et la liste restait
   en `display: block`, donc les icônes empilées (corrigé le 02/09/2026). */
#product .shine-social .ps-socialfollow__list {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

#product .shine-social .ps-socialfollow__item { margin: 0; }

#product .shine-social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--shine-dark);
  transition: color 0.15s ease;
}

#product .shine-social a:hover {
  color: var(--shine-race-sec);
}


/* Respiration sous les pilules de déclinaison : le prix venait se coller au
   dernier conditionnement. */
#product .product__variants.shine-variants {
  margin-block-end: 1rem;
}


/* ==========================================================================
   BLOCS DE PRODUITS EN ÉTAGÈRE  (02/09/2026)
   Sur-titre + titre, puis une étagère horizontale à flèches. Sert les quatre
   blocs : accessoires de la fiche, ps_categoryproducts, ps_crossselling,
   ps_viewedproduct. Volontairement SANS préfixe `#product` : ps_viewedproduct
   s'affiche aussi hors fiche produit.
   ========================================================================== */
.shine-pblock { margin: 56px 0 8px; }

.shine-pblock__head {
  margin: 0 0 26px;
  text-align: left;
}

.shine-pblock__head .shine-eyebrow { margin: 0 0 6px; }

.shine-pblock__head .section-title {
  margin: 0;
  text-transform: uppercase;
}

/* La piste et ses flèches. Les flèches sont posées SUR les bords de la piste
   plutôt qu'à côté : la piste garde ainsi toute la largeur de la colonne, et
   l'alignement des vignettes reste celui du reste de la page. */
.shine-carousel { position: relative; }

.shine-carousel__track { overflow: visible; }

/* `productlist.tpl` sort une grille ; on la remet à plat en étagère. */
.shine-carousel .products {
  display: flex;
  flex-wrap: nowrap;
  gap: 16px;
  margin: 0;
  padding: 4px 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
}

.shine-carousel .products::-webkit-scrollbar { display: none; }

/* Quatre vignettes visibles en desktop, la 5e amorcée pour signaler le défilement. */
.shine-carousel .products > * {
  flex: 0 0 calc((100% - 3 * 16px) / 4);
  max-width: calc((100% - 3 * 16px) / 4);
  scroll-snap-align: start;
}

.shine-carousel__arrow {
  position: absolute;
  top: 40%;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  color: var(--shine-dark);
  background: var(--shine-white);
  border: 1px solid var(--shine-border-neutral);
  border-radius: 50%;
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.10);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}

.shine-carousel__arrow:hover {
  color: var(--shine-white);
  background: var(--shine-dark);
  border-color: var(--shine-dark);
}

.shine-carousel__arrow[hidden] { display: none; }

.shine-carousel__arrow--prev { left: -20px; }
.shine-carousel__arrow--next { right: -20px; }

@media (max-width: 1199.98px) {
  .shine-carousel .products > * {
    flex-basis: calc((100% - 2 * 16px) / 3);
    max-width: calc((100% - 2 * 16px) / 3);
  }
  /* Sous 1200 px la marge autour de la colonne ne suffit plus à loger les
     flèches en débord : elles rentrent sur la piste. */
  .shine-carousel__arrow--prev { left: 4px; }
  .shine-carousel__arrow--next { right: 4px; }
}

@media (max-width: 767.98px) {
  .shine-pblock { margin-top: 40px; }

  .shine-carousel .products {
    gap: 12px;
    /* Au doigt, les flèches n'apportent rien et masqueraient une vignette sur
       deux : le balayage suffit. Même précaution qu'en haut de page contre le
       rebond vertical d'iOS. */
    touch-action: pan-x;
    scroll-snap-type: x proximity;
  }

  .shine-carousel .products > * {
    flex-basis: calc((100% - 12px) / 2);
    max-width: calc((100% - 12px) / 2);
  }

  .shine-carousel__arrow { display: none; }
}

/* ==========================================================================
   17. CONTENU DU PSEUDO-PACK — liste, dans l'onglet (03/09/2026)

   Le bloc est passé par une étagère horizontale dans la journée avant de revenir
   à la liste : le contenu d'un pack se lit, il ne se balaye pas. Une ligne par
   article, produits d'abord puis accessoires (tri fait dans le gabarit, la
   convention AS/ACS étant propre à cette boutique), et une ligne de synthèse.
   ========================================================================== */

#product .shine-pblock--pack {
  margin: 0;
}

/* Intertitres de groupe : « Produits » puis « Accessoires ». Discrets — ils
   rangent la liste, ils ne la commentent pas. */
#product .shine-packgroup + .shine-packgroup {
  margin-top: 14px;
}

#product .shine-packgroup__title {
  margin: 0 0 4px;
  padding-bottom: 4px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--shine-muted);
  border-bottom: 1px solid var(--shine-line);
}

/* 🔴 CLASSE DOUBLÉE, et ce n'est pas une coquille. La liste du pack vit dans un
   volet d'onglet, où `#product .shine-tabs__content ul` (plus haut dans ce même
   fichier) impose déjà `list-style: disc` et `padding-left: 1.35em` — c'est ce
   qui habille les listes des descriptions produit. Cette règle-là pèse (1,1,1) ;
   un simple `#product .shine-packlist` ne pèse que (1,1,0) et perdait, d'où la
   puce et le décalage de 20 px constatés le 03/09.
   Répéter la classe monte à (1,2,0), qui l'emporte — et, contrairement à un
   `#product .shine-tabs__content ul.shine-packlist`, ça ne dépend pas de
   l'endroit où le bloc est posé. Il a déjà déménagé deux fois dans la journée. */
#product .shine-packlist.shine-packlist,
#product .shine-packlist.shine-packlist > li {
  margin: 0;
  padding-left: 0;
  list-style: none;
}

#product .shine-packlist.shine-packlist > li::marker {
  content: "";
}

#product .shine-packrow + .shine-packrow {
  border-top: 1px solid var(--shine-line);
}

/* Lignes resserrées (03/09/2026) : à 76 px, huit articles poussaient la synthèse
   hors de l'écran. L'information par ligne est courte — un nom, une contenance,
   un prix — elle n'a pas besoin de cette hauteur. */
#product .shine-packrow__link {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 4px;
  color: inherit;
  text-decoration: none;
}

#product .shine-packrow__link:hover {
  background: var(--shine-white);
}

#product .shine-packrow__link:hover .shine-packrow__name {
  text-decoration: underline;
}

#product .shine-packrow__image {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  object-fit: contain;
  /* Les visuels produits sont détourés sur blanc : le fondu multiplié évite le
     carré blanc sur la ligne, sans avoir à retoucher les fichiers. */
  mix-blend-mode: multiply;
}

#product .shine-packrow__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

#product .shine-packrow__name {
  font-family: "Anek", system-ui, sans-serif;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--shine-ink);
}

#product .shine-packrow__qty {
  font-weight: 700;
  color: var(--shine-dark);
}

#product .shine-packrow__variant {
  font-size: 12px;
  line-height: 1.25;
  color: var(--shine-muted);
}

#product .shine-packrow__price {
  flex: 0 0 auto;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 14px;
  font-weight: 700;
  color: var(--shine-ink);
  white-space: nowrap;
}

/* --- la ligne de synthèse -----------------------------------------------
   Ce qu'il y a dedans à gauche, ce qu'on économise à droite. La puce est en
   encre foncée sur le vert de marque, jamais l'inverse : ce vert en TEXTE sur
   fond clair tombe à 1,10:1, illisible, alors qu'inversé il donne 16,5:1. */
#product .shine-packlist__total {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1.5px solid var(--shine-line-strong);
  font-family: "Anek", system-ui, sans-serif;
  font-size: 14px;
}

#product .shine-packlist__count {
  font-weight: 700;
  color: var(--shine-ink);
}

#product .shine-packlist__money {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* Les deux pastilles restent solidaires : elles disent la même remise de deux
   façons, les séparer sur deux lignes casserait la lecture. */
#product .shine-packlist__badges {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

#product .shine-packlist__total-label,
#product .shine-packlist__total-sum {
  color: var(--shine-muted);
}

#product .shine-packlist__total-sum {
  font-weight: 600;
  text-decoration-thickness: 1px;
}

#product .shine-packlist__saving,
#product .shine-packlist__rate {
  padding: 4px 12px;
  font-weight: 700;
  border-radius: 999px;
  white-space: nowrap;
}

/* Le MONTANT en vert de marque, encre foncée dessus : ce vert en texte sur fond
   clair tombe à 1,10:1, inversé il donne 16,5:1. */
#product .shine-packlist__saving {
  color: var(--shine-dark);
  background: var(--shine-race);
}

/* Le TAUX en noir : deux pastilles vertes côte à côte se seraient confondues en
   une seule tache, et le noir de charte donne 17,8:1 en blanc dessus. */
#product .shine-packlist__rate {
  color: var(--shine-white);
  background: var(--shine-dark);
}

@media (max-width: 575px) {
  /* La synthèse repasse en colonne : côte à côte, le libellé de gauche se
     coupait en trois lignes pour laisser la place au montant. */
  #product .shine-packlist__total {
    flex-direction: column;
    align-items: flex-start;
  }

  /* Sous 576 px, « Achetés séparément : 90,80 € » et les pastilles ne tiennent
     plus sur la même ligne : les pastilles prennent la leur, ensemble. */
  #product .shine-packlist__badges {
    flex: 0 0 100%;
    margin-top: 2px;
  }

  #product .shine-packrow__image {
    flex-basis: 38px;
    width: 38px;
    height: 38px;
  }

  #product .shine-packrow__name { font-size: 13.5px; }
  #product .shine-packrow__price { font-size: 13.5px; }
}

/* ==========================================================================
   18. VARIANTE « CARTES BALAYABLES » du contenu de pack (03/09/2026)

   Présentation alternative soumise à Anne, activée par `?packview=swipe`.
   Elle réutilise la mécanique des carrousels produits (`.shine-carousel` +
   `.products`) : seules les dimensions de la vignette sont propres au pack.
   Si la liste est retenue, cette section part avec les deux gabarits.
   ========================================================================== */

/* Une piste par groupe : la gouttière sous l'intertitre suffit à les séparer. */
#product .shine-packstrip {
  padding: 2px 0 6px;
}

/* Cartes larges : le nom monte à 15 px et tient sur deux lignes. À 168 px il
   passait à 13 px et coupait un nom sur deux — l'inverse de ce qu'on cherche
   quand on met les produits en avant. */
#product .shine-packgroup .shine-packstrip > * {
  flex: 0 0 200px;
  max-width: 200px;
}

#product .shine-packcard {
  height: 100%;
  background: #fff;
  border: 1px solid var(--shine-line);
  border-radius: 12px;
  overflow: hidden;
  transition: border-color 0.15s ease;
}

#product .shine-packcard:hover {
  border-color: var(--shine-dark);
}

#product .shine-packcard__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  color: inherit;
  text-decoration: none;
}

#product .shine-packcard__media {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;
  background: var(--shine-white);
}

#product .shine-packcard__image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  mix-blend-mode: multiply;
}

/* La quantité est posée SUR l'image : deux exemplaires du même article, c'est
   une information de prix, pas une décoration. */
#product .shine-packcard__qty {
  position: absolute;
  top: 8px;
  right: 8px;
  padding: 2px 9px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 13px;
  font-weight: 700;
  color: var(--shine-dark);
  background: var(--shine-race);
  border-radius: 999px;
}

#product .shine-packcard__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px 12px;
}

/* Deux lignes puis points de suspension : au-delà, les cartes n'ont plus la
   même hauteur et la rangée se déforme au balayage. Le `title` du gabarit garde
   le nom entier accessible. */
#product .shine-packcard__name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--shine-ink);
}

#product .shine-packcard__variant {
  font-size: 12.5px;
  color: var(--shine-muted);
}

#product .shine-packcard__price {
  margin-top: auto;
  padding-top: 6px;
  font-family: "Anek", system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  color: var(--shine-ink);
}

@media (max-width: 767.98px) {
  /* Au doigt, une carte et demie visible indique qu'il y en a d'autres à côté
     sans réduire la première à une vignette. */
  #product .shine-packgroup .shine-packstrip > * {
    flex-basis: 158px;
    max-width: 158px;
  }

  #product .shine-packcard__name { font-size: 14px; }
  #product .shine-packcard__price { font-size: 14px; }
}
