/* ═══════════════════════════════════════════════════════════
   CUBX THEME — theme-cart.css (v2.5.99 — Sprint 3 Vague 1A.3.2 refonte)
   ───────────────────────────────────────────────────────────
   Charge à priority 218 (entre theme-category.css 215 et fixes 220).

   Contient les styles dédiés à l'UI panier CUBX :
     1. Cart buttons (header mode + floating mode) — v2.5.99 (1A.3.2 refonte)
     2. Cart drawer (slide-in droite)              — v2.5.99 (1A.3.2 refonte)
     3. Animations ATC (none/pulse/fly)            — viendra en v2.6.0 (1A.3.3)

   Variables CSS consommées :
     --cubx-accent       (couleur principale = rose CUBX)
     --cubx-accent-2     (variante hover)
     --h2j-text          (texte foncé #1a1f2c)
     --h2j-text-light    (texte gris #6b7280)
     --h2j-bg            (blanc #ffffff)
     --h2j-bg-light      (gris clair #f8f7ff)
     --h2j-border        (bordure #e5e7eb)
     --cubx-radius       (rayon arrondi global = 6px par défaut)

   Le markup des boutons est posé par Smarty selon le mode BO :
     - cart-header-button.tpl   : mode 'header'   (inséré dans .header-right)
     - cart-floating-button.tpl : mode 'floating' (fixed bottom-right|left)

   @author    H2J Ecosystem <info@2klove.fr>
   @copyright 2024-2026 H2J sas RCS 978391720
   @since     v2.5.97 (création) / v2.5.99 (refonte)
   ═══════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════
   1. CART BUTTONS — v2.5.99 (1A.3.2 refonte)
   ───────────────────────────────────────────────────────────
   2 modes distincts :
     1.A. Mode 'header'   : bouton dans .header-right (équivalent burger top-left)
     1.B. Mode 'floating' : FAB cubique en coin bas (visible si articles ≥ 1)

   Les 2 modes partagent la classe de base .cubx-cart-btn et le badge
   .cubx-cart-btn__badge, mais ont chacun leurs modificateurs spécifiques.
   ═══════════════════════════════════════════════════════════ */

/* ── Base partagée entre modes ── */
.cubx-cart-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  flex-shrink: 0;
}

.cubx-cart-btn:hover,
.cubx-cart-btn:focus-visible {
  text-decoration: none;
}

/* v2.5.116 — Wrapper de l'icône pour servir de containing block au badge en sur-impression.
   Strictement aligné sur le pattern .h2j-mm-cart-card__icon de la cart-card megamenu :
   même taille (carré ~icon size), même position relative pour ancrer le badge absolute.
   Le badge devient ainsi posé sur l'ICÔNE (pas sur le bouton parent) — identité visuelle
   parfaite avec la cart-card megamenu, et plus jamais rogné par l'edge viewport. */
.cubx-cart-btn__icon-wrap {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  /* La taille du wrapper suit la taille de l'icône SVG à l'intérieur (22×22).
     Pas de width/height fixes : le SVG dicte la taille naturelle. */
}

.cubx-cart-btn__icon {
  flex-shrink: 0;
  display: block;
}

/* Badge compteur — v2.5.119 architecture revue : badge SOUS l'icône, jamais en
   sur-impression dessus. L'icône reste 100% visible et lisible.

   Évolution :
     - v2.5.116 : badge top:-6 right:-6 (en sur-impression coin haut-droit de l'icône)
     - v2.5.118 : badge bottom:-6 left:-6 (en sur-impression coin bas-gauche)
     - v2.5.119 : badge top:100% (juste SOUS l'icône) — l'icône n'est plus jamais
                   masquée par le badge. Décalé légèrement à gauche (left:-2px)
                   pour la signature visuelle "décalé" comme idyll, et le bouton
                   header est repositionné via padding-top pour laisser place au
                   badge en dessous (cf. .cubx-cart-btn--header).

   Pattern : le icon-wrap est le containing block (position:relative). Le badge
   en position:absolute avec top:100% se place pile sous le wrapper. Le bouton
   header parent (56×56) a maintenant un padding-top + flex-direction:column
   pour réserver l'espace nécessaire au badge en dessous de l'icône, sans
   modifier la taille externe du bouton.

   Note : la cart-card du megamenu sidebar conserve sa position historique
   (top-right en sur-impression) — non modifiée selon volonté David. */
.cubx-cart-btn__badge {
  position: absolute;
  top: 100%;
  left: -2px;
  margin-top: 2px;
  display: flex;
  align-items: center;
  justify-content: center;

  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;

  background: var(--cubx-accent, #e91e63);
  color: var(--h2j-bg, #ffffff);
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  text-align: center;
  box-sizing: content-box;
  border: 2px solid var(--h2j-bg, #ffffff);

  transition:
    transform 0.15s cubic-bezier(0.4, 0, 0.2, 1),
    background-color 0.15s ease;
}

.cubx-cart-btn__badge[hidden] {
  display: none;
}


/* ═══════════════════════════════════════════════════════════
   1.A. MODE 'HEADER' — bouton fixe dans .header-right
   ───────────────────────────────────────────────────────────
   Style strictement aligné sur .cubx-menu-toggle (burger megamenu) :
     - 40x40px
     - border 1px solid var(--h2j-border)
     - border-radius var(--cubx-radius) (= 6px)
     - background transparent
     - hover : bg light + border accent
   ═══════════════════════════════════════════════════════════ */

.cubx-cart-btn--header {
  /* v2.5.107 — Symétrie parfaite avec le burger megamenu (top-left).
     Le bouton sort de .header-top (qui est caché par html.h2j-mm-active)
     et devient un corner fixed top-right 56×56, miroir du burger 56×56 top-left.

     Spécs visuelles alignées sur .h2j-mm-burger--floating :
       - position: fixed top:0 right:0 (vs burger top:0 left:0)
       - 56×56px (même taille)
       - background blanc, color text foncé
       - border-radius 0 0 0 12px (arrondi bas-gauche, miroir du burger
         qui a 0 0 12px 0 = arrondi bas-droite)
       - box-shadow -2px 2px 8px rgba(0,0,0,0.12) (miroir 2px 2px 8px du burger)
       - z-index 850 (même que burger)

     Pourquoi pas dans .header-right :
     v2.5.99-106 le bouton vivait dans .header-right (.header-top > .container).
     Mais le megamenu pose `html.h2j-mm-active` qui doit cacher .header-top
     intégralement (architecture voulue : le burger remplace toute la legacy nav).
     Tenter de préserver .header-right créait un bandeau résiduel pleine largeur
     visible (cf. screenshot David v2.5.106). Solution propre : le bouton sort
     du DOM .header-top et devient un élément flottant indépendant en miroir
     du burger. */
  position: fixed !important;
  top: 0 !important;
  right: 0 !important;
  left: auto !important;
  z-index: 850 !important;

  display: inline-flex !important;
  visibility: visible !important;
  opacity: 1 !important;
  align-items: center;
  justify-content: center;

  width: 56px !important;
  height: 56px !important;
  flex-shrink: 0;
  margin: 0 !important;

  /* v2.5.119 — Padding-top pour remonter l'icône dans le bouton et libérer
     l'espace en bas pour le badge (qui se pose sous l'icône via top:100%).
     L'icône (22×22) reste centrée horizontalement, mais déplacée vers le haut
     du bouton (offset ~6px par rapport au centre vertical strict).
     Compensation : le badge en dessous (16h + 2 margin = 18px total) tient
     dans les 17px d'espace bas + débord léger naturel. */
  padding-top: 6px !important;

  background-color: var(--h2j-bg, #ffffff);
  color: var(--h2j-text, #1a1f2c);
  border: none;
  /* Miroir du burger : burger = 0 0 12px 0 (arrondi bas-droite),
     cart  = 0 0 0 12px (arrondi bas-gauche) */
  border-radius: 0 0 0 12px;
  /* Miroir du box-shadow burger (2px 2px 8px) → -2px 2px 8px */
  box-shadow: -2px 2px 8px rgba(0, 0, 0, 0.12);

  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.cubx-cart-btn--header:hover,
.cubx-cart-btn--header:focus-visible {
  background-color: var(--h2j-bg-light, #f8f7ff);
  color: var(--cubx-accent, #e91e63);
  text-decoration: none;
  outline: none;
}

.cubx-cart-btn--header:focus-visible {
  outline: 2px solid var(--cubx-accent, #e91e63);
  outline-offset: 2px;
}

/* Badge en mode header : pas d'override de positionnement nécessaire.
   v2.5.119 — le positionnement (top:100% left:-2 margin-top:2) est sur le
   badge global et le bouton header a un padding-top:6 pour libérer l'espace.
   La pile s'aligne naturellement : icône en haut → badge directement dessous. */


/* ═══════════════════════════════════════════════════════════
   1.B. MODE 'FLOATING' — FAB cubique en coin de page
   ───────────────────────────────────────────────────────────
   Style cube arrondi (radius 16px = cube modéré, plus grand que le mode header
   pour être plus visible), 56px (48px mobile), accent rose, élévation Material.

   Position fixe en bottom-right OU bottom-left selon modificateur.
   Visible UNIQUEMENT si .cubx-cart-btn--visible (ajouté par JS si articles ≥ 1).
   ═══════════════════════════════════════════════════════════ */

.cubx-cart-btn--floating {
  position: fixed;
  bottom: 20px;
  z-index: 1050;

  width: 56px;
  height: 56px;
  border-radius: 16px; /* Cube modéré, distinct du burger 6px */
  background-color: var(--cubx-accent, #e91e63);
  color: #ffffff;
  border: none;

  /* Élévation Material */
  box-shadow:
    0 4px 12px rgba(0, 0, 0, 0.15),
    0 2px 4px rgba(0, 0, 0, 0.1);

  /* Caché par défaut — JS ajoute .cubx-cart-btn--visible */
  display: none;

  transition:
    transform 0.2s cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1),
    background-color 0.15s ease;
}

/* Position bottom-right (défaut) */
.cubx-cart-btn--floating.cubx-cart-btn--bottom-right {
  right: 20px;
}

/* Position bottom-left */
.cubx-cart-btn--floating.cubx-cart-btn--bottom-left {
  left: 20px;
}

/* Visible state — posé par JS si articles ≥ 1 */
.cubx-cart-btn--floating.cubx-cart-btn--visible {
  display: inline-flex;
}

/* Hover/focus : scale up + shadow plus forte */
.cubx-cart-btn--floating:hover,
.cubx-cart-btn--floating:focus-visible {
  background-color: var(--cubx-accent-2, var(--cubx-accent, #c2185b));
  box-shadow:
    0 6px 20px rgba(0, 0, 0, 0.2),
    0 4px 8px rgba(0, 0, 0, 0.12);
  transform: scale(1.05);
  color: #ffffff;
  outline: none;
}

.cubx-cart-btn--floating:active {
  transform: scale(0.98);
  box-shadow:
    0 2px 8px rgba(0, 0, 0, 0.15),
    0 1px 2px rgba(0, 0, 0, 0.1);
}

/* Badge en mode floating : v2.5.119 aligné sur le mode header (badge sous icône).
   Override des couleurs uniquement (contraste foncé sur fond rose accent du FAB). */
.cubx-cart-btn--floating {
  /* Padding-top miroir du header pour libérer l'espace badge en dessous icône. */
  padding-top: 6px;
}

.cubx-cart-btn--floating .cubx-cart-btn__badge {
  background-color: var(--h2j-text, #1a1f2c); /* Contraste sur fond rose */
}


/* ═══════════════════════════════════════════════════════════
   RESPONSIVE — Mobile/Tablet
   ═══════════════════════════════════════════════════════════ */

@media (max-width: 768px) {
  /* v2.5.119 — Mobile : badge légèrement agrandi pour lisibilité, position
     conservée (top:100% left:-2 margin-top:2 hérité du desktop). On override
     uniquement la taille et la border. */
  .cubx-cart-btn--header .cubx-cart-btn__badge {
    min-width: 18px;
    height: 18px;
    font-size: 10px;
    border-width: 1.5px;
  }

  /* Mode floating : réduit à 48px et resserré aux bords */
  .cubx-cart-btn--floating {
    width: 48px;
    height: 48px;
    border-radius: 14px;
    bottom: 16px;
    box-shadow:
      0 3px 10px rgba(0, 0, 0, 0.15),
      0 1px 3px rgba(0, 0, 0, 0.1);
  }

  .cubx-cart-btn--floating.cubx-cart-btn--bottom-right {
    right: 16px;
  }
  .cubx-cart-btn--floating.cubx-cart-btn--bottom-left {
    left: 16px;
  }

  .cubx-cart-btn--floating .cubx-cart-btn__icon {
    width: 22px;
    height: 22px;
  }
}


/* ═══════════════════════════════════════════════════════════
   ACCESSIBILITY — prefers-reduced-motion
   ═══════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .cubx-cart-btn,
  .cubx-cart-btn__badge {
    transition: none;
  }

  .cubx-cart-btn:hover,
  .cubx-cart-btn:focus-visible,
  .cubx-cart-btn:active {
    transform: none;
  }
}


/* ═══════════════════════════════════════════════════════════
   2. CART DRAWER (slide-in droite) — v2.5.99 (1A.3.2 refonte)
   ───────────────────────────────────────────────────────────
   Drawer qui slide depuis la droite quand on clique le bouton panier.
   Refonte depuis le dropdown top de v2.5.98.

   Architecture identique : header sticky / body scrollable / footer sticky.
   Largeur fixe 420px desktop, 100% mobile.
   Hauteur 100vh.

   States gérés par JS (cubx-core.js initCartDrawer) :
     - Default                  : caché (display:none + hidden attr)
     - .cubx-cart-drawer--open  : afficher (display:block) +
                                   backdrop fade-in + panel slide-in droite
   ═══════════════════════════════════════════════════════════ */

.cubx-cart-drawer {
  /* Container plein écran : couvre toute la viewport */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1100; /* Au-dessus des cart buttons (1050) */

  /* v2.5.101 — même fix dvh sur le container : sur certains browsers mobiles,
     position:fixed top:0 bottom:0 ne couvre pas exactement la viewport visible
     parce que la barre URL est animée. dvh garantit la zone visible. */
  height: 100vh;
  height: 100dvh;

  /* Caché par défaut — JS ajoute .cubx-cart-drawer--open */
  display: none;
}

.cubx-cart-drawer--open {
  display: block;
}

/* Backdrop semi-transparent qui fade-in/out.
   v2.5.142 — Sprint 4 V2.1.7 : aligné sur la durée/easing du panel (850ms)
   pour synchroniser le fade backdrop avec le fade-slide du panel. */
.cubx-cart-drawer__backdrop {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.45);
  opacity: 0;
  backdrop-filter: blur(0);
  -webkit-backdrop-filter: blur(0);
  transition: opacity 0.85s cubic-bezier(0.4, 0, 0.2, 1),
              backdrop-filter 0.85s cubic-bezier(0.4, 0, 0.2, 1),
              -webkit-backdrop-filter 0.85s cubic-bezier(0.4, 0, 0.2, 1);
  cursor: pointer;
}

.cubx-cart-drawer--open .cubx-cart-drawer__backdrop {
  opacity: 1;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

/* Mobile : pas de blur (perf cost trop élevé sur GPU mobile, déclenche reflow
   complet à chaque frame d'animation). On garde uniquement le fade opacity. */
@media (max-width: 768px) {
  .cubx-cart-drawer__backdrop,
  .cubx-cart-drawer--open .cubx-cart-drawer__backdrop {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* Panel principal — slide-in depuis la droite */
.cubx-cart-drawer__panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;

  /* Largeur fixe desktop, full mobile */
  width: 420px;
  max-width: 100%;
  /* v2.5.101 — Hauteur : utilise 100dvh (dynamic viewport) qui exclut les barres
     URL/system mobile, fallback 100vh pour vieux navigateurs. Sans dvh, sur Safari
     iOS le panel dépassait l'écran visible → le footer (CTAs Order/View cart) était
     sous la barre URL, le user ne voyait pas la fin du drawer. Avec dvh, le panel
     est strictement égal à la zone visible et le body scrolle correctement entre
     header et footer. */
  height: 100vh;
  height: 100dvh;

  display: flex;
  flex-direction: column;

  background-color: var(--h2j-bg, #ffffff);
  /* Pas de border-radius sur le côté gauche pour un alignement net avec le bord */
  box-shadow: -8px 0 32px rgba(0, 0, 0, 0.15);

  /* État fermé : translaté vers la droite (off-screen) + opacity 0.
     v2.5.142 — Sprint 4 V2.1.7 : transposition fidèle du pattern fade-slide ID4
     du megamenu (.h2j-mm-sidebar--anim-fade-slide). David a constaté que l'anim
     v2.5.140 (350ms iOS easing) était imperceptible à l'écran malgré être techniquement
     correcte. Le megamenu utilise 850ms cubic-bezier Material avec opacity ease-out.
     On aligne strictement sur cette formule pour avoir la même sensation visuelle
     entre les 2 drawers (megamenu à gauche, cart à droite — symétriques).
     Avant V2.1.5 : transition transform 280ms cubic-bezier Material standard.
     V2.1.5 : 350ms iOS easing (trop court à l'œil).
     V2.1.7 : 850ms cubic-bezier(0.4, 0, 0.2, 1) Material + opacity ease-out 850ms.
     Le panel translate de 100% → 0 (slide complet, pas un mini-glissement) ET fade
     simultanément, donnant le même effet smooth & pro que l'ID4 megamenu. */
  opacity: 0;
  transform: translateX(100%);
  transition: transform 0.85s cubic-bezier(0.4, 0, 0.2, 1),
              opacity 0.85s ease-out;

  /* v2.5.101 — important : le panel est un FLEX container vertical.
     Le body interne doit avoir flex:1 1 auto + overflow-y:auto pour scroller
     entre header (sticky top) et footer (sticky bottom). */
  overflow: hidden;
}

.cubx-cart-drawer--open .cubx-cart-drawer__panel {
  opacity: 1;
  transform: translateX(0);
}

/* ── Header sticky (titre + close X) ── */
.cubx-cart-drawer__header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--h2j-border, #e5e7eb);
  background-color: var(--h2j-bg, #ffffff);
}

.cubx-cart-drawer__title {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--h2j-text, #1a1f2c);
}

.cubx-cart-drawer__count {
  font-weight: 400;
  font-size: 14px;
  color: var(--h2j-text-light, #6b7280);
  margin-left: 4px;
  text-transform: none;
  letter-spacing: 0;
}

.cubx-cart-drawer__close {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--h2j-text, #1a1f2c);
  border-radius: var(--cubx-radius, 6px);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.cubx-cart-drawer__close:hover,
.cubx-cart-drawer__close:focus-visible {
  background-color: var(--h2j-bg-light, #f8f7ff);
  outline: none;
}

/* ── Body scrollable ── */
.cubx-cart-drawer__body {
  flex: 1 1 auto;
  /* v2.5.101 — min-height:0 indispensable pour que le flex child puisse rétrécir
     en dessous de sa hauteur intrinsèque de contenu et activer son overflow-y.
     Sans ça, le body grandit pour contenir tous ses items et fait sortir le panel
     du viewport (drawer mobile sans scroll). */
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 8px 0;
}

.cubx-cart-drawer__body::-webkit-scrollbar {
  width: 6px;
}
.cubx-cart-drawer__body::-webkit-scrollbar-track {
  background: transparent;
}
.cubx-cart-drawer__body::-webkit-scrollbar-thumb {
  background: var(--h2j-border, #e5e7eb);
  border-radius: 3px;
}
.cubx-cart-drawer__body::-webkit-scrollbar-thumb:hover {
  background: var(--h2j-text-light, #6b7280);
}

.cubx-cart-drawer__items {
  list-style: none;
  margin: 0;
  padding: 0;
}

.cubx-cart-drawer__item {
  display: grid;
  grid-template-columns: 80px 1fr auto;
  gap: 12px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--h2j-border, #f0f0f0);
  align-items: start;
}

.cubx-cart-drawer__item:last-child {
  border-bottom: none;
}

/* Vignette */
.cubx-cart-drawer__item-image {
  display: block;
  width: 80px;
  height: 80px;
  border-radius: var(--cubx-radius, 6px);
  overflow: hidden;
  background-color: var(--h2j-bg-light, #f8f7ff);
  flex-shrink: 0;
}

.cubx-cart-drawer__item-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Body : nom + déclis + prix unit */
.cubx-cart-drawer__item-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.cubx-cart-drawer__item-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--h2j-text, #1a1f2c);
  text-decoration: none;
  line-height: 1.3;

  /* Tronquer à 2 lignes max */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.cubx-cart-drawer__item-name:hover {
  color: var(--cubx-accent, #e91e63);
}

.cubx-cart-drawer__item-attrs {
  font-size: 12px;
  color: var(--h2j-text-light, #6b7280);
  line-height: 1.3;
}

.cubx-cart-drawer__item-attr-label {
  font-weight: 500;
}

.cubx-cart-drawer__item-price-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-top: 2px;
}

.cubx-cart-drawer__item-regular-price {
  font-size: 12px;
  color: var(--h2j-text-light, #6b7280);
  text-decoration: line-through;
}

.cubx-cart-drawer__item-price {
  font-size: 13px;
  font-weight: 600;
  color: var(--h2j-text, #1a1f2c);
}

/* Actions : qty stepper + total + remove */
.cubx-cart-drawer__item-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  min-width: 0;
}

.cubx-cart-drawer__item-qty {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--h2j-border, #e5e7eb);
  border-radius: var(--cubx-radius, 6px);
  overflow: hidden;
  background-color: var(--h2j-bg, #ffffff);
}

/* v2.5.101 — boutons +/- du qty stepper */
.cubx-cart-drawer__item-qty-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 32px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--h2j-text-light, #6b7280);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
  flex-shrink: 0;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}

/* v2.5.102 — fix click event handler : sur Firefox notamment, e.target peut
   être le <svg> ou un de ses children (<line>) au lieu du <button>, ce qui
   casse la délégation jQuery sur `[data-cubx-qty-action]`. En posant
   pointer-events:none sur le SVG, le click traverse l'icone et atteint
   directement le button parent → e.target = button → le matcher de
   délégation fonctionne. */
.cubx-cart-drawer__item-qty-btn svg,
.cubx-cart-drawer__item-qty-btn svg * {
  pointer-events: none;
}

.cubx-cart-drawer__item-qty-btn:hover,
.cubx-cart-drawer__item-qty-btn:focus-visible {
  background-color: var(--h2j-bg-light, #f8f7ff);
  color: var(--cubx-accent, #e91e63);
  outline: none;
}

.cubx-cart-drawer__item-qty-btn:active {
  background-color: var(--cubx-accent, #e91e63);
  color: #ffffff;
}

.cubx-cart-drawer__item-qty-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

.cubx-cart-drawer__item-qty-btn--down {
  border-right: 1px solid var(--h2j-border, #e5e7eb);
}

.cubx-cart-drawer__item-qty-btn--up {
  border-left: 1px solid var(--h2j-border, #e5e7eb);
}

.cubx-cart-drawer__item-qty-input {
  width: 40px;
  height: 32px;
  border: none;
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  color: var(--h2j-text, #1a1f2c);
  background: transparent;
  -moz-appearance: textfield;
  flex-shrink: 0;
}

/* v2.5.101 — cacher TOUJOURS les spinners natifs browser (les boutons +/-
   custom remplacent complètement la fonctionnalité). */

.cubx-cart-drawer__item-qty-input::-webkit-outer-spin-button,
.cubx-cart-drawer__item-qty-input::-webkit-inner-spin-button {
  -webkit-appearance: none !important;
  margin: 0 !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

.cubx-cart-drawer__item-qty-input:focus {
  outline: none;
  background-color: var(--h2j-bg-light, #f8f7ff);
}

.cubx-cart-drawer__item-total {
  font-size: 14px;
  font-weight: 700;
  color: var(--h2j-text, #1a1f2c);
}

.cubx-cart-drawer__item-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  color: var(--h2j-text-light, #6b7280);
  border-radius: 4px;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.cubx-cart-drawer__item-remove:hover,
.cubx-cart-drawer__item-remove:focus-visible {
  color: var(--cubx-accent, #e91e63);
  background-color: var(--h2j-bg-light, #f8f7ff);
  outline: none;
}

.cubx-cart-drawer__item-gift {
  font-size: 12px;
  font-style: italic;
  color: var(--cubx-accent, #e91e63);
  font-weight: 600;
}

/* Empty state */
.cubx-cart-drawer__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  color: var(--h2j-text-light, #6b7280);
}

.cubx-cart-drawer__empty svg {
  margin-bottom: 16px;
  opacity: 0.4;
}

.cubx-cart-drawer__empty-text {
  margin: 0;
  font-size: 14px;
  text-align: center;
}

/* ── Footer sticky (totaux + CTAs) ── */
.cubx-cart-drawer__footer {
  flex-shrink: 0;
  padding: 16px 20px;
  border-top: 1px solid var(--h2j-border, #e5e7eb);
  background-color: var(--h2j-bg, #ffffff);
}

/* ── Message de franco (module h2jlogistics) ── */
.cubx-cart-drawer__freeship-hint {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  padding: 10px 12px;
  border-radius: var(--cubx-radius, 6px);
  background: var(--cubx-accent-soft, #fdeef4);
  border: 1px solid var(--cubx-accent, #e91e63);
  color: var(--h2j-text, #1a1f2c);
  font-size: 13px;
  line-height: 1.4;
}

.cubx-cart-drawer__freeship-hint svg {
  flex-shrink: 0;
  color: var(--cubx-accent, #e91e63);
}

.cubx-cart-drawer__freeship-hint-text strong {
  color: var(--cubx-accent, #e91e63);
}

/* Etat franco atteint : message de felicitation en vert. */
.cubx-cart-drawer__freeship-hint--unlocked {
  background: var(--cubx-success-soft, #e8f6ed);
  border-color: var(--cubx-success, #2e9e54);
}

.cubx-cart-drawer__freeship-hint--unlocked svg,
.cubx-cart-drawer__freeship-hint--unlocked .cubx-cart-drawer__freeship-hint-text strong {
  color: var(--cubx-success, #2e9e54);
}

.cubx-cart-drawer__totals {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}

.cubx-cart-drawer__total-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 14px;
  color: var(--h2j-text, #1a1f2c);
}

.cubx-cart-drawer__total-line--discount {
  color: var(--cubx-accent, #e91e63);
}

.cubx-cart-drawer__total-line--total {
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid var(--h2j-border, #f0f0f0);
  font-size: 16px;
  font-weight: 700;
}

/* CTAs */
.cubx-cart-drawer__ctas {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.cubx-cart-drawer__cta {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 48px;
  padding: 0 16px;
  border-radius: var(--cubx-radius, 6px);
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-decoration: none;
  border: 2px solid transparent;
  cursor: pointer;
  transition: all 0.15s ease;
}

.cubx-cart-drawer__cta--primary {
  background-color: var(--cubx-accent, #e91e63);
  color: #ffffff;
}

.cubx-cart-drawer__cta--primary:hover,
.cubx-cart-drawer__cta--primary:focus-visible {
  background-color: var(--cubx-accent-2, #c2185b);
  color: #ffffff;
  outline: none;
  text-decoration: none;
}

.cubx-cart-drawer__cta--secondary {
  background-color: transparent;
  color: var(--h2j-text, #1a1f2c);
  border-color: var(--h2j-border, #e5e7eb);
}

.cubx-cart-drawer__cta--secondary:hover,
.cubx-cart-drawer__cta--secondary:focus-visible {
  background-color: var(--h2j-bg-light, #f8f7ff);
  border-color: var(--h2j-text, #1a1f2c);
  color: var(--h2j-text, #1a1f2c);
  outline: none;
  text-decoration: none;
}

/* ── Responsive mobile (≤768px) — drawer plein écran ── */
@media (max-width: 768px) {
  .cubx-cart-drawer__panel {
    width: 100%;
    max-width: 100%;
  }

  .cubx-cart-drawer__header {
    padding: 14px 16px;
  }

  .cubx-cart-drawer__title {
    font-size: 16px;
  }

  .cubx-cart-drawer__item {
    grid-template-columns: 64px 1fr auto;
    gap: 10px;
    padding: 10px 16px;
  }

  .cubx-cart-drawer__item-image {
    width: 64px;
    height: 64px;
  }

  .cubx-cart-drawer__item-name {
    font-size: 13px;
  }

  .cubx-cart-drawer__footer {
    padding: 12px 16px;
  }

  .cubx-cart-drawer__cta {
    height: 44px;
    font-size: 13px;
  }
}

/* ── prefers-reduced-motion ── */
@media (prefers-reduced-motion: reduce) {
  .cubx-cart-drawer__panel,
  .cubx-cart-drawer__backdrop {
    transition: none;
  }
}


/* ═══════════════════════════════════════════════════════════
   3. ANIMATIONS ATC — placeholder (sera implémenté en v2.6.0 / 1A.3.3)
   ═══════════════════════════════════════════════════════════ */

/* ═════════════════════════════════════════════════════════
   3. ANIMATIONS ATC — v2.5.112 (Sprint 3 Vague 1A.3.3 étape 1 : pulse)
   ═════════════════════════════════════════════════════════ */

/* Le mode est lu depuis H2JCUBX_ATC_ANIM_BADGE (BO) :
     - 'none'   : pas d'animation (défaut)
     - 'pulse'  : badge scale 1→1.3→1 + flash accent (350ms ease-out)        ← étape 1 ✅
     - 'bounce' : badge bond vertical -8px + scale + retour élastique (500ms)  ← étape 2 ✅
     - 'fly'    : bulle "+1" parabolique du bouton ATC vers le badge (800ms)  ← étape 3 ✅

   La classe .cubx-badge-anim-<mode> est ajoutée par cubx-core.js triggerBadgeAnim()
   au moment où le badge change de valeur (uniquement vers le haut, count >= 1). */

@keyframes cubx-badge-pulse {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 var(--cubx-accent, #e91e63);
  }
  50% {
    transform: scale(1.3);
    box-shadow: 0 0 0 8px rgba(233, 30, 99, 0);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 transparent;
  }
}

.cubx-cart-btn__badge.cubx-badge-anim-pulse {
  animation: cubx-badge-pulse 350ms ease-out;
  transform-origin: center center;
  will-change: transform, box-shadow;
}

/* v2.5.113 — Mode 'bounce' : bond vertical avec rebond élastique.
   Plus dynamique que pulse : le badge "saute" vers le haut puis retombe
   en passant légèrement sous sa position initiale avant de revenir.
   Combine translateY + scale pour un effet de squash & stretch.
   Easing cubic-bezier choisi pour un retour élastique sans rebond fou. */
@keyframes cubx-badge-bounce {
  0% {
    transform: translateY(0) scale(1);
  }
  30% {
    transform: translateY(-8px) scale(1.15);
  }
  60% {
    transform: translateY(2px) scale(0.95);
  }
  85% {
    transform: translateY(-1px) scale(1.02);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}

.cubx-cart-btn__badge.cubx-badge-anim-bounce {
  animation: cubx-badge-bounce 500ms cubic-bezier(0.34, 1.56, 0.64, 1);
  transform-origin: center center;
  will-change: transform;
}

/* prefers-reduced-motion : coupe TOUTES les animations badge (pulse + bounce + futurs modes).
   Le sélecteur attribut [class*="cubx-badge-anim-"] matche toute classe d'animation
   posée par triggerBadgeAnim() sans devoir lister chaque mode individuellement. */
@media (prefers-reduced-motion: reduce) {
  .cubx-cart-btn__badge[class*="cubx-badge-anim-"] {
    animation: none;
  }
  /* La bulle fly est inutile en reduced-motion : on la masque purement.
     Le triggerBadgeAnim() détecte aussi reduced-motion et fallback sur pulse,
     mais double protection ne fait pas de mal. */
  .cubx-fly-bubble {
    display: none !important;
  }
}

/* v2.5.114 — Mode 'fly' : bulle "+1" qui vole en parabole du bouton ATC source
   vers le badge cart-btn corner. La bulle est créée dynamiquement par cubx-core.js
   (flyToBadge()) en position:fixed avec coords initiales = bouton source. Une
   transition CSS la déplace ensuite vers le point intermédiaire (phase 1, montée)
   puis vers le badge (phase 2, descente avec scale-down + fade-out).

   La bulle est une pastille ronde 28px avec "+1" centré, couleur accent. Pas de
   border ni shadow lourde — minimaliste pour ne pas distraire de l'effet de vol. */
.cubx-fly-bubble {
  position: fixed;
  z-index: 9999;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--cubx-accent, #e91e63);
  color: #ffffff;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  user-select: none;
  /* Transition cubic-bezier identique pour les 2 phases — la trajectoire en
     parabole est obtenue côté JS en chaînant 2 transitions sur left/top. */
  transition: left 400ms cubic-bezier(0.4, 0, 0.6, 1),
              top 400ms cubic-bezier(0.4, 0, 0.6, 1),
              transform 400ms cubic-bezier(0.4, 0, 0.6, 1),
              opacity 400ms ease-out;
  /* Optimisation perf : compositor-only props pendant l'anim. */
  will-change: left, top, transform, opacity;
}

/* Phase 2 (descente) : la bulle fond et rétrécit en arrivant sur le badge.
   Cette classe est ajoutée en JS au moment du switch phase 1 → phase 2. */
.cubx-fly-bubble.cubx-fly-bubble--landing {
  transform: scale(0.4);
  opacity: 0;
}

/* ══════════════════════════════════════════════════════════
   4. ATC BUTTON CLICK FEEDBACK — v2.5.117 (microfeedback local)
   ══════════════════════════════════════════════════════════

   Problématique UX mobile : sur petits écrans, le badge cart-btn (top-right)
   est éloigné visuellement du bouton ATC qu'on vient de cliquer (typiquement
   dans la info-band noire en bas de la miniature ou en bas de la page produit).
   L'utilisateur ne voit pas le retour visuel et se demande si le produit a
   bien été ajouté.

   Solution : feedback LOCAL immédiat sur le bouton ATC lui-même au moment
   du click. Pulse rapide en 300ms (scale 1→0.96→1.04→1) + flash background.
   Plus court et plus marqué que l'anim badge (qui reste utile pour les events
   non-locaux : drawer +/-, ATC programmatique, etc.).

   La classe .cubx-atc-clicked est posée par cubx-core.js initATCSourceTracker()
   au moment du click, retirée après 300ms.

   Toujours actif quel que soit le mode d'animation badge (none/pulse/bounce/fly).
   Les 2 feedbacks sont complémentaires : ATC pulse confirme l'action, badge
   anim signale que le panier a été mis à jour. */

@keyframes cubx-atc-click-pulse {
  0% {
    transform: scale(1);
    filter: brightness(1);
  }
  20% {
    transform: scale(0.96);
    filter: brightness(0.92);
  }
  50% {
    transform: scale(1.04);
    filter: brightness(1.08);
  }
  100% {
    transform: scale(1);
    filter: brightness(1);
  }
}

/* La classe est ajoutée par initATCSourceTracker() sur l'élément cliqué.
   Sélecteurs cibles connus :
     - #add-to-cart-button (page produit)
     - button[data-button-action="add-to-cart"] (variante PS)
     - .hb-cart-btn (miniatures homeblocks — info-band noire)
     - [data-cubx-qty-action="up"] (drawer + — optionnel)
   Le sélecteur ci-dessous est volontairement générique pour matcher tous
   les variants sans énumérer chaque cas. */
.cubx-atc-clicked {
  animation: cubx-atc-click-pulse 300ms cubic-bezier(0.4, 0, 0.2, 1);
  transform-origin: center center;
  will-change: transform, filter;
}

/* prefers-reduced-motion : coupe l'animation, garde un simple flash de fond
   pour ne pas perdre le feedback (l'utilisateur a explicitement demandé moins
   d'animations, mais a quand même besoin de savoir que son click a été pris). */
@media (prefers-reduced-motion: reduce) {
  .cubx-atc-clicked {
    animation: none;
    filter: brightness(0.92);
    transition: filter 300ms ease-out;
  }
}

/* ============================================================================
   6. TOAST COMPONENT — v2.5.125 (Sprint 3 V1A.3.8)
   ============================================================================
   
   Toast feedback en haut d'écran. Créé dynamiquement par window.cubxShowToast()
   défini dans cubx-core.js. Stack en haut, mobile-first (top center), z-index
   au-dessus du drawer (1000) et du sticky bar (900).
   
   Markup généré :
     .cubx-toast-stack (container fixed top center)
       └ .cubx-toast.cubx-toast--<type> (info|success|error|warning)
            ├ .cubx-toast__icon (SVG)
            ├ .cubx-toast__msg (texte)
            └ .cubx-toast__close (× button)
   
   Transition : --in (slide down + fade in) / --out (fade out).
   ============================================================================ */

.cubx-toast-stack {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10000; /* au-dessus du drawer (1000) et sticky bar (900) */
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  max-width: calc(100vw - 32px);
  pointer-events: none; /* le stack ne capture pas les clicks, seuls les toasts */
}

.cubx-toast {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-width: 280px;
  max-width: 480px;
  padding: 12px 16px;
  background: var(--h2j-bg-card, #fff);
  border: 1px solid var(--h2j-border, #e5e7eb);
  border-left-width: 4px;
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  font-size: 14px;
  line-height: 1.4;
  color: var(--h2j-text, #1f2937);
  opacity: 0;
  transform: translateY(-20px);
  transition: opacity 250ms ease-out, transform 250ms ease-out;
  will-change: opacity, transform;
}

.cubx-toast--in {
  opacity: 1;
  transform: translateY(0);
}

.cubx-toast--out {
  opacity: 0;
  transform: translateY(-20px);
  transition: opacity 200ms ease-in, transform 200ms ease-in;
}

/* Variantes de couleur via border-left-color + couleur icône */
.cubx-toast--info {
  border-left-color: var(--h2j-info, #3b82f6);
}
.cubx-toast--info .cubx-toast__icon {
  color: var(--h2j-info, #3b82f6);
}

.cubx-toast--success {
  border-left-color: var(--h2j-success, #10b981);
}
.cubx-toast--success .cubx-toast__icon {
  color: var(--h2j-success, #10b981);
}

.cubx-toast--error {
  border-left-color: var(--h2j-error, #ef4444);
}
.cubx-toast--error .cubx-toast__icon {
  color: var(--h2j-error, #ef4444);
}

.cubx-toast--warning {
  border-left-color: var(--h2j-warning, #f59e0b);
}
.cubx-toast--warning .cubx-toast__icon {
  color: var(--h2j-warning, #f59e0b);
}

.cubx-toast__icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
}

.cubx-toast__msg {
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-word;
}

.cubx-toast__close {
  all: unset;
  cursor: pointer;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  color: var(--h2j-text-light, #6b7280);
  transition: color 150ms, background 150ms;
}

.cubx-toast__close:hover,
.cubx-toast__close:focus-visible {
  color: var(--h2j-text, #1f2937);
  background: var(--h2j-bg-light, #f3f4f6);
}

/* Mobile : full-width avec marges */
@media (max-width: 600px) {
  .cubx-toast-stack {
    top: 12px;
    left: 8px;
    right: 8px;
    transform: none;
    max-width: none;
  }
  .cubx-toast {
    min-width: 0;
    width: 100%;
    max-width: none;
    font-size: 13px;
    padding: 10px 12px;
  }
}

/* prefers-reduced-motion : pas de slide, juste fade */
@media (prefers-reduced-motion: reduce) {
  .cubx-toast {
    transform: none;
    transition: opacity 200ms;
  }
  .cubx-toast--in,
  .cubx-toast--out {
    transform: none;
  }
}

/* ============================================================================
   7. DRAWER ITEM REMOVAL ANIMATION — v2.5.125 (Sprint 3 V1A.3.4)
   ============================================================================
   
   Animation de suppression d'un item du drawer. Posée sur la ligne au moment
   du click "Supprimer", retirée après 200ms (timing aligné avec le setTimeout
   du handler dans cubx-core.js).
   
   Pattern : fade out + slide right (sortie vers la droite, comme si l'item
   était jeté hors du drawer).
   ============================================================================ */

.cubx-cart-drawer__item--removing {
  animation: cubx-drawer-item-remove 200ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
  pointer-events: none;
  will-change: opacity, transform;
}

@keyframes cubx-drawer-item-remove {
  0% {
    opacity: 1;
    transform: translateX(0);
    max-height: 200px;
  }
  100% {
    opacity: 0;
    transform: translateX(40px);
    max-height: 0;
    margin: 0;
    padding: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cubx-cart-drawer__item--removing {
    animation: none;
    opacity: 0;
    transition: opacity 100ms;
  }
}

/* ═══════════════════════════════════════════════════════════
   PAGE PANIER /panier — Sprint 4 V2.1.1 (squelette)
   ───────────────────────────────────────────────────────────
   Hero gallery à gauche (réutilise .cubx-hero-layout de theme-core.css),
   contenu panier à droite dans .cubx-hero-content avec layout 1 colonne
   (items en haut, summary en bas, mobile-first naturel).

   V2.1.1 livre : wrapper, header, placeholders V2.1.2/V2.1.3, état vide.
   V2.1.2 livrera les styles items.
   V2.1.3 livrera les styles summary + voucher + bouton checkout.
   ═══════════════════════════════════════════════════════════ */

.cubx-cart-page {
  /* Padding interne harmonisé avec PDP/drawer (~12px) */
  padding: 24px 28px 48px;
  max-width: 720px;
  margin: 0 auto;
}

/* ── Mode hero actif : pas de max-width, le hero-layout gère la largeur ── */
.cubx-hero-active.cubx-hero-cart .cubx-cart-page {
  max-width: none;
  margin: 0;
}

/* ── Header titre ── */
.cubx-cart-page__header {
  margin-bottom: 24px;
  text-align: center;
}

.cubx-cart-page__title {
  font-size: 32px;
  font-weight: 600;
  color: var(--h2j-text);
  margin: 0;
  letter-spacing: -0.02em;
}

@media (max-width: 767px) {
  .cubx-cart-page__title {
    font-size: 24px;
  }
  .cubx-cart-page {
    padding: 16px 16px 32px;
  }
}

/* ── Lien "Continuer mes achats" ── */
.cubx-cart-page__continue {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 24px 0;
  color: var(--h2j-text);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  transition: color 150ms ease;
}

.cubx-cart-page__continue:hover,
.cubx-cart-page__continue:focus {
  color: var(--cubx-accent);
  text-decoration: none;
}

.cubx-cart-page__continue svg {
  flex-shrink: 0;
}

/* ── Placeholders V2.1.1 (à supprimer en V2.1.2/V2.1.3) ── */
.cubx-cart-page__placeholder {
  background: var(--h2j-bg-light);
  border: 1px dashed var(--h2j-border);
  border-radius: var(--cubx-radius);
  padding: 24px;
  margin: 16px 0;
  text-align: center;
  color: var(--h2j-text-light);
}

.cubx-cart-page__placeholder p {
  margin: 0 0 8px;
  color: var(--h2j-text);
  font-weight: 500;
}

.cubx-cart-page__placeholder small {
  font-size: 12px;
  font-style: italic;
  opacity: 0.7;
}

.cubx-cart-page__placeholder--summary {
  background: var(--h2j-bg);
  border: 1px solid var(--h2j-border);
  border-style: solid;
}

/* ── État panier vide ── */
.cubx-cart-page__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 24px 16px 48px;
}

.cubx-cart-page__empty .cubx-cart-page__header {
  width: 100%;
  margin-bottom: 32px;
}

.cubx-cart-page__empty-icon {
  color: var(--h2j-text-light);
  margin: 24px 0 16px;
  opacity: 0.6;
}

.cubx-cart-page__empty-text {
  font-size: 16px;
  color: var(--h2j-text-light);
  margin: 0 0 32px;
}

.cubx-cart-page__empty-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 28px;
  background: var(--cubx-accent);
  color: #fff;
  border-radius: var(--cubx-radius);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: background 150ms ease, transform 150ms ease;
}

.cubx-cart-page__empty-cta:hover,
.cubx-cart-page__empty-cta:focus {
  background: var(--cubx-accent-2);
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
}

.cubx-cart-page__empty-cta:active {
  transform: translateY(0);
}

.cubx-cart-page__empty-cta svg {
  flex-shrink: 0;
}

/* ── Masquer cart corner top-right sur /panier (V2.1.1.1) ──
   L'utilisateur est déjà sur sa page panier complète, le bouton corner
   qui ouvre le drawer est redondant et bruit visuel. Le burger megamenu
   top-left reste visible pour permettre la navigation "continuer mes achats".
   PS 8.x ajoute body.page-cart sur le controller=cart, on cible large pour
   couvrir aussi les variantes (#checkout container body class). */
body.page-cart #cubx-cart-btn,
body.cart #cubx-cart-btn {
  display: none !important;
}

/* v2.5.140 — Sprint 4 V2.1.5 : cart corner conditionnel selon panier vide.
   Logique : si le panier est vide (count=0), le bouton cart corner top-right
   n'a aucun sens — on le masque. La classe `cubx-cart-empty` est posée sur <body>
   par updateCartCornerVisibility(count) dans cubx-core.js.
   Stratégie strict (validation David 02/05) : panier vide → corner caché PARTOUT.
   v2.5.140-fix : on cible #cubx-cart-btn dans son ensemble (pas seulement le mode
   floating) car le tpl cart-header-button.tpl rend le bouton avec la classe
   .cubx-cart-btn--header MAIS positionné en corner top-right via le CSS sticky
   header. Donc la règle de masquage doit s'appliquer aux 2 modes.
   v2.5.141 — Sprint 4 V2.1.6 : ajout !important obligatoire car la règle
   `.cubx-cart-btn--header` (qui est aussi appliquée au même btn) contient
   `display: inline-flex !important` qui écrasait notre `display: none` sans
   !important. Pattern cohérent avec la règle body.page-cart au-dessus qui
   utilise aussi !important pour la même raison. */
body.cubx-cart-empty #cubx-cart-btn {
  display: none !important;
}

/* v2.5.139 — Sprint 4 V2.1.4 : repositionner le `.notifications-container`
   PS Core sur la page panier. PS Core l'injecte au tout début de <body> (avant
   notre header CUBX), ce qui le fait passer SOUS le burger megamenu top-left
   et il est partiellement masqué. On le remonte avec margin-top + padding
   horizontal pour qu'il s'affiche proprement.
   Ces alertes apparaissent par exemple quand on tente d'aller au checkout
   alors qu'une qty dépasse le stock dispo ("Vous ne pouvez acheter que 3...").
   Avec V2.1.4, le clamp JS prévient ce cas, mais d'autres cas peuvent encore
   déclencher cette alerte (voucher invalide, contrainte fournisseur, etc.). */
body.page-cart .notifications-container {
  margin-top: 60px;
  padding: 0 24px;
  max-width: 1280px;
  margin-left: auto;
  margin-right: auto;
}

body.page-cart .notifications-container .alert {
  border-radius: var(--cubx-radius);
  padding: 12px 16px;
  font-size: 14px;
  line-height: 1.4;
}

body.page-cart .notifications-container .alert-danger {
  background: #fef2f2;
  border-color: #fecaca;
  color: #991b1b;
}

body.page-cart .notifications-container .alert ul {
  padding-left: 18px;
  margin: 0;
}

@media (max-width: 599px) {
  body.page-cart .notifications-container {
    margin-top: 56px;
    padding: 0 12px;
  }
}

/* ═══════════════════════════════════════════════════════════
   PAGE PANIER — ITEMS (Sprint 4 V2.1.2)
   ───────────────────────────────────────────────────────────
   Layout aéré idyll-style :
     - Image 100×100 à gauche
     - Body (nom, prix, attrs combi) au centre flex:1
     - Actions (qty stepper, total, trash) à droite
     - Bandeau OOS/low en pleine largeur dessous (si applicable)
   Mobile : layout vertical compact (image + body en haut, actions en bas).
   ═══════════════════════════════════════════════════════════ */

/* Wrapper liste items */
.cubx-cart-page__items-wrap {
  margin-bottom: 24px;
}

.cubx-cart-page__items-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ── Card item ligne horizontale aérée ── */
.cubx-cart-page__item {
  position: relative;
  display: grid;
  grid-template-columns: 100px 1fr auto;
  gap: 20px;
  padding: 16px;
  background: var(--h2j-bg);
  border: 1px solid var(--h2j-border);
  border-radius: var(--cubx-radius);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}

.cubx-cart-page__item:hover {
  border-color: var(--h2j-text-light);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.cubx-cart-page__item--oos {
  background: #fef9f9;
  border-color: #f3d4d4;
}

/* ── Image 100×100 ── */
.cubx-cart-page__item-image {
  position: relative;
  display: block;
  width: 100px;
  height: 100px;
  flex-shrink: 0;
  border-radius: 4px;
  overflow: hidden;
  background: var(--h2j-bg-light);
}

.cubx-cart-page__item-image img,
.cubx-cart-page__item-image picture,
.cubx-cart-page__item-image source {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Badge stock 3 états sur miniature — cohérence drawer + PDP gallery.
   Position : bottom-left de l'image, pill compact 11px police, padding 3×6. */
.cubx-cart-page__item-stock-badge {
  position: absolute;
  bottom: 4px;
  left: 4px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  padding: 3px 6px;
  border-radius: 3px;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  /* prevent screen readers from announcing twice (banner already does it) */
}

.cubx-cart-page__item-stock-badge--in_stock {
  background: #d1fae5;
  color: #065f46;
}

.cubx-cart-page__item-stock-badge--low_stock {
  background: #fed7aa;
  color: #9a3412;
}

.cubx-cart-page__item-stock-badge--out_of_stock {
  background: #fecaca;
  color: #991b1b;
}

/* ── Body : nom + prix + attrs ── */
.cubx-cart-page__item-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  /* min-width pour permettre text-overflow ellipsis sur le nom */
}

.cubx-cart-page__item-name {
  display: block;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--h2j-text);
  text-decoration: none;
  margin: 0;
  /* Wrap raisonnable, max 2 lignes (police 13px évite tronquage colonne étroite) */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.cubx-cart-page__item-name:hover,
.cubx-cart-page__item-name:focus {
  color: var(--cubx-accent);
  text-decoration: none;
}

.cubx-cart-page__item-price-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 2px 0 4px;
}

.cubx-cart-page__item-price {
  font-size: 15px;
  font-weight: 600;
  color: var(--h2j-text);
}

.cubx-cart-page__item-regular-price {
  font-size: 13px;
  color: var(--h2j-text-light);
  text-decoration: line-through;
}

/* ── Liste attributs combi ── */
.cubx-cart-page__item-attrs {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.cubx-cart-page__item-attr {
  font-size: 13px;
  color: var(--h2j-text-light);
  line-height: 1.4;
}

.cubx-cart-page__item-attr-label {
  display: inline;
}

.cubx-cart-page__item-attr-value {
  display: inline;
  color: var(--h2j-text);
  font-weight: 500;
}

.cubx-cart-page__item-customizations {
  list-style: none;
  padding: 0;
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--h2j-text-light);
  font-style: italic;
}

/* ── Actions : qty stepper + total + trash ── */
.cubx-cart-page__item-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-shrink: 0;
}

/* Qty stepper compact */
.cubx-cart-page__item-qty {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--h2j-border);
  border-radius: var(--cubx-radius);
  background: var(--h2j-bg);
  overflow: hidden;
}

.cubx-cart-page__item-qty-btn {
  width: 32px;
  height: 32px;
  background: var(--h2j-bg);
  border: 0;
  color: var(--h2j-text);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 150ms ease, color 150ms ease;
  padding: 0;
}

.cubx-cart-page__item-qty-btn:hover:not(:disabled) {
  background: var(--h2j-bg-light);
  color: var(--cubx-accent);
}

.cubx-cart-page__item-qty-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.cubx-cart-page__item-qty-btn svg {
  pointer-events: none;
  /* défense pour la délégation jQuery (cf. drawer pattern v2.5.102) */
}

.cubx-cart-page__item-qty-input {
  width: 40px;
  height: 32px;
  border: 0;
  border-left: 1px solid var(--h2j-border);
  border-right: 1px solid var(--h2j-border);
  background: var(--h2j-bg);
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  color: var(--h2j-text);
  -moz-appearance: textfield;
  appearance: textfield;
  /* Hide spin buttons natifs */
}

.cubx-cart-page__item-qty-input::-webkit-outer-spin-button,
.cubx-cart-page__item-qty-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.cubx-cart-page__item-qty-input:focus {
  outline: 2px solid var(--cubx-accent);
  outline-offset: -1px;
}

/* Total ligne */
.cubx-cart-page__item-total {
  font-size: 16px;
  font-weight: 700;
  color: var(--h2j-text);
  min-width: 80px;
  text-align: right;
}

/* Bouton remove (corbeille) */
.cubx-cart-page__item-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--cubx-radius);
  color: var(--h2j-text-light);
  background: transparent;
  text-decoration: none;
  transition: background 150ms ease, color 150ms ease;
}

.cubx-cart-page__item-remove:hover,
.cubx-cart-page__item-remove:focus {
  background: #fef2f2;
  color: #dc2626;
  text-decoration: none;
}

.cubx-cart-page__item-remove svg {
  pointer-events: none;
}

/* Gift label (si is_gift) */
.cubx-cart-page__item-gift {
  font-size: 13px;
  font-weight: 600;
  color: var(--cubx-accent);
  padding: 6px 12px;
  background: #fce7f3;
  border-radius: var(--cubx-radius);
}

/* ── Bandeau OOS / low stock pleine largeur sous l'item ── */
.cubx-cart-page__item-banner {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
}

.cubx-cart-page__item-banner svg {
  flex-shrink: 0;
}

.cubx-cart-page__item-banner--oos {
  background: #fef2f2;
  color: #991b1b;
  border: 1px solid #fecaca;
}

.cubx-cart-page__item-banner--low {
  background: #fffbeb;
  color: #9a3412;
  border: 1px solid #fed7aa;
}

/* ── Animation suppression item (miroir drawer v2.5.125) ── */
.cubx-cart-page__item--removing {
  animation: cubx-cart-page-item-remove 250ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
  pointer-events: none;
  will-change: opacity, transform, max-height;
}

@keyframes cubx-cart-page-item-remove {
  0% {
    opacity: 1;
    transform: translateX(0);
    max-height: 300px;
  }
  100% {
    opacity: 0;
    transform: translateX(40px);
    max-height: 0;
    margin: 0;
    padding-top: 0;
    padding-bottom: 0;
    border-width: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cubx-cart-page__item--removing {
    animation: none;
    opacity: 0;
    transition: opacity 100ms;
  }
}

/* ── Mobile : layout vertical compact ── */
@media (max-width: 599px) {
  .cubx-cart-page__item {
    grid-template-columns: 80px 1fr;
    gap: 12px;
    padding: 12px;
  }

  .cubx-cart-page__item-image {
    width: 80px;
    height: 80px;
  }

  /* Actions descendent en pleine largeur sous l'image+body */
  .cubx-cart-page__item-actions {
    grid-column: 1 / -1;
    justify-content: space-between;
    border-top: 1px solid var(--h2j-border);
    padding-top: 12px;
    margin-top: 4px;
  }

  .cubx-cart-page__item-name {
    font-size: 12px;
    -webkit-line-clamp: 2;
  }

  .cubx-cart-page__item-stock-badge {
    font-size: 9px;
    padding: 2px 5px;
  }

  .cubx-cart-page__item-total {
    min-width: auto;
    font-size: 15px;
  }
}

/* ═══════════════════════════════════════════════════════════
   PAGE PANIER — SUMMARY + VOUCHER + CHECKOUT (Sprint 4 V2.1.3)
   ───────────────────────────────────────────────────────────
   Card résumé inspirée idyll-style :
     - Card fond gris clair, ombre légère
     - Lignes subtotal/discount/shipping/tax/total empilées
     - Total final en gras avec border-top
     - Voucher en accordéon collapse-fermable ("Vous avez un code promo ?")
     - Bouton commander pleine largeur, accent rose, height 48px
   ═══════════════════════════════════════════════════════════ */

/* ── Wrapper card résumé ── */
.cubx-cart-page__summary-card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  background: var(--h2j-bg-light);
  border: 1px solid var(--h2j-border);
  border-radius: var(--cubx-radius);
  padding: 20px;
  margin-bottom: 24px;
}

/* ── Subtotals ── */
.cubx-cart-page__summary-totals {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.cubx-cart-page__summary-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  font-size: 14px;
  color: var(--h2j-text);
  line-height: 1.4;
}

.cubx-cart-page__summary-label {
  color: var(--h2j-text-light);
}

.cubx-cart-page__summary-value {
  font-weight: 500;
  color: var(--h2j-text);
  text-align: right;
  white-space: nowrap;
}

.cubx-cart-page__summary-line--discount {
  color: var(--cubx-accent);
}

.cubx-cart-page__summary-line--discount .cubx-cart-page__summary-label,
.cubx-cart-page__summary-line--discount .cubx-cart-page__summary-value {
  color: var(--cubx-accent);
}

/* Total final : border-top + font plus grand + gras */
.cubx-cart-page__summary-line--total {
  border-top: 1px solid var(--h2j-border);
  padding-top: 12px;
  margin-top: 4px;
  font-size: 17px;
  font-weight: 700;
}

.cubx-cart-page__summary-line--total .cubx-cart-page__summary-label,
.cubx-cart-page__summary-line--total .cubx-cart-page__summary-value {
  color: var(--h2j-text);
  font-weight: 700;
}

/* ── Warning montant minimum ── */
.cubx-cart-page__summary-warning {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 10px 12px;
  background: #fffbeb;
  border: 1px solid #fed7aa;
  border-radius: 4px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
  color: #9a3412;
}

.cubx-cart-page__summary-warning svg {
  flex-shrink: 0;
  margin-top: 1px;
}

/* ── Bouton checkout ── */
.cubx-cart-page__checkout-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 48px;
  padding: 0 20px;
  background: var(--cubx-accent);
  color: #fff;
  border: 0;
  border-radius: var(--cubx-radius);
  text-decoration: none;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 150ms ease, transform 150ms ease;
}

.cubx-cart-page__checkout-btn:hover:not(:disabled),
.cubx-cart-page__checkout-btn:focus:not(:disabled) {
  background: var(--cubx-accent-2);
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
}

.cubx-cart-page__checkout-btn:active:not(:disabled) {
  transform: translateY(0);
}

.cubx-cart-page__checkout-btn:disabled,
.cubx-cart-page__checkout-btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  background: var(--h2j-text-light);
}

.cubx-cart-page__checkout-btn svg {
  flex-shrink: 0;
}

/* ═══════════════════════════════════════════════════════════
   VOUCHER (accordéon)
   ═══════════════════════════════════════════════════════════ */

.cubx-cart-page__voucher {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--h2j-border);
}

/* Liste vouchers actifs */
.cubx-cart-page__voucher-list {
  list-style: none;
  padding: 0;
  margin: 0 0 4px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.cubx-cart-page__voucher-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--h2j-bg);
  border: 1px solid var(--h2j-border);
  border-radius: 4px;
  font-size: 13px;
}

.cubx-cart-page__voucher-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
  color: var(--cubx-accent);
  font-weight: 500;
}

.cubx-cart-page__voucher-tag svg {
  flex-shrink: 0;
  color: var(--cubx-accent);
}

.cubx-cart-page__voucher-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--h2j-text);
  font-weight: 500;
}

.cubx-cart-page__voucher-value {
  font-weight: 600;
  color: var(--cubx-accent);
  flex-shrink: 0;
}

.cubx-cart-page__voucher-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  color: var(--h2j-text-light);
  background: transparent;
  text-decoration: none;
  flex-shrink: 0;
  transition: background 150ms ease, color 150ms ease;
}

.cubx-cart-page__voucher-remove:hover,
.cubx-cart-page__voucher-remove:focus {
  background: #fef2f2;
  color: #dc2626;
  text-decoration: none;
}

.cubx-cart-page__voucher-remove svg {
  pointer-events: none;
}

/* Toggle accordéon "Have a promo code ?" */
.cubx-cart-page__voucher-toggle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 8px 4px;
  background: transparent;
  border: 0;
  color: var(--h2j-text);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
  transition: color 150ms ease;
}

.cubx-cart-page__voucher-toggle:hover,
.cubx-cart-page__voucher-toggle:focus {
  color: var(--cubx-accent);
}

.cubx-cart-page__voucher-toggle-icon {
  transition: transform 200ms ease;
  flex-shrink: 0;
}

.cubx-cart-page__voucher-toggle[aria-expanded="true"] .cubx-cart-page__voucher-toggle-icon {
  transform: rotate(180deg);
}

/* Form input + bouton (caché par défaut, togglé en JS) */
.cubx-cart-page__voucher-form {
  display: block;
  /* Le hidden HTML attribute fait foi pour le boot ; le JS toggle [hidden] */
}

.cubx-cart-page__voucher-form[hidden] {
  display: none;
}

.cubx-cart-page__voucher-input-group {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.cubx-cart-page__voucher-input {
  flex: 1;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--h2j-border);
  border-radius: 4px;
  background: var(--h2j-bg);
  color: var(--h2j-text);
  font-size: 13px;
  font-family: inherit;
}

.cubx-cart-page__voucher-input:focus {
  outline: 2px solid var(--cubx-accent);
  outline-offset: -1px;
  border-color: var(--cubx-accent);
}

.cubx-cart-page__voucher-submit {
  height: 36px;
  padding: 0 16px;
  background: var(--h2j-text);
  color: #fff;
  border: 0;
  border-radius: 4px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 150ms ease;
}

.cubx-cart-page__voucher-submit:hover,
.cubx-cart-page__voucher-submit:focus {
  background: var(--cubx-accent);
}

/* ── Réassurance dans la page panier (le partial cubx_reassurance.tpl est inclus
      dans cart-content.tpl, hérite des styles cubx-pp-card.cubx-pp-card--reass
      déjà définis dans theme-product.css). On ajoute juste un margin-top pour
      espacement avec le summary-card ── */
.cubx-cart-page .cubx-pp-card.cubx-pp-card--reass {
  margin-top: 8px;
}

/* ── Mobile : Summary card et voucher ── */
@media (max-width: 599px) {
  .cubx-cart-page__summary-card {
    padding: 16px;
  }

  .cubx-cart-page__checkout-btn {
    height: 52px;
    /* tactile target HIG/Material */
    font-size: 14px;
  }
}

