{
  "version": 3,
  "sources": ["/cdn/shop/t/20/assets/main-cart.js?mdsv=20260806a"],
  "sourcesContent": ["/*\n  Page panier \u2014 My Discount Solar\n  M\u00EAme m\u00E9canique que assets/cart.js : Cart AJAX API + rendu de sections bundl\u00E9\n  (la section de la page, le badge compteur et le tiroir offcanvas restent synchronis\u00E9s).\n*/\n\nclass MainCart extends HTMLElement {\n  constructor () {\n    super()\n\n    this.sectionId = this.dataset.sectionId\n    // La section est remplac\u00E9e \u00E0 chaque mise \u00E0 jour AJAX du panier : sans ce\n    // registre, chaque re-rendu laissait des \u00E9couteurs `resize` sur window\n    // pointant vers des instances d\u00E9tach\u00E9es.\n    this.windowListeners = []\n\n    // \u00AB Continuer vos achats \u00BB : retour \u00E0 la derni\u00E8re page collection/produit\n    // visit\u00E9e (m\u00E9moris\u00E9e dans styles-scripts.liquid), sinon l'accueil.\n    // R\u00E9-appliqu\u00E9 \u00E0 chaque re-rendu AJAX puisque replaceWith() reconstruit l'\u00E9l\u00E9ment.\n    const continueLink = this.querySelector('.main-cart-continue')\n    if (continueLink) {\n      try {\n        const lastShopUrl = sessionStorage.getItem('mds:continue-shopping-url')\n        if (lastShopUrl) continueLink.href = lastShopUrl\n      } catch (error) {}\n    }\n\n    this.querySelectorAll('[name=\"updates[]\"]').forEach(input => {\n      input.dataset.prevValue = input.value\n      input.addEventListener('change', () => {\n        const quantity = Number(input.value)\n\n        if (quantity <= 0) {\n          // Confirmation avant de retirer l'article du panier\n          this.confirmRemove(input)\n        } else {\n          input.dataset.prevValue = String(quantity)\n          this.change(input.dataset.lineItemKey, quantity)\n        }\n      })\n      // Entr\u00E9e dans un champ quantit\u00E9 : mettre \u00E0 jour la ligne, ne pas\n      // d\u00E9clencher la soumission implicite du formulaire (bouton paiement)\n      input.addEventListener('keydown', event => {\n        if (event.key === 'Enter') {\n          event.preventDefault()\n          input.dispatchEvent(new Event('change'))\n        }\n      })\n    })\n\n    this.querySelectorAll('.btn-line-item-remove').forEach(btn =>\n      btn.addEventListener('click', () => this.confirmRemove(btn))\n    )\n\n    this.querySelectorAll('[data-upsell-add]').forEach(btn =>\n      btn.addEventListener('click', () => this.addUpsell(btn))\n    )\n\n    // Bundles (natifs Shopify ou app Bundle Kit) : d\u00E9plier/replier les composants\n    this.querySelectorAll('[data-bundle-toggle]').forEach(btn =>\n      btn.addEventListener('click', () => this.toggleBundle(btn))\n    )\n\n    // Vignettes Bundle Kit sans handle : retrouv\u00E9es par SKU (helper d\u00E9fini\n    // dans assets/cart.js, charg\u00E9 globalement avant cette section)\n    if (window.mdsHydrateBundleImages) window.mdsHydrateBundleImages(this)\n\n    this.initUpsellCarousel()\n\n    const noteToggle = this.querySelector('[data-note-toggle]')\n    if (noteToggle) {\n      noteToggle.addEventListener('click', () => this.toggleNote(noteToggle))\n    }\n\n    const noteInput = this.querySelector('[data-cart-note]')\n    if (noteInput) {\n      noteInput.addEventListener('change', () => this.saveNote(noteInput.value))\n    }\n\n    const promoApply = this.querySelector('[data-promo-apply]')\n    if (promoApply) {\n      promoApply.addEventListener('click', () => this.applyPromo())\n      this.querySelector('[data-promo-input]').addEventListener('keydown', event => {\n        if (event.key === 'Enter') {\n          event.preventDefault()\n          this.applyPromo()\n        }\n      })\n    }\n\n    this.querySelectorAll('[data-promo-remove]').forEach(btn =>\n      btn.addEventListener('click', () => this.removePromo(btn.dataset.code))\n    )\n\n    const specialVehicle = this.querySelector('[data-special-vehicle-toggle]')\n    if (specialVehicle) {\n      specialVehicle.addEventListener('change', () => this.toggleSpecialVehicle(specialVehicle))\n    }\n\n    this.initQuote()\n\n    this.setHeaderOffset()\n    this.addWindowListener('resize', () => this.setHeaderOffset())\n  }\n\n  addWindowListener (type, handler) {\n    window.addEventListener(type, handler)\n    this.windowListeners.push([type, handler])\n  }\n\n  disconnectedCallback () {\n    this.windowListeners.forEach(([type, handler]) => window.removeEventListener(type, handler))\n    this.windowListeners = []\n  }\n\n  /*\n    Devis : instantan\u00E9 du panier stock\u00E9 en localStorage, avec r\u00E9f\u00E9rence et\n    validit\u00E9 30 jours. Le PDF s'obtient via une fen\u00EAtre d'impression ; le lien\n    e-mail pr\u00E9pare une demande adress\u00E9e \u00E0 la boutique. Si le panier change\n    (signature Liquid diff\u00E9rente), le devis m\u00E9moris\u00E9 est abandonn\u00E9.\n  */\n  initQuote () {\n    this.quoteWrap = this.querySelector('[data-quote]')\n    if (!this.quoteWrap) return\n\n    let stored = null\n    try {\n      stored = JSON.parse(localStorage.getItem('mds:cart-quote'))\n    } catch (error) {}\n\n    if (stored &&\n        (stored.signature !== this.quoteWrap.dataset.quoteSignature ||\n         Date.parse(stored.expiresAt) < Date.now())) {\n      stored = null\n      try { localStorage.removeItem('mds:cart-quote') } catch (error) {}\n      // Le panier a chang\u00E9 (ou le devis a expir\u00E9) : la r\u00E9f\u00E9rence attach\u00E9e au\n      // panier ne correspond plus \u00E0 rien et ne doit pas suivre jusqu'\u00E0 la\n      // commande. Nettoy\u00E9e ici seulement, pour ne pas appeler l'API \u00E0 chaque\n      // rendu de la page quand aucun devis n'a jamais exist\u00E9.\n      this.setQuoteCartAttribute('')\n    }\n\n    this.quote = stored\n    this.quoteAction = 'download'\n    this.renderQuote()\n\n    if (this.quote && this.quote.emailSentTo) {\n      this.showQuoteEmailStatus(`Votre demande de devis ${this.quote.ref} a \u00E9t\u00E9 transmise (${this.quote.emailSentTo}).`)\n    }\n\n    // Demande rest\u00E9e en attente apr\u00E8s un \u00E9chec r\u00E9seau : derni\u00E8re chance\n    this.flushPendingQuoteLead()\n\n    this.quoteWrap.querySelector('[data-quote-create]')\n      .addEventListener('click', () => this.createQuote())\n    this.quoteWrap.querySelector('[data-quote-cancel]')\n      .addEventListener('click', () => this.cancelQuote())\n    this.quoteWrap.querySelector('[data-quote-download]')\n      .addEventListener('click', event => {\n        event.preventDefault()\n        this.printQuote()\n      })\n    this.quoteWrap.querySelector('[data-quote-email-link]')\n      .addEventListener('click', event => {\n        event.preventDefault()\n        this.emailQuote()\n      })\n\n    const quoteForm = this.querySelector('[data-quote-form]')\n    if (quoteForm) {\n      quoteForm.addEventListener('submit', event => {\n        event.preventDefault()\n        this.submitQuoteForm(quoteForm)\n      })\n\n      // Mode de r\u00E9ception + adresse de livraison diff\u00E9rente : en retrait\n      // magasin la question de l'adresse dispara\u00EEt ; les champs cach\u00E9s sont\n      // d\u00E9sactiv\u00E9s pour \u00EAtre ignor\u00E9s par la validation et l'envoi\n      const syncDeliveryMode = () => {\n        const checked = quoteForm.querySelector('[name=\"delivery_mode\"]:checked')\n        const retrait = checked && checked.value === 'retrait'\n        const toggle = quoteForm.querySelector('[data-quote-ship-toggle]')\n        const block = quoteForm.querySelector('[data-quote-shipping]')\n\n        quoteForm.querySelector('[data-quote-ship-choice]').hidden = retrait\n        quoteForm.querySelector('[data-quote-special-vehicle-choice]').hidden = retrait\n        quoteForm.querySelector('[data-quote-pickup]').hidden = !retrait\n        const showBlock = !retrait && toggle.checked\n        block.hidden = !showBlock\n        block.querySelectorAll('input').forEach(input => {\n          input.disabled = !showBlock\n        })\n      }\n      quoteForm.querySelectorAll('[name=\"delivery_mode\"], [data-quote-ship-toggle]')\n        .forEach(input => input.addEventListener('change', syncDeliveryMode))\n    }\n  }\n\n  createQuote () {\n    let cart = null\n    try {\n      cart = JSON.parse(this.quoteWrap.querySelector('[data-quote-data]').textContent)\n    } catch (error) {}\n    if (!cart || !cart.items.length) return\n\n    const created = new Date()\n    const expires = new Date(created.getTime() + 30 * 24 * 60 * 60 * 1000)\n\n    this.quote = {\n      ref: `D-${created.getFullYear()}-${Math.floor(1000 + Math.random() * 9000)}`,\n      createdAt: created.toISOString(),\n      expiresAt: expires.toISOString(),\n      signature: this.quoteWrap.dataset.quoteSignature,\n      permalink: this.quoteWrap.dataset.quotePermalink,\n      shop: this.quoteWrap.dataset.quoteShop,\n      email: this.quoteWrap.dataset.quoteEmail,\n      cart\n    }\n    try { localStorage.setItem('mds:cart-quote', JSON.stringify(this.quote)) } catch (error) {}\n    this.setQuoteCartAttribute(this.quote.ref)\n    this.renderQuote()\n  }\n\n  cancelQuote () {\n    this.quote = null\n    try { localStorage.removeItem('mds:cart-quote') } catch (error) {}\n    this.setQuoteCartAttribute('')\n    this.renderQuote()\n  }\n\n  /*\n    R\u00E9f\u00E9rence du devis attach\u00E9e au panier : si le client finit par commander,\n    la commande la porte dans l'admin et dans l'e-mail de confirmation, ce qui\n    permet de rapprocher devis et commande. Sans effet sur la signature du\n    devis (variantes/quantit\u00E9s/total uniquement). Silencieux : un \u00E9chec ne doit\n    pas g\u00EAner la cr\u00E9ation du devis.\n  */\n  setQuoteCartAttribute (ref) {\n    fetch(`${window.Shopify.routes.cart_update_url}.js`, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ attributes: { 'R\u00E9f\u00E9rence devis': ref } })\n    }).catch(() => {})\n  }\n\n  renderQuote () {\n    this.quoteWrap.querySelector('[data-quote-request]').hidden = Boolean(this.quote)\n    const done = this.quoteWrap.querySelector('[data-quote-done]')\n    done.hidden = !this.quote\n    if (this.quote) {\n      done.querySelector('[data-quote-ref]').textContent = this.quote.ref\n    }\n  }\n\n  quoteMoney (cents) {\n    return new Intl.NumberFormat('fr-FR', {\n      style: 'currency',\n      currency: this.quote.cart.currency || 'EUR'\n    }).format(cents / 100)\n  }\n\n  quoteEscape (value) {\n    return String(value).replace(/[&<>\"']/g, c => (\n      { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[c]\n    ))\n  }\n\n  /*\n    Le PDF n'est d\u00E9livr\u00E9 qu'apr\u00E8s saisie des coordonn\u00E9es client : la modale\n    bloque le premier t\u00E9l\u00E9chargement, enregistre les informations avec le\n    devis et les transmet \u00E0 la boutique via le formulaire de contact Shopify.\n  */\n  submitQuoteForm (form) {\n    if (!form.reportValidity()) return\n    if (!this.quote) return\n\n    const fields = new FormData(form)\n    const field = key => String(fields.get(key) || '').trim()\n    this.quote.customer = {\n      firstName: field('first_name'),\n      lastName: field('last_name'),\n      name: `${field('first_name')} ${field('last_name')}`.trim(),\n      email: field('email'),\n      address: field('address'),\n      address2: field('address2'),\n      zip: field('zip'),\n      city: field('city'),\n      phone: field('phone'),\n      message: field('message'),\n      shipping: field('delivery_mode') === 'livraison' && fields.get('ship_diff')\n        ? {\n            address: field('ship_address'),\n            address2: field('ship_address2'),\n            zip: field('ship_zip'),\n            city: field('ship_city')\n          }\n        : null\n    }\n    this.quote.delivery = {\n      mode: field('delivery_mode') || 'livraison',\n      rateName: null,\n      ratePrice: null,\n      // Rue non accessible aux camions de 19 t : suppl\u00E9ment v\u00E9hicule adapt\u00E9\n      specialVehicle: field('delivery_mode') !== 'retrait' && Boolean(fields.get('special_vehicle')),\n      specialVehiclePrice: parseInt(this.quoteWrap.dataset.quoteSpecialVehiclePrice, 10) || 0\n    }\n    try { localStorage.setItem('mds:cart-quote', JSON.stringify(this.quote)) } catch (error) {}\n\n    if (this.quoteAction === 'email') {\n      this.sendQuoteByEmail()\n    } else {\n      this.downloadQuote()\n    }\n\n    const modalEl = this.querySelector('#main-cart-quote-modal')\n    if (modalEl && window.bootstrap && window.bootstrap.Modal) {\n      window.bootstrap.Modal.getOrCreateInstance(modalEl).hide()\n    }\n  }\n\n  openQuoteModal (action) {\n    const modalEl = this.querySelector('#main-cart-quote-modal')\n    if (!modalEl || !window.bootstrap || !window.bootstrap.Modal) {\n      this.showError('Impossible d\u2019ouvrir le formulaire de coordonn\u00E9es. Veuillez recharger la page.')\n      return\n    }\n\n    this.quoteAction = action\n    modalEl.querySelector('[data-quote-submit]').textContent =\n      action === 'email' ? 'Recevoir mon devis par e-mail' : 'T\u00E9l\u00E9charger mon devis'\n    window.bootstrap.Modal.getOrCreateInstance(modalEl).show()\n  }\n\n  /*\n    T\u00E9l\u00E9chargement : la fen\u00EAtre d'impression doit s'ouvrir pendant le geste\n    utilisateur, donc printQuote() d\u00E9marre en premier. La demande ne part\n    qu'ensuite, une fois les frais de port connus, pour que la boutique re\u00E7oive\n    exactement le total imprim\u00E9 sur le PDF du client. Un \u00E9chec de transmission\n    ne retient jamais le PDF, mais il est signal\u00E9.\n  */\n  async downloadQuote () {\n    await this.printQuote().catch(() => {})\n\n    try {\n      await this.ensureQuoteShipping()\n      const sent = await this.sendQuoteLead()\n      if (!sent) throw new Error('quote lead not confirmed')\n    } catch (error) {\n      this.showQuoteEmailStatus(\n        `Votre devis est pr\u00EAt, mais sa transmission \u00E0 notre \u00E9quipe a \u00E9chou\u00E9. ` +\n        `Contactez-nous en mentionnant la r\u00E9f\u00E9rence ${this.quote.ref}.`,\n        true\n      )\n    }\n  }\n\n  /*\n    \u00AB Recevoir par e-mail \u00BB ne fait PAS partir le devis vers le client : le\n    th\u00E8me n'a aucun moyen d'envoyer un e-mail avec pi\u00E8ce jointe. La demande est\n    transmise \u00E0 la boutique avec le marqueur `contact[Demande]`, et l'\u00E9quipe\n    r\u00E9pond au client (le reply-to du message est d\u00E9j\u00E0 son adresse). Le message\n    affich\u00E9 doit donc rester une promesse de traitement, pas d'envoi imm\u00E9diat.\n  */\n  async sendQuoteByEmail () {\n    const q = this.quote\n    if (!q || !q.customer) return\n\n    this.showQuoteEmailStatus('Transmission de votre demande en cours\u2026')\n    try {\n      await this.ensureQuoteShipping()\n      const sent = await this.sendQuoteLead(true)\n      if (!sent) throw new Error('quote email request failed')\n\n      q.emailSentTo = q.customer.email\n      try { localStorage.setItem('mds:cart-quote', JSON.stringify(q)) } catch (error) {}\n      this.showQuoteEmailStatus(\n        `Votre demande de devis ${q.ref} a bien \u00E9t\u00E9 transmise. ` +\n        `Vous le recevrez \u00E0 ${q.customer.email} sous 24 h ouvr\u00E9es.`\n      )\n    } catch (error) {\n      this.showQuoteEmailStatus('L\u2019envoi a \u00E9chou\u00E9. Veuillez r\u00E9essayer dans un instant.', true)\n    }\n  }\n\n  showQuoteEmailStatus (message, isError) {\n    const status = this.quoteWrap.querySelector('[data-quote-email-status]')\n    if (!status) return\n\n    status.textContent = message\n    status.hidden = false\n    status.classList.toggle('is-error', Boolean(isError))\n  }\n\n  /*\n    Totaux du devis \u2014 source unique pour le PDF remis au client ET pour la\n    demande transmise \u00E0 la boutique. Les deux divergeaient : le lead annon\u00E7ait\n    le sous-total du panier, sans port ni v\u00E9hicule adapt\u00E9, quand le PDF\n    affichait le total r\u00E9el.\n  */\n  quoteTotals () {\n    const q = this.quote\n    const delivery = q.delivery || { mode: 'livraison', rateName: null, ratePrice: null }\n    let grandTotal = q.cart.total\n    let deliveryLabel\n    let deliveryRowLabel\n    let deliveryAmount\n    let shippingFootnote\n\n    if (delivery.mode === 'retrait') {\n      deliveryLabel = 'Retrait en magasin'\n      deliveryRowLabel = 'Retrait en magasin'\n      deliveryAmount = 'Offert'\n      shippingFootnote = 'Retrait en magasin \u2014 aucun frais de livraison.'\n    } else if (delivery.ratePrice !== null && delivery.ratePrice !== undefined) {\n      const rateName = delivery.rateName && delivery.rateName !== 'Livraison \u00E0 domicile'\n        ? ` \u2014 ${delivery.rateName}`\n        : ''\n      deliveryRowLabel = `Livraison \u00E0 domicile${rateName}`\n      if (delivery.ratePrice === 0) {\n        deliveryLabel = 'Livraison \u00E0 domicile \u2014 offerte'\n        deliveryAmount = 'Offerte'\n        shippingFootnote = 'Livraison offerte.'\n      } else {\n        deliveryLabel = `Livraison \u00E0 domicile \u2014 frais estim\u00E9s ${this.quoteMoney(delivery.ratePrice)}${rateName}`\n        deliveryAmount = this.quoteMoney(delivery.ratePrice)\n        shippingFootnote = 'Frais de livraison inclus.'\n      }\n      grandTotal += delivery.ratePrice\n    } else {\n      deliveryLabel = 'Livraison \u00E0 domicile \u2014 frais \u00E0 confirmer'\n      deliveryRowLabel = 'Livraison \u00E0 domicile'\n      deliveryAmount = 'Communiqu\u00E9s \u00E0 la confirmation'\n      shippingFootnote = 'Frais de livraison communiqu\u00E9s \u00E0 la confirmation de commande.'\n    }\n\n    let specialVehiclePrice = 0\n    if (delivery.mode !== 'retrait' && delivery.specialVehicle && delivery.specialVehiclePrice > 0) {\n      specialVehiclePrice = delivery.specialVehiclePrice\n      grandTotal += specialVehiclePrice\n    }\n\n    return {\n      // `ecoTotal` est d\u00E9j\u00E0 compris dans les prix : information, pas addition\n      discount: q.cart.discount || 0,\n      ecoTotal: q.cart.ecoTotal || 0,\n      deliveryLabel,\n      deliveryRowLabel,\n      deliveryAmount,\n      shippingFootnote,\n      specialVehiclePrice,\n      grandTotal\n    }\n  }\n\n  /*\n    La demande part vers la boutique via le formulaire de contact Shopify\n    natif : l'e-mail arrive sur l'adresse de notification de la boutique avec\n    le client en reply-to (r\u00E9pondre = relancer en un clic). Aucun service tiers.\n\n    Les champs `contact[Libell\u00E9]` s'affichent tels quels dans l'e-mail re\u00E7u ; le\n    corps porte le d\u00E9tail. Sa premi\u00E8re ligne est un marqueur\n    `=== DEVIS <ref> ===` : le sujet de l'e-mail n'\u00E9tant pas param\u00E9trable depuis\n    le th\u00E8me, c'est sur lui que se r\u00E8gle le filtre de la bo\u00EEte de r\u00E9ception.\n  */\n  buildQuoteLeadFields (emailRequested) {\n    const q = this.quote\n    const totals = this.quoteTotals()\n    const dateFr = iso => new Date(iso).toLocaleDateString('fr-FR')\n\n    const lines = []\n    q.cart.items.forEach(item => {\n      lines.push(`- ${item.qty} x ${item.title} : ${this.quoteMoney(item.line)}`)\n      if (item.variant && item.variant !== 'Default Title') lines.push(`    ${item.variant}`)\n      if (item.sku) lines.push(`    R\u00E9f. ${item.sku}`)\n      // Configuration choisie et composants du kit : sans eux, impossible de\n      // savoir ce que le client a r\u00E9ellement configur\u00E9.\n      if (item.options && item.options.length) lines.push(`    Options : ${item.options.join(' | ')}`)\n      if (item.components && item.components.length) lines.push(`    Contenu : ${item.components.join(' / ')}`)\n      if (item.flash) lines.push('    Vente flash')\n    })\n\n    const totalLines = []\n    if (totals.ecoTotal > 0) {\n      totalLines.push(`Dont \u00E9co-participation DEEE : ${this.quoteMoney(totals.ecoTotal)}`)\n    }\n    if (totals.discount > 0) {\n      totalLines.push(`Remise : -${this.quoteMoney(totals.discount)}`)\n    }\n    totalLines.push(totals.deliveryLabel)\n    if (totals.specialVehiclePrice > 0) {\n      totalLines.push(`Livraison par v\u00E9hicule adapt\u00E9 : ${this.quoteMoney(totals.specialVehiclePrice)}`)\n    }\n    totalLines.push(`Total TTC : ${this.quoteMoney(totals.grandTotal)}`)\n\n    const body = [\n      `=== DEVIS ${q.ref} ===`,\n      `Cr\u00E9\u00E9 le ${dateFr(q.createdAt)}, valable jusqu'au ${dateFr(q.expiresAt)}.`,\n      '',\n      ...lines,\n      '',\n      ...totalLines,\n      '',\n      `Panier du client : ${q.permalink}`\n    ].join('\\n')\n\n    const fullAddress = [q.customer.address, q.customer.address2, `${q.customer.zip} ${q.customer.city}`]\n      .filter(Boolean).join(', ')\n\n    // `form_type` et `utf8` sont d\u00E9j\u00E0 rendus par le {% form 'contact' %}\n    const fields = {\n      'contact[email]': q.customer.email,\n      'contact[Nom complet]': q.customer.name,\n      'contact[T\u00E9l\u00E9phone]': q.customer.phone,\n      'contact[Adresse]': fullAddress,\n      'contact[R\u00E9f\u00E9rence devis]': q.ref,\n      'contact[Mode de r\u00E9ception]': totals.deliveryLabel\n    }\n    if (totals.specialVehiclePrice > 0) {\n      fields['contact[V\u00E9hicule adapt\u00E9]'] =\n        `Rue non accessible aux camions de 19 t \u2014 suppl\u00E9ment v\u00E9hicule adapt\u00E9 accept\u00E9 : ${this.quoteMoney(totals.specialVehiclePrice)}`\n    }\n    if (q.customer.shipping) {\n      fields['contact[Adresse de livraison]'] = [q.customer.shipping.address, q.customer.shipping.address2,\n        `${q.customer.shipping.zip} ${q.customer.shipping.city}`].filter(Boolean).join(', ')\n    }\n    if (q.customer.message) {\n      fields['contact[Message du client]'] = q.customer.message\n    }\n    const adminCustomerUrl = this.quoteWrap.dataset.quoteAdminCustomerUrl\n    if (adminCustomerUrl) {\n      fields['contact[Fiche client]'] = adminCustomerUrl\n    }\n    if (emailRequested) {\n      fields['contact[Demande]'] = 'ENVOYER LE DEVIS PAR E-MAIL AU CLIENT'\n    }\n    fields['contact[body]'] = body\n\n    return fields\n  }\n\n  /*\n    Envoi ET accus\u00E9 de r\u00E9ception : l'ancienne version ne regardait jamais la\n    r\u00E9ponse, si bien qu'un rejet (mur anti-robot, 429, panne) passait pour un\n    envoi r\u00E9ussi \u2014 le devis \u00E9tait perdu sans que personne ne le sache. Tant que\n    l'envoi n'est pas constat\u00E9, la demande reste en file pour un rejeu.\n  */\n  async sendQuoteLead (emailRequested) {\n    const q = this.quote\n    if (!q || !q.customer) return false\n\n    const fields = this.buildQuoteLeadFields(emailRequested)\n    this.storePendingQuoteLead(fields)\n\n    const sent = await this.postQuoteLead(fields)\n    if (sent) this.storePendingQuoteLead(null)\n    return sent\n  }\n\n  /*\n    \u26A0\uFE0F NE PAS repasser en `fetch('/contact')` : le formulaire de contact est\n    prot\u00E9g\u00E9 par le captcha Shopify, qui ne signe qu'un vrai formulaire soumis\n    nativement. Toute requ\u00EAte construite en JavaScript est rejet\u00E9e en\n    400 \u00AB Missing CAPTCHA token \u00BB \u2014 quel que soit l'encodage (multipart ou\n    urlencod\u00E9) et le jeu de champs. C'est ce qui emp\u00EAchait, depuis l'origine,\n    tout devis d'arriver \u00E0 la boutique.\n\n    On remplit donc le {% form 'contact' %} cach\u00E9 rendu par main-cart.liquid et\n    on le soumet vers son iframe : la page panier n'est pas quitt\u00E9e.\n    `requestSubmit()` est indispensable \u2014 `submit()` n'\u00E9met pas l'\u00E9v\u00E9nement\n    submit que le hook captcha intercepte, et la soumission serait rejet\u00E9e.\n\n    Succ\u00E8s : l'iframe atterrit sur `?contact_posted=true` (le param\u00E8tre qui\n    rend `form.posted_successfully?` vrai c\u00F4t\u00E9 Shopify). Une iframe qui charge\n    autre chose (page d'erreur 400) ou qui ne charge pas du tout = \u00E9chec.\n  */\n  postQuoteLead (fields) {\n    // Cibl\u00E9 par id : {% form 'contact' %} n'accepte pas d'attribut data-*\n    const form = this.querySelector('#mds-quote-lead-form')\n    const frame = this.querySelector('[data-quote-lead-frame]')\n    if (!form || !frame) return Promise.resolve(false)\n\n    // Champs vides d\u00E9sactiv\u00E9s : non soumis, donc absents de l'e-mail re\u00E7u\n    form.querySelectorAll('[data-quote-lead-field]').forEach(input => {\n      const value = fields[input.name]\n      input.value = value || ''\n      input.disabled = !value\n    })\n\n    return new Promise(resolve => {\n      let settled = false\n      const finish = result => {\n        if (settled) return\n        settled = true\n        clearTimeout(timer)\n        frame.removeEventListener('load', onLoad)\n        resolve(result)\n      }\n      const onLoad = () => {\n        // M\u00EAme origine que la boutique : l'URL d'arriv\u00E9e est lisible\n        let href = ''\n        try { href = frame.contentWindow.location.href } catch (error) {}\n        finish(href.includes('contact_posted=true'))\n      }\n      const timer = setTimeout(() => finish(false), 20000)\n\n      frame.addEventListener('load', onLoad)\n      try {\n        // Garde-fou : sans cible, la soumission ferait quitter la page panier\n        // au client (et lui ferait perdre son devis \u00E0 l'\u00E9cran)\n        form.target = frame.getAttribute('name')\n        form.requestSubmit()\n      } catch (error) {\n        finish(false)\n      }\n    })\n  }\n\n  storePendingQuoteLead (fields) {\n    try {\n      if (fields) {\n        localStorage.setItem('mds:cart-quote-lead-pending',\n          JSON.stringify({ fields, at: Date.now() }))\n      } else {\n        localStorage.removeItem('mds:cart-quote-lead-pending')\n      }\n    } catch (error) {}\n  }\n\n  /*\n    Rejeu d'une demande jamais confirm\u00E9e : un seul essai, et la file est vid\u00E9e\n    avant l'envoi quel qu'en soit le r\u00E9sultat \u2014 elle ne doit pas devenir une\n    source d'envois r\u00E9p\u00E9t\u00E9s \u00E0 chaque visite. Le d\u00E9lai de garde \u00E9vite de rejouer\n    une demande encore en vol quand la section est re-rendue en AJAX.\n    Compromis assum\u00E9 : mieux vaut un doublon rare qu'un devis jamais re\u00E7u.\n  */\n  flushPendingQuoteLead () {\n    let pending = null\n    try {\n      pending = JSON.parse(localStorage.getItem('mds:cart-quote-lead-pending'))\n    } catch (error) {}\n\n    if (!pending || !pending.fields) return\n    if (Date.now() - (pending.at || 0) < 30000) return\n\n    this.storePendingQuoteLead(null)\n    this.postQuoteLead(pending.fields)\n  }\n\n  async printQuote () {\n    const q = this.quote\n    if (!q) return\n\n    if (!q.customer) {\n      this.openQuoteModal('download')\n      return\n    }\n\n    // La fen\u00EAtre doit s'ouvrir pendant le geste utilisateur (sinon le\n    // navigateur la bloque) ; le devis y est \u00E9crit une fois les frais connus\n    const win = window.open('', '_blank')\n    if (!win) {\n      this.showError(\"Autorisez l'ouverture de fen\u00EAtres pour t\u00E9l\u00E9charger le devis.\")\n      return\n    }\n    win.document.write('<!doctype html><html lang=\"fr\"><body style=\"font-family:Poppins,system-ui,sans-serif;color:#14522F;padding:40px;\">Pr\u00E9paration de votre devis\u2026</body></html>')\n    win.document.close()\n\n    await this.ensureQuoteShipping()\n\n    const html = this.buildQuoteHtml()\n    win.document.open()\n    win.document.write(html)\n    win.document.close()\n  }\n\n  /*\n    Frais de livraison r\u00E9els calcul\u00E9s par Shopify pour le panier en cours\n    (tarifs configur\u00E9s dans l'admin), d'apr\u00E8s le code postal de livraison.\n    L'API r\u00E9pond 202 tant que le calcul est en cours. \u00C9chec non bloquant :\n    le devis indique alors \u00AB communiqu\u00E9s \u00E0 la confirmation \u00BB.\n  */\n  async ensureQuoteShipping () {\n    const q = this.quote\n    if (!q.delivery) {\n      q.delivery = { mode: 'livraison', rateName: null, ratePrice: null }\n    }\n    if (q.delivery.mode !== 'livraison' || q.delivery.ratePrice !== null) return\n\n    try {\n      const zip = (q.customer.shipping && q.customer.shipping.zip) || q.customer.zip\n      const params = new URLSearchParams({\n        'shipping_address[zip]': zip,\n        'shipping_address[country]': 'France'\n      })\n\n      for (let attempt = 0; attempt < 4; attempt++) {\n        const response = await fetch(`/cart/shipping_rates.json?${params}`)\n        if (response.status === 200) {\n          const rates = (await response.json()).shipping_rates || []\n          if (!rates.length) return\n          const cheapest = rates.reduce((a, b) =>\n            parseFloat(a.price) <= parseFloat(b.price) ? a : b\n          )\n          q.delivery.rateName = cheapest.name\n          q.delivery.ratePrice = Math.round(parseFloat(cheapest.price) * 100)\n          try { localStorage.setItem('mds:cart-quote', JSON.stringify(q)) } catch (error) {}\n          return\n        }\n        if (response.status !== 202) return\n        await new Promise(resolve => setTimeout(resolve, 1000))\n      }\n    } catch (error) {}\n  }\n\n  buildQuoteHtml () {\n    const q = this.quote\n    const dateFr = iso => new Date(iso).toLocaleDateString('fr-FR')\n    const rows = q.cart.items.map(item => {\n      let details = this.quoteEscape(item.title)\n      if (item.variant && item.variant !== 'Default Title') {\n        details += `<br><small>${this.quoteEscape(item.variant)}</small>`\n      }\n      if (item.sku) {\n        details += `<br><small>R\u00E9f. ${this.quoteEscape(item.sku)}</small>`\n      }\n      // Configuration choisie et composants du kit : le devis serait\n      // inexploitable sans le d\u00E9tail de ce que le client a assembl\u00E9.\n      if (item.options && item.options.length) {\n        details += `<br><small>${item.options.map(option => this.quoteEscape(option)).join('<br>')}</small>`\n      }\n      if (item.components && item.components.length) {\n        details += `<br><small>Contenu : ${item.components.map(component => this.quoteEscape(component)).join(' &middot; ')}</small>`\n      }\n      if (item.flash) {\n        details += '<br><span class=\"flash\">\u26A1 Vente flash</span>'\n      }\n      return `<tr>\n        <td>${details}</td>\n        <td class=\"num\">${item.qty}</td>\n        <td class=\"num\">${this.quoteMoney(item.unit)}</td>\n        <td class=\"num\">${this.quoteMoney(item.line)}</td>\n      </tr>`\n    }).join('')\n\n    // M\u00EAmes totaux que la demande envoy\u00E9e \u00E0 la boutique (cf. quoteTotals)\n    const totals = this.quoteTotals()\n    const delivery = q.delivery || { mode: 'livraison', rateName: null, ratePrice: null }\n    const grandTotal = totals.grandTotal\n    const shippingFootnote = totals.shippingFootnote\n\n    /*\n      Un tarif de campagne ne tient que le temps de l'op\u00E9ration : le devis ne\n      peut pas le garantir sur ses 30 jours de validit\u00E9, contrairement au reste\n      du panier. La r\u00E9serve est donc port\u00E9e en pied de page, et la mention\n      \u00AB prix TTC bloqu\u00E9s \u00BB de l'en-t\u00EAte est nuanc\u00E9e en cons\u00E9quence.\n    */\n    const hasFlash = q.cart.items.some(item => item.flash)\n    const flashFootnote = hasFlash\n      ? `<p class=\"flash-note\">\u26A1 Les articles signal\u00E9s \u00AB Vente flash \u00BB b\u00E9n\u00E9ficient d'un tarif promotionnel limit\u00E9 \u00E0 la dur\u00E9e de l'op\u00E9ration : ce prix n'est pas bloqu\u00E9 jusqu'au ${dateFr(q.expiresAt)} et s'applique dans la limite des stocks disponibles.</p>`\n      : ''\n\n    const discountRow = totals.discount > 0\n      ? `<tr class=\"total-row\"><td colspan=\"3\">Remise</td><td class=\"num\">&minus;${this.quoteMoney(totals.discount)}</td></tr>`\n      : ''\n    // D\u00E9j\u00E0 comprise dans les prix affich\u00E9s : mention, jamais additionn\u00E9e\n    const ecoRow = totals.ecoTotal > 0\n      ? `<tr class=\"total-row\"><td colspan=\"3\"><small>Dont \u00E9co-participation DEEE (incluse dans les prix)</small></td><td class=\"num\"><small>${this.quoteMoney(totals.ecoTotal)}</small></td></tr>`\n      : ''\n    const deliveryRow = `<tr class=\"total-row\"><td colspan=\"3\">${this.quoteEscape(totals.deliveryRowLabel)}</td><td class=\"num\">${totals.deliveryAmount}</td></tr>`\n    const specialVehicleRow = totals.specialVehiclePrice > 0\n      ? `<tr class=\"total-row\"><td colspan=\"3\">Livraison par v\u00E9hicule adapt\u00E9<br><small>Rue non accessible aux camions de 19 tonnes \u2014 service accept\u00E9 par le client.</small></td><td class=\"num\">${this.quoteMoney(totals.specialVehiclePrice)}</td></tr>`\n      : ''\n    const noteBlock = q.cart.note\n      ? `<p class=\"note\"><strong>Note :</strong> ${this.quoteEscape(q.cart.note)}</p>`\n      : ''\n    const c = q.customer\n    let shippingBlock\n    if (delivery.mode === 'retrait') {\n      const wrap = this.quoteWrap.dataset\n      shippingBlock = `\n      <div class=\"client\">\n        <div class=\"client-label\">Retrait en magasin</div>\n        <strong>${this.quoteEscape(wrap.quotePickupName)}</strong><br>\n        ${this.quoteEscape(wrap.quotePickupAddress1)}<br>\n        ${this.quoteEscape(wrap.quotePickupAddress2)}\n      </div>`\n    } else {\n      // Sans adresse de livraison distincte, la livraison reprend la facturation\n      const ship = c.shipping || c\n      shippingBlock = `\n      <div class=\"client\">\n        <div class=\"client-label\">Client \u2014 livraison</div>\n        <strong>${this.quoteEscape(c.name)}</strong><br>\n        ${this.quoteEscape(ship.address)}<br>\n        ${ship.address2 ? `${this.quoteEscape(ship.address2)}<br>` : ''}\n        ${this.quoteEscape(ship.zip)} ${this.quoteEscape(ship.city)}\n      </div>`\n    }\n    const customerBlock = `\n      <div class=\"clients\">\n        <div class=\"client\">\n          <div class=\"client-label\">Client \u2014 facturation</div>\n          <strong>${this.quoteEscape(c.name)}</strong><br>\n          ${this.quoteEscape(c.address)}<br>\n          ${c.address2 ? `${this.quoteEscape(c.address2)}<br>` : ''}\n          ${this.quoteEscape(c.zip)} ${this.quoteEscape(c.city)}<br>\n          ${this.quoteEscape(c.email)}<br>\n          ${this.quoteEscape(c.phone)}\n        </div>${shippingBlock}\n      </div>`\n\n    const html = `<!doctype html>\n<html lang=\"fr\">\n<head>\n<meta charset=\"utf-8\">\n<title>Devis ${this.quoteEscape(q.ref)} \u2014 ${this.quoteEscape(q.shop)}</title>\n<style>\n  body { font-family: Poppins, system-ui, sans-serif; color: #14522F; margin: 40px; font-size: 14px; }\n  header { display: flex; justify-content: space-between; align-items: flex-start; border-bottom: 3px solid #1E7A46; padding-bottom: 16px; }\n  h1 { font-size: 26px; margin: 0; color: #1E7A46; }\n  .shop { font-size: 18px; font-weight: 700; }\n  .meta { margin: 18px 0 26px; line-height: 1.7; }\n  table { width: 100%; border-collapse: collapse; }\n  th { text-align: left; background: #f0f8f2; padding: 8px 10px; border-bottom: 2px solid #1E7A46; }\n  td { padding: 8px 10px; border-bottom: 1px solid #e1e4e8; vertical-align: top; }\n  .num { text-align: right; white-space: nowrap; }\n  th.num { text-align: right; }\n  small { color: #6c757d; }\n  /* Pastille contourn\u00E9e (pas de fond) : lisible m\u00EAme quand l'impression des\n     arri\u00E8re-plans est d\u00E9sactiv\u00E9e, ce qui est le r\u00E9glage par d\u00E9faut. */\n  .flash { display: inline-block; margin-top: 4px; padding: 1px 8px; border: 1px solid #C0392B; border-radius: 999px; color: #C0392B; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }\n  .total-row td { border-bottom: 0; font-size: 15px; }\n  .grand td { font-weight: 700; font-size: 17px; border-top: 2px solid #1E7A46; }\n  .note { margin-top: 18px; }\n  .payment { margin-top: 26px; padding: 12px 16px; background: #f0f8f2; border: 1px solid rgba(20, 82, 47, 0.1); line-height: 1.7; }\n  .clients { display: flex; align-items: stretch; gap: 12px; margin: 0 0 26px; }\n  .client { flex: 1; padding: 12px 16px; background: #f0f8f2; border: 1px solid rgba(20, 82, 47, 0.1); line-height: 1.6; }\n  .client-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: #6c757d; margin-bottom: 4px; }\n  footer { margin-top: 36px; padding-top: 14px; border-top: 1px solid #e1e4e8; font-size: 12px; color: #6c757d; line-height: 1.7; }\n  footer a { color: #1E7A46; word-break: break-all; }\n  .flash-note { margin: 0 0 10px; padding-left: 10px; border-left: 2px solid #C0392B; color: #C0392B; }\n  /*\n    Impression multi-pages : les totaux ne sont volontairement PAS dans un\n    <tfoot> (un pied de tableau est r\u00E9p\u00E9t\u00E9 par le navigateur sur chaque page).\n    Ils forment un second <tbody> gard\u00E9 d'un seul tenant en fin de tableau.\n  */\n  tbody.totals, tr, .clients, .payment, footer { break-inside: avoid; page-break-inside: avoid; }\n  @media print { body { margin: 12mm; } }\n</style>\n</head>\n<body>\n  <header>\n    <div class=\"shop\">${this.quoteEscape(q.shop)}</div>\n    <div>\n      <h1>DEVIS</h1>\n      <div>R\u00E9f\u00E9rence ${this.quoteEscape(q.ref)}</div>\n    </div>\n  </header>\n  <p class=\"meta\">\n    Date d'\u00E9mission : <strong>${dateFr(q.createdAt)}</strong><br>\n    Valable jusqu'au : <strong>${dateFr(q.expiresAt)}</strong> \u2014 prix TTC bloqu\u00E9s${hasFlash ? ', hors articles en vente flash' : ''}.\n  </p>\n  ${customerBlock}\n  <table>\n    <thead>\n      <tr><th>Article</th><th class=\"num\">Qt\u00E9</th><th class=\"num\">Prix unitaire TTC</th><th class=\"num\">Total TTC</th></tr>\n    </thead>\n    <tbody>${rows}</tbody>\n    <tbody class=\"totals\">\n      ${ecoRow}\n      ${discountRow}\n      ${deliveryRow}\n      ${specialVehicleRow}\n      <tr class=\"total-row grand\"><td colspan=\"3\">Total TTC</td><td class=\"num\">${this.quoteMoney(grandTotal)}</td></tr>\n    </tbody>\n  </table>\n  ${noteBlock}\n  <div class=\"payment\">\n    <div class=\"client-label\">Moyen de paiement pour passer commande \u2014 virement bancaire</div>\n    Titulaire du compte : <strong>${this.quoteEscape(this.quoteWrap.dataset.quoteBankHolder)}</strong><br>\n    \u00C9tablissement : ${this.quoteEscape(this.quoteWrap.dataset.quoteBankName)}<br>\n    IBAN : <strong>${this.quoteEscape(this.quoteWrap.dataset.quoteBankIban)}</strong><br>\n    BIC : ${this.quoteEscape(this.quoteWrap.dataset.quoteBankBic)}\n  </div>\n  <footer>\n    ${flashFootnote}\n    ${shippingFootnote}<br>\n    Pour commander aux prix de ce devis avant le ${dateFr(q.expiresAt)}, retrouvez votre panier :\n    <a href=\"${this.quoteEscape(q.permalink)}\">${this.quoteEscape(q.permalink)}</a><br>\n    ou contactez-nous en mentionnant la r\u00E9f\u00E9rence ${this.quoteEscape(q.ref)} : ${this.quoteEscape(q.email)}\n  </footer>\n  <script>window.print()<\\/script>\n</body>\n</html>`\n\n    return html\n  }\n\n  emailQuote () {\n    const q = this.quote\n    if (!q) return\n\n    if (!q.customer) {\n      this.openQuoteModal('email')\n      return\n    }\n    this.sendQuoteByEmail()\n  }\n\n  /*\n    Carrousels des ventes additionnelles (\u00AB Compl\u00E9tez votre installation \u00BB et\n    \u00AB Nos clients ach\u00E8tent \u00E9galement \u00BB) : les fl\u00E8ches font d\u00E9filer la piste\n    d'une \u00AB page \u00BB (largeur visible) et se d\u00E9sactivent en but\u00E9e. Quand toutes\n    les cartes tiennent dans la piste, elles sont masqu\u00E9es (is-static).\n  */\n  initUpsellCarousel () {\n    this.querySelectorAll('[data-upsell-carousel]').forEach(carousel => {\n      const track = carousel.querySelector('[data-upsell-track]')\n      const prev = carousel.querySelector('[data-upsell-prev]')\n      const next = carousel.querySelector('[data-upsell-next]')\n\n      const update = () => {\n        const maxScroll = track.scrollWidth - track.clientWidth\n        carousel.classList.toggle('is-static', maxScroll <= 2)\n        prev.disabled = track.scrollLeft <= 2\n        next.disabled = track.scrollLeft >= maxScroll - 2\n      }\n\n      prev.addEventListener('click', () =>\n        track.scrollBy({ left: -track.clientWidth, behavior: 'smooth' })\n      )\n      next.addEventListener('click', () =>\n        track.scrollBy({ left: track.clientWidth, behavior: 'smooth' })\n      )\n      track.addEventListener('scroll', update, { passive: true })\n      this.addWindowListener('resize', update)\n\n      // Apr\u00E8s un re-rendu AJAX, le constructeur s'ex\u00E9cute pendant l'insertion\n      // dans le DOM : les dimensions ne sont mesurables qu'\u00E0 la frame suivante\n      requestAnimationFrame(update)\n    })\n  }\n\n  get sectionsToRender () {\n    return [this.sectionId, 'cart-count-badge', 'offcanvas-cart']\n  }\n\n  setHeaderOffset () {\n    const header = document.getElementById('header-group')\n\n    if (header) {\n      this.style.setProperty('--mds-header-offset', `${header.offsetHeight}px`)\n    }\n  }\n\n  // `trigger` : champ quantit\u00E9 pass\u00E9 \u00E0 0 ou bouton de suppression de la ligne.\n  // \u00C0 l'annulation, seul le champ quantit\u00E9 doit \u00EAtre restaur\u00E9 \u00E0 sa valeur.\n  confirmRemove (trigger) {\n    const message = '\u00CAtes-vous s\u00FBr de vouloir supprimer ce produit de votre panier ?'\n    const modalEl = this.querySelector('#main-cart-remove-modal')\n    const isQtyInput = trigger.matches('[name=\"updates[]\"]')\n    const restore = () => {\n      if (isQtyInput) trigger.value = trigger.dataset.prevValue || '1'\n    }\n\n    if (!modalEl || !window.bootstrap || !window.bootstrap.Modal) {\n      // Repli : confirmation native du navigateur\n      if (window.confirm(message)) {\n        this.change(trigger.dataset.lineItemKey, 0)\n      } else {\n        restore()\n      }\n      return\n    }\n\n    const item = trigger.closest('.main-cart-item')\n    const titleEl = item && item.querySelector('.main-cart-item-title')\n    modalEl.querySelector('[data-remove-product-name]').textContent =\n      titleEl ? titleEl.textContent.trim() : ''\n\n    const modal = window.bootstrap.Modal.getOrCreateInstance(modalEl)\n    let confirmed = false\n\n    modalEl.querySelector('[data-remove-confirm]').onclick = () => {\n      confirmed = true\n      modal.hide()\n    }\n\n    // On attend la fermeture compl\u00E8te (backdrop retir\u00E9) avant d'agir\n    modalEl.addEventListener('hidden.bs.modal', () => {\n      if (confirmed) {\n        this.change(trigger.dataset.lineItemKey, 0)\n      } else {\n        restore()\n      }\n    }, { once: true })\n\n    modal.show()\n  }\n\n  async change (key, quantity) {\n    this.classList.add('loading')\n\n    try {\n      const response = await fetch(`${window.Shopify.routes.cart_change_url}.js`, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({\n          id: key,\n          quantity,\n          sections: this.sectionsToRender,\n          sections_url: window.Shopify.routes.cart_url\n        })\n      })\n      const data = await response.json()\n\n      if (response.ok) {\n        window.dispatchEvent(new CustomEvent('kt.cart.changed', { detail: data }))\n        this.reloadSections(data.sections)\n      } else {\n        this.showError(data.description || data.message)\n      }\n    } catch (error) {\n      this.showError()\n    }\n\n    this.classList.remove('loading')\n  }\n\n  async addUpsell (btn) {\n    btn.disabled = true\n    this.classList.add('loading')\n\n    try {\n      const response = await fetch(`${window.Shopify.routes.cart_add_url}.js`, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({\n          items: [{ id: Number(btn.dataset.variantId), quantity: 1 }],\n          sections: this.sectionsToRender,\n          sections_url: window.Shopify.routes.cart_url\n        })\n      })\n      const data = await response.json()\n\n      if (response.ok) {\n        window.dispatchEvent(new CustomEvent('kt.cart.added', { detail: data }))\n        this.reloadSections(data.sections)\n      } else {\n        this.showError(data.description || data.message)\n        btn.disabled = false\n      }\n    } catch (error) {\n      this.showError()\n      btn.disabled = false\n    }\n\n    this.classList.remove('loading')\n  }\n\n  /*\n    Livraison par v\u00E9hicule adapt\u00E9 (rue non accessible aux camions de 19 t) :\n    la case \u00E0 cocher ajoute/retire le produit-service du panier. Le total du\n    r\u00E9capitulatif int\u00E8gre alors les 299 \u20AC et le montant est r\u00E9ellement encaiss\u00E9\n    au paiement (un simple ajustement d'affichage du total ne serait pas repris\n    par le checkout Shopify). Apr\u00E8s re-rendu de la section, la case refl\u00E8te\n    l'\u00E9tat r\u00E9el du panier : inutile de la r\u00E9activer c\u00F4t\u00E9 succ\u00E8s (l'\u00E9l\u00E9ment est\n    remplac\u00E9) ; en cas d'\u00E9chec on r\u00E9tablit son \u00E9tat.\n  */\n  async toggleSpecialVehicle (checkbox) {\n    const variantId = Number(checkbox.dataset.variantId)\n    const lineKey = checkbox.dataset.lineKey\n    const shouldAdd = checkbox.checked\n\n    // Ajout : id de variante (add.js). Retrait : cl\u00E9 de ligne \u00AB id:hash \u00BB\n    // (change.js refuse l'id de variante nu \u2014 cf. la m\u00E9thode change()).\n    if (shouldAdd && !variantId) return\n    if (!shouldAdd && !lineKey) return\n\n    checkbox.disabled = true\n    this.classList.add('loading')\n\n    // R\u00E9tablit l'\u00E9tat de la case et affiche l'erreur (aucune ligne n'a boug\u00E9)\n    const revert = message => {\n      checkbox.checked = !shouldAdd\n      checkbox.disabled = false\n      this.showError(message)\n      this.classList.remove('loading')\n    }\n\n    try {\n      const endpoint = shouldAdd\n        ? `${window.Shopify.routes.cart_add_url}.js`\n        : `${window.Shopify.routes.cart_change_url}.js`\n      const payload = shouldAdd\n        ? { items: [{ id: variantId, quantity: 1 }] }\n        : { id: lineKey, quantity: 0 }\n      payload.sections = this.sectionsToRender\n      payload.sections_url = window.Shopify.routes.cart_url\n\n      const response = await fetch(endpoint, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json', Accept: 'application/json' },\n        body: JSON.stringify(payload)\n      })\n\n      // La r\u00E9ponse peut \u00EAtre une page HTML (d\u00E9fi anti-robot \u00AB connexion \u00E0\n      // v\u00E9rifier \u00BB, 404, 5xx\u2026) : on lit le texte d'abord pour r\u00E9v\u00E9ler la vraie\n      // cause au lieu du g\u00E9n\u00E9rique \u00AB Une erreur est survenue \u00BB.\n      const raw = await response.text()\n      let data = null\n      try {\n        data = JSON.parse(raw)\n      } catch (parseError) {\n        console.error('MDS panier \u2014 v\u00E9hicule adapt\u00E9 : r\u00E9ponse non-JSON', endpoint, response.status, raw.slice(0, 300))\n        revert(`Ajout impossible (r\u00E9ponse inattendue du serveur, HTTP ${response.status}). R\u00E9essayez dans un instant.`)\n        return\n      }\n\n      if (!response.ok) {\n        console.error('MDS panier \u2014 v\u00E9hicule adapt\u00E9 : \u00E9chec', endpoint, response.status, data)\n        revert(data.description || data.message || `Ajout impossible (HTTP ${response.status}).`)\n        return\n      }\n\n      window.dispatchEvent(new CustomEvent(shouldAdd ? 'kt.cart.added' : 'kt.cart.changed', { detail: data }))\n      this.reloadSections(data.sections)\n    } catch (error) {\n      console.error('MDS panier \u2014 v\u00E9hicule adapt\u00E9 :', error)\n      revert('Une erreur r\u00E9seau est survenue. Veuillez r\u00E9essayer.')\n    }\n  }\n\n  /*\n    Bundle (natif Shopify ou app Bundle Kit) : d\u00E9plie/replie la liste des\n    composants rendue par snippets/cart-bundle-components.liquid. R\u00E9-attach\u00E9\n    \u00E0 chaque re-rendu de section puisque le constructeur se r\u00E9-ex\u00E9cute sur\n    replaceWith() ; l'\u00E9tat revient donc \u00E0 \u00AB repli\u00E9 \u00BB apr\u00E8s une modification\n    du panier, ce qui est acceptable. (M\u00EAme m\u00E9canique que toggleBundle dans\n    cart.js pour le tiroir panier.)\n  */\n  toggleBundle (btn) {\n    const bundle = btn.closest('[data-bundle]')\n    if (!bundle) return\n\n    const list = bundle.querySelector('[data-bundle-list]')\n    const label = btn.querySelector('[data-bundle-toggle-label]')\n    const expanded = btn.getAttribute('aria-expanded') === 'true'\n    const next = !expanded\n\n    if (list) list.hidden = !next\n    btn.setAttribute('aria-expanded', String(next))\n    if (label) {\n      label.textContent = next\n        ? (btn.dataset.labelExpanded || label.textContent)\n        : (btn.dataset.labelCollapsed || label.textContent)\n    }\n  }\n\n  toggleNote (btn) {\n    const wrap = this.querySelector('[data-note-wrap]')\n    if (!wrap) return\n\n    wrap.hidden = !wrap.hidden\n    btn.setAttribute('aria-expanded', String(!wrap.hidden))\n    btn.textContent = wrap.hidden ? 'Ajouter une note \u00E0 votre commande' : 'Masquer la note'\n\n    if (!wrap.hidden) {\n      wrap.querySelector('textarea').focus()\n    }\n  }\n\n  async saveNote (note) {\n    const status = this.querySelector('[data-note-status]')\n\n    const data = await this.postUpdate({ note })\n    if (data && status) {\n      status.textContent = 'Note enregistr\u00E9e \u2713'\n      setTimeout(() => { status.textContent = '' }, 3000)\n    }\n  }\n\n  /*\n    Codes promo en cours. La croix de retrait peut se trouver sur une ligne\n    produit (remise au niveau de l'article) alors que le champ code promo du\n    r\u00E9capitulatif est masqu\u00E9 : on retombe alors sur l'attribut port\u00E9 par\n    <main-cart> lui-m\u00EAme. Sans cette source, la liste serait vide et le\n    \u00AB retrait \u00BB d'un code effacerait tous les autres.\n  */\n  appliedCodes () {\n    const promo = this.querySelector('[data-promo]')\n    const codes = promo?.dataset.appliedCodes ?? this.dataset.appliedCodes ?? ''\n    return codes.split(',').filter(Boolean)\n  }\n\n  async applyPromo () {\n    const input = this.querySelector('[data-promo-input]')\n    const code = (input.value || '').trim()\n\n    if (!code) {\n      this.showPromoError('Saisissez un code.')\n      return\n    }\n\n    this.classList.add('loading')\n\n    const previous = this.appliedCodes()\n    const data = await this.postUpdate({\n      discount: previous.concat([code]).join(','),\n      sections: this.sectionsToRender,\n      sections_url: window.Shopify.routes.cart_url\n    })\n\n    this.classList.remove('loading')\n    if (!data) return\n\n    if (!Array.isArray(data.discount_codes)) {\n      // Boutique sans prise en charge des codes promo dans le panier :\n      // on applique le code pour l'\u00E9tape de paiement via l'URL de r\u00E9duction.\n      window.location.href = `/discount/${encodeURIComponent(code)}?redirect=${encodeURIComponent(window.Shopify.routes.cart_url)}`\n      return\n    }\n\n    const entry = data.discount_codes.find(dc =>\n      dc.code.toUpperCase() === code.toUpperCase()\n    )\n\n    if (entry && entry.applicable) {\n      window.dispatchEvent(new CustomEvent('kt.cart.changed', { detail: data }))\n      this.reloadSections(data.sections)\n    } else {\n      // Code refus\u00E9 : on restaure les codes pr\u00E9c\u00E9dents et on affiche l'erreur\n      const reverted = await this.postUpdate({\n        discount: previous.join(','),\n        sections: this.sectionsToRender,\n        sections_url: window.Shopify.routes.cart_url\n      })\n      if (reverted) this.reloadSections(reverted.sections)\n      this.showPromoError('Code invalide ou expir\u00E9.', code)\n    }\n  }\n\n  async removePromo (code) {\n    this.classList.add('loading')\n\n    const remaining = this.appliedCodes().filter(c =>\n      c.toUpperCase() !== String(code).toUpperCase()\n    )\n    const data = await this.postUpdate({\n      discount: remaining.join(','),\n      sections: this.sectionsToRender,\n      sections_url: window.Shopify.routes.cart_url\n    })\n\n    this.classList.remove('loading')\n    if (!data) return\n\n    window.dispatchEvent(new CustomEvent('kt.cart.changed', { detail: data }))\n    this.reloadSections(data.sections)\n\n    // Le code est toujours l\u00E0 : la boutique n'a pas pris en compte le retrait.\n    const stillThere = Array.isArray(data.discount_codes) && data.discount_codes.some(dc =>\n      dc.code.toUpperCase() === String(code).toUpperCase()\n    )\n    if (stillThere) {\n      const cart = document.querySelector('main-cart') || this\n      cart.showError(`Le code ${code} n'a pas pu \u00EAtre retir\u00E9. Il pourra \u00EAtre supprim\u00E9 \u00E0 l'\u00E9tape de paiement.`)\n    }\n  }\n\n  async postUpdate (body) {\n    try {\n      const response = await fetch(`${window.Shopify.routes.cart_update_url}.js`, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify(body)\n      })\n      const data = await response.json()\n\n      if (!response.ok) {\n        this.showError(data.description || data.message)\n        return null\n      }\n\n      return data\n    } catch (error) {\n      this.showError()\n      return null\n    }\n  }\n\n  reloadSections (sections) {\n    if (!sections) return\n\n    for (const [key, value] of Object.entries(sections)) {\n      if (!value) continue\n      const newDoc = new DOMParser().parseFromString(value, 'text/html')\n\n      if (key === 'cart-count-badge') {\n        document.querySelectorAll('.cart-count-badge').forEach(elem => {\n          const badge = newDoc.querySelector('.cart-count-badge')\n          if (badge) elem.replaceWith(badge.cloneNode(true))\n        })\n      } else if (key === 'offcanvas-cart') {\n        const current = document.querySelector('#offcanvas-cart cart-container')\n        const fresh = newDoc.querySelector('cart-container')\n        if (current && fresh) current.replaceWith(fresh)\n      } else if (key === this.sectionId) {\n        const fresh = newDoc.querySelector('main-cart')\n        if (fresh) this.replaceWith(fresh)\n      }\n    }\n\n    window.dispatchEvent(new CustomEvent('kt.cart.reloaded'))\n  }\n\n  showPromoError (message, keepValue) {\n    // Apr\u00E8s un re-rendu, l'\u00E9l\u00E9ment courant peut avoir \u00E9t\u00E9 remplac\u00E9 :\n    // on cible toujours l'instance pr\u00E9sente dans le document.\n    const cart = document.querySelector('main-cart') || this\n    const error = cart.querySelector('[data-promo-error]')\n    const input = cart.querySelector('[data-promo-input]')\n\n    if (error) {\n      error.textContent = message\n      error.hidden = false\n    }\n    if (input) {\n      if (keepValue) input.value = keepValue\n      input.focus()\n    }\n  }\n\n  showError (message) {\n    const alert = this.querySelector('.main-cart-alert')\n\n    if (alert) {\n      alert.querySelector('[data-alert-msg]').textContent =\n        message || 'Une erreur est survenue. Veuillez r\u00E9essayer.'\n      alert.hidden = false\n    }\n  }\n}\n\ncustomElements.define('main-cart', MainCart)\n"],
  "mappings": "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",
  "names": []
}
