/** Shopify CDN: Minification failed

Line 43:4 Unexpected "7"
Line 49:1 Unexpected "{"
Line 49:3 Expected identifier but found "'component-add-on-products-callout.css'"
Line 50:0 Unexpected "<"
Line 56:9 Unexpected "{"
Line 56:18 Expected ":"
Line 57:6 Unexpected "<"
Line 59:13 Unexpected "{"
Line 59:22 Expected ":"
Line 59:46 Unexpected "<"
... and 659 more hidden warnings

**/
ChatGPT

























Invita membri del team
mar 7 apr alle 19:37
allora il cliente mi ha chiesto una piccola modifica, in pratica sotto al prezzo bisogna adesso inserire le informazioni di dettaglio, cominciamo da quello della sezione. E poi passiamo a quella pdp, ti passo prima i file dela parte della sezione. come vedi sotto al prezzo ci sono gli altri dettagli del prodotto (prima foto)

Partiamo dal liquid principale.


{{ 'component-add-on-products-callout.css' | asset_url | stylesheet_tag }}
<script src="{{ 'add-on-callout.js' | asset_url }}" defer="defer"></script>

<div class="SaftkurCallout SaftkurCallout--Adaptation">
  <div class="bs-container">
    <header class="SaftkurCallout__header">
      <h2 class="SaftkurCallout__title">
        {{ section.settings.title }}
      </h2>
      <div class="SaftkurCallout__description">
        <h3>{{ section.settings.description }}</h3>
      </div>
    </header>

    <div class="SaftkurCallout__main">
      <div class="SaftkurCallout__banner{% if section.settings.banner_badge != blank %} SaftkurCallout__badge{% endif %}" data-badge="{{ section.settings.banner_badge }}">
        {% if section.settings.section_image %}
          {{ section.settings.section_image | image_url: width: 700 | image_tag: class: "SaftkurCallout__image" }}
        {% elsif section.settings.collection.featured_image %}
          {{ section.settings.collection.featured_image | image_url: width: 700 | image_tag: class: "SaftkurCallout__image" }}
        {% endif %}

        <div class="SaftkurCallout__Availability SaftkurCallout__Availability--banner">
          {%- if section.settings.collection -%}
            <span class="Availability__pulse"></span>
            <span class="Availability__text" style="color:#125c46">{{ section.settings.banner_in_stock_text }}</span>
          {%- else -%}
            <span class="Availability__pulse Availability__pulse_available--false"></span>
            <span class="Availability__text" style="color:rgba(236,54,24,1)">{{ section.settings.banner_not_in_stock_text }}</span>
          {%- endif -%}
        </div>
      </div>

      <ul class="SaftkurCallout__product-list">
        {% for product in section.settings.collection.products %}
          {% liquid
            if product.tags contains 'hidden'
              continue
            endif
          %}
          {% if forloop.index <= section.settings.products_amount %}

            {% liquid
              assign v = product.selected_or_first_available_variant
              assign callout_form_id = 'saftkur-callout-form-' | append: section.id | append: '-' | append: product.id
              assign callout_price_id = 'saftkur-callout-price-' | append: section.id | append: '-' | append: product.id
              assign card_index = forloop.index
            %}

            {% liquid
              assign has_any_addon = false
              assign addons_heading_for_card = blank

              for b in section.blocks
                if b.type != 'callout_addon'
                  continue
                endif

                assign applies = false
                if b.settings.apply_all
                  assign applies = true
                else
                  if card_index == 1 and b.settings.apply_card_1
                    assign applies = true
                  endif
                  if card_index == 2 and b.settings.apply_card_2
                    assign applies = true
                  endif
                  if card_index == 3 and b.settings.apply_card_3
                    assign applies = true
                  endif
                endif

                if applies and b.settings.addon_product != blank
                  assign has_any_addon = true
                endif

                if applies and addons_heading_for_card == blank and b.settings.heading != blank
                  assign addons_heading_for_card = b.settings.heading
                endif
              endfor
            %}

            <li
              class="SaftkurCallout__product-card{% if forloop.index == section.settings.bestseller_position and section.settings.bestseller %} SaftkurCallout__product-card--bestseller{% endif %}"
              data-variant-id="{{ v.id }}"
            >
              <div class="SaftkurCallout__product-card--top SaftkurCallout__product-card--topAdapt">
                <h3 class="SaftkurCallout__product-title">
                  {%- if product.metafields.custom.product_title_highlight_prefix != blank
                    and product.title contains product.metafields.custom.product_title_highlight_prefix
                    and shop.locale == 'de'
                  -%}
                    {%- assign product_title_highlight_prefix = product.metafields.custom.product_title_highlight_prefix -%}
                    {%- assign product_title_highlight = product.metafields.custom.product_title_highlight -%}
                    {%- assign product_title = product.title | split: product_title_highlight_prefix -%}

                    <a href="{{ product.url }}">
                      {{ product_title_highlight_prefix }}
                      <span class="SaftkurCallout__product-title-highlight">
                        {{ product_title_highlight }}
                      </span>
                      {{ product_title.last }}
                    </a>
                  {%- else -%}
                    <a href="{{ product.url }}">{{ product.title }}</a>
                  {%- endif -%}
                </h3>
              </div>

              <div class="SaftkurCallout__product-card--center">
                <div class="SaftkurCallout__PriceRow" data-js-price-row>
                  <span class="SaftkurCallout__PriceOriginal" data-js-price-original hidden></span>

                  <div id="{{ callout_price_id }}" class="SaftkurCallout__PriceWrap">
                    {% if product.metafields.custom.duration != blank %}
                      {% liquid
                        assign duration = product.metafields.custom.duration
                        assign price_per_day_number = product.price | divided_by: duration | money
                        assign price_per_day = price_per_day_number | prepend: '<p class="SaftkurCallout__price-per-day">(' | append: '/Tag)</p>'
                      %}
                      {% render 'price', product: product, use_variant: true, append_price: price_per_day %}
                    {% else %}
                      {% render 'price', product: product, use_variant: true %}
                    {% endif %}
                  </div>

                  <span class="SaftkurCallout__DiscountPill" data-js-discount-pill hidden></span>
                </div>

                {%- if has_any_addon -%}
                  {%- liquid
                    assign money_format_escaped = shop.money_format | escape
                  -%}

                  <div
                    class="AddOnProducts AddOnProducts--Callout"
                    data-js-addon-container
                    data-section-id="{{ section.id }}"
                    data-money-format="{{ money_format_escaped }}"
                    data-base-price="{{ v.price }}"
                    data-duration="{{ product.metafields.custom.duration }}"
                    data-parent-handle="{{ product.handle }}"
                    data-parent-variant-id="{{ v.id }}"
                    data-product-form-id="{{ callout_form_id }}"
                    data-price-target-id="{{ callout_price_id }}"
                  >
                    {%- if addons_heading_for_card != blank -%}
                      <p class="AddOnProducts__Heading">{{ addons_heading_for_card }}</p>
                    {%- endif -%}

                    <div class="AddOnProducts__List">
                      {%- for b in section.blocks -%}
                        {%- if b.type != 'callout_addon' -%}
                          {%- continue -%}
                        {%- endif -%}

                        {%- liquid
                          assign applies = false
                          if b.settings.apply_all
                            assign applies = true
                          else
                            if card_index == 1 and b.settings.apply_card_1
                              assign applies = true
                            endif
                            if card_index == 2 and b.settings.apply_card_2
                              assign applies = true
                            endif
                            if card_index == 3 and b.settings.apply_card_3
                              assign applies = true
                            endif
                          endif

                          if applies == false
                            continue
                          endif

                          assign addon_product = b.settings.addon_product
                          if addon_product == blank
                            continue
                          endif

                          assign addon_variant = addon_product.selected_or_first_available_variant
                          if addon_variant == blank
                            continue
                          endif

                          assign title_override = b.settings.title_override
                          assign footnote = b.settings.footnote
                          assign subline = b.settings.subline
                          assign info_question = b.settings.info_question
                          assign info_answer = b.settings.info_answer
                          assign is_preselected = b.settings.preselected

                          assign has_info = false
                          if info_question != blank or info_answer != blank
                            assign has_info = true
                          endif

                          assign display_title = addon_product.title
                          if title_override != blank
                            assign display_title = title_override
                          endif

                          assign price = addon_variant.price
                          assign compare_at = addon_variant.compare_at_price
                          assign has_discount = false
                          if compare_at and compare_at > price
                            assign has_discount = true
                          endif

                          assign info_id = section.id | append: '-' | append: product.id | append: '-addon-' | append: b.id
                        -%}

                        <div class="AddOnItem{% if has_discount %} is-discounted{% endif %}" data-js-addon-item {{ b.shopify_attributes }}>
                          <label class="AddOnItem__Label">
                            <div class="AddOnItem__Inner">
                              <div class="AddOnItem__Selector">
                                <input
                                  class="AddOnItem__Checkbox"
                                  type="checkbox"
                                  name="addon_variant_id"
                                  value="{{ addon_variant.id }}"
                                  data-addon-variant-id="{{ addon_variant.id }}"
                                  data-addon-price="{{ price }}"
                                  {% if has_discount %}data-addon-compare-at="{{ compare_at }}"{% endif %}
                                  {% if is_preselected %}data-preselected="true" checked{% endif %}
                                >
                                <span class="AddOnItem__Mark" aria-hidden="true">
                                  <span class="AddOnItem__MarkPlus">＋</span>
                                  <img
                                    class="AddOnItem__MarkCheck"
                                    src="{{ 'check-circle.svg' | asset_url }}"
                                    alt=""
                                    width="20"
                                    height="20"
                                    loading="lazy"
                                  >
                                </span>
                              </div>

                              <div class="AddOnItem__Content">
                                <p class="AddOnItem__Title">
                                  {{ display_title }}
                                  {%- if footnote != blank -%}
                                    <span class="AddOnItem__Footnote">{{ footnote }}</span>
                                  {%- endif -%}
                                </p>

                                {%- if subline != blank -%}
                                  <div class="AddOnItem__Subline">{{ subline }}</div>
                                {%- endif -%}
                              </div>

                              {%- if has_info -%}
                                <button
                                  class="AddOnItem__InfoBtn"
                                  type="button"
                                  aria-label="Info"
                                  data-js-addon-info-button
                                  data-addon-info-target="{{ info_id }}"
                                >
                                  <svg class="AddOnItem__InfoIcon" viewBox="0 0 19 18" fill="none" aria-hidden="true">
                                    <path
                                      d="M9.5 12.2V9M9.5 5.8H9.508M17.5 9C17.5 13.4183 13.9183 17 9.5 17C5.08172 17 1.5 13.4183 1.5 9C1.5 4.58172 5.08172 1 9.5 1C13.9183 1 17.5 4.58172 17.5 9Z"
                                      stroke="#006750"
                                      stroke-width="2"
                                      stroke-linecap="round"
                                      stroke-linejoin="round"
                                    />
                                  </svg>
                                </button>
                              {%- else -%}
                                <span class="AddOnItem__InfoSpacer" aria-hidden="true"></span>
                              {%- endif -%}

                              <div class="AddOnItem__Price">
                                {%- if has_discount -%}
                                  <span class="AddOnItem__CompareAt" data-js-addon-compare-at>{{ compare_at | money }}</span>
                                {%- endif -%}

                                <span class="AddOnItem__CurrentPrice" data-js-addon-current>
                                  <span class="AddOnItem__PricePlus" aria-hidden="true">+&nbsp;</span>
                                  <span class="AddOnItem__CurrentValue">{{ price | money }}</span>
                                </span>

                                <span class="AddOnItem__DiscountedPrice" data-js-addon-discounted hidden></span>
                              </div>
                            </div>
                          </label>
                        </div>

                        {%- if has_info -%}
                          <div
                            class="AddOnTip aioa-ignore"
                            data-js-addon-tip="{{ info_id }}"
                            role="dialog"
                            aria-label="Info"
                            data-aioa-ignore="true"
                            data-uw-ignore="true"
                            data-uw-rm-ignore="true"
                          >
                            <div class="AddOnTip__Arrow" aria-hidden="true"></div>
                            <div class="AddOnTip__Inner">
                              <div class="AddOnTip__Header">
                                <p class="AddOnTip__Title">{{ info_question | default: display_title }}</p>
                                <button class="AddOnTip__Close" type="button" aria-label="Close" data-js-addon-tip-close>×</button>
                              </div>
                              <div class="AddOnTip__Body">
                                {{ info_answer }}
                              </div>
                            </div>
                          </div>
                        {%- endif -%}
                      {%- endfor -%}
                    </div>

                    <div class="AddOnOverlay" data-js-addon-overlay></div>
                  </div>
                {%- endif -%}
              </div>

              <div class="SaftkurCallout__product-card--bottom SaftkurCallout__product-card--bottomAdapt">
                {% render 'buy-buttons',
                  product: product,
                  section_id: section.id,
                  product_form_id: callout_form_id
                %}

                <div class="SaftkurCallout__bottomReviews">
                  <div style="display:block;" class="ruk_rating_snippet2" data-sku="{{ v.sku }}"></div>
                </div>
              </div>
            </li>

          {% endif %}
        {% endfor %}

        <li class="SaftkurCallout__info-text">
          <span>{{ section.settings.product_hint }}</span>
        </li>
      </ul>
    </div>
  </div>
</div>

{% style %}
.SaftkurCallout__product-title-suffix{
  display: block;
  margin-top: 2px;
}

.SaftkurCallout__product-title-highlight:before {
  content: "1";
  position: absolute;
  font-size: 8px;
  top: -8px;
  right: 5px;
}

.SaftkurCallout__product-title-highlight{
  color: #125c46;
  position: relative;
  padding-right: 4px;
}

.SaftkurCallout__product-title-suffix {
  display: block;
  margin-top: 0px !important;
}

.SaftkurCallout .price .price-item.price-item--regular,
.SaftkurCallout .price .price-item.price-item--sale.price-item--last {
  color: #181818;
}

.SaftkurCallout__sale-badge {
  display: none !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__product-card--topAdapt{
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:12px;
}

.SaftkurCallout--Adaptation .SaftkurCallout__product-card--topAdapt .SaftkurCallout__product-title{
  flex: 1 1 auto;
  min-width: 0;
}

.SaftkurCallout--Adaptation .SaftkurCallout__product-card--bottomAdapt{
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 14px;
}

.SaftkurCallout--Adaptation .SaftkurCallout__product-card--bottomAdapt .ProductForm,
.SaftkurCallout--Adaptation .SaftkurCallout__product-card--bottomAdapt form{
  width: 100%;
}

.SaftkurCallout--Adaptation .SaftkurCallout__bottomReviews{
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.SaftkurCallout--Adaptation .SaftkurCallout__bottomReviews .ruk_rating_snippet2{
  display: block;
}

.SaftkurCallout__PriceRow{
  display: flex;
  align-items: flex-start;
  gap: 8px;
  width: fit-content;
}

.SaftkurCallout__PriceWrap{
  display: block;
}

.SaftkurCallout__PriceOriginal{
  font-family: BrandonTextWeb, sans-serif;
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
  color: #8a8a8a;
  text-decoration: line-through;
  white-space: nowrap;
  margin-top: 1px;
}

.SaftkurCallout__PriceOriginal[hidden]{
  display: none !important;
}

.SaftkurCallout__DiscountPill{
  display: inline-flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  padding: 3px 9px;
  gap: 2px;
  height: 18px;
  background: #D5841B;
  border-radius: 30px;
  font-family: BrandonTextWeb, sans-serif;
  font-weight: 700;
  font-size: 12px;
  line-height: 14px;
  color: #FFFFFF;
  white-space: nowrap;
  margin-top: 2px;
}

.SaftkurCallout__DiscountPill[hidden]{
  display: none !important;
}

.AddOnItem__CurrentPrice {
  display: inline-flex;
  align-items: center;
  gap: 0;
}

.AddOnItem__CurrentValue {
  display: inline;
}

.AddOnItem__DiscountedPrice {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  color: #125c46;
  white-space: nowrap;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CompareAt {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__PricePlus {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentPrice {
  color: #8a8a8a !important;
  font-weight: 400 !important;
  text-decoration: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentValue {
  text-decoration: line-through;
}

.AddOnItem.is-cart-discount-active .AddOnItem__DiscountedPrice[hidden] {
  display: none !important;
}
{% endstyle %}

{% schema %}
{
  "name": "Saftkur callout v2",
  "settings": [
    {
      "type": "text",
      "id": "title",
      "label": "Section title",
      "default": "3, 5 oder 7 Tage durchstarten:"
    },
    {
      "type": "richtext",
      "id": "description",
      "label": "Section description",
      "default": "<p>Haltbarkeit: Alle Säfte sind nach Ankunft bei Dir mindestens 4 Wochen haltbar.<br> Du kannst Dein Startdatum also frei wählen!</p>"
    },
    {
      "type": "image_picker",
      "id": "section_image",
      "label": "Section image"
    },
    {
      "type": "text",
      "id": "banner_badge",
      "label": "Banner Badge",
      "default": "🔖 Du sparst 20%",
      "info": "If this field is blank the badge will be disabled"
    },
    {
      "type": "collection",
      "id": "collection",
      "label": "Collection"
    },
    {
      "type": "text",
      "id": "banner_in_stock_text",
      "label": "Banner in stock Text",
      "default": "Auf Lager - in 1-2 Werktagen bei Dir"
    },
    {
      "type": "text",
      "id": "banner_not_in_stock_text",
      "label": "Banner not in stock Text"
    },
    {
      "type": "text",
      "id": "product_hint",
      "label": "Product hint",
      "default": "Haltbarkeit: Alle Säfte sind nach Ankunft bei Dir gekühlt bis zu 4 Wochen haltbar."
    },
    {
      "type": "range",
      "id": "products_amount",
      "min": 1,
      "max": 10,
      "step": 1,
      "label": "Products shown",
      "default": 3
    },
    {
      "type": "checkbox",
      "id": "bestseller",
      "label": "Bestseller",
      "default": true
    },
    {
      "type": "number",
      "id": "bestseller_position",
      "label": "Bestseller position",
      "info": "Enter a number between 1 and 10 to highlight a specific product card starting count from the first product on the top",
      "default": 2
    }
  ],
  "blocks": [
    {
      "type": "callout_addon",
      "name": "Callout add-on",
      "settings": [
        {
          "type": "text",
          "id": "heading",
          "label": "Add-ons heading",
          "default": "Ergänzend zur Saftkur:"
        },
        { "type": "product", "id": "addon_product", "label": "Add-on product" },
        { "type": "checkbox", "id": "preselected", "label": "Preselected (checked by default)", "default": false },

        { "type": "text", "id": "title_override", "label": "Title override (optional)" },
        { "type": "text", "id": "footnote", "label": "Footnote (e.g. ²)" },
        { "type": "text", "id": "subline", "label": "Subline (optional)" },
        { "type": "text", "id": "info_question", "label": "Info question" },
        { "type": "richtext", "id": "info_answer", "label": "Info answer" },

        { "type": "header", "content": "Apply to cards" },
        { "type": "checkbox", "id": "apply_all", "label": "Apply to all cards", "default": true },
        { "type": "checkbox", "id": "apply_card_1", "label": "Apply to card #1", "default": false },
        { "type": "checkbox", "id": "apply_card_2", "label": "Apply to card #2", "default": false },
        { "type": "checkbox", "id": "apply_card_3", "label": "Apply to card #3", "default": false }
      ]
    }
  ],
  "presets": [
    { "name": "Saftkur callout v2" }
  ]
}
{% endschema %}

Qui lo snippet.

{%- comment -%}
  Add-on products (CALLOUT - settings-based)
  - Reads add-ons from section.settings using prefixes p1 / p2 / p3
  - MAX 3 add-ons per card
  - Uses card_index (1..3) to pick settings group
{%- endcomment -%}

{%- liquid
  assign money_format_escaped = shop.money_format | escape
  assign base_variant = base_variant_override | default: product.selected_or_first_available_variant

  assign idx = card_index | default: 1

  comment
    Build prefix from card index:
    1 => p1
    2 => p2
    3 => p3
  endcomment
  assign prefix = 'p' | append: idx

  assign test_key = prefix | append: '_addon_1_product'
  assign has_any_addon = false
  if section.settings[test_key] != blank
    assign has_any_addon = true
  endif
-%}

{%- if has_any_addon -%}
  <div
    class="AddOnProducts AddOnProducts--Callout"
    data-js-addon-container
    data-section-id="{{ section.id }}"
    data-money-format="{{ money_format_escaped }}"
    data-base-price="{{ base_variant.price }}"
    data-parent-handle="{{ product.handle }}"
    data-parent-variant-id="{{ base_variant.id }}"
    data-product-form-id="{{ product_form_id }}"
    data-price-target-id="{{ price_target_id }}"
  >
    {%- comment -%}
      Callout heading (per your screenshot)
      If you want this configurable later, we can wire a setting.
    {%- endcomment -%}
    <p class="AddOnProducts__Heading">Ergänzend zur Saftkur:</p>

    <div class="AddOnProducts__List">
      {%- for i in (1..3) -%}
        {%- liquid
          assign p_key  = prefix | append: '_addon_' | append: i | append: '_product'
          assign t_key  = prefix | append: '_addon_' | append: i | append: '_title_override'
          assign f_key  = prefix | append: '_addon_' | append: i | append: '_footnote'
          assign s_key  = prefix | append: '_addon_' | append: i | append: '_subline'
          assign iq_key = prefix | append: '_addon_' | append: i | append: '_info_question'
          assign ia_key = prefix | append: '_addon_' | append: i | append: '_info_answer'

          assign addon_product = section.settings[p_key]
          if addon_product == blank
            continue
          endif

          assign addon_variant = addon_product.selected_or_first_available_variant
          if addon_variant == blank
            continue
          endif

          assign title_override = section.settings[t_key]
          assign footnote = section.settings[f_key]
          assign subline = section.settings[s_key]
          assign info_question = section.settings[iq_key]
          assign info_answer = section.settings[ia_key]

          assign has_info = false
          if info_question != blank or info_answer != blank
            assign has_info = true
          endif

          assign display_title = addon_product.title
          if title_override != blank
            assign display_title = title_override
          endif

          assign price = addon_variant.price
          assign compare_at = addon_variant.compare_at_price
          assign has_discount = false
          if compare_at and compare_at > price
            assign has_discount = true
          endif

          comment
            Stable unique id per card + addon + index
          endcomment
          assign info_id = section.id | append: '-' | append: product.id | append: '-' | append: prefix | append: '-addon-' | append: i
        -%}

        <div class="AddOnItem{% if has_discount %} is-discounted{% endif %}" data-js-addon-item>
          <label class="AddOnItem__Label">
            <div class="AddOnItem__Inner">
              <div class="AddOnItem__Selector">
                <input
                  class="AddOnItem__Checkbox"
                  type="checkbox"
                  name="addon_variant_id"
                  value="{{ addon_variant.id }}"
                  data-addon-variant-id="{{ addon_variant.id }}"
                  data-addon-price="{{ price }}"
                  {% if has_discount %}data-addon-compare-at="{{ compare_at }}"{% endif %}
                >
                <span class="AddOnItem__Mark" aria-hidden="true">
                  <span class="AddOnItem__MarkPlus">+</span>
                  <img
                    class="AddOnItem__MarkCheck"
                    src="{{ 'check-circle.svg' | asset_url }}"
                    alt=""
                    width="20"
                    height="20"
                    loading="lazy"
                  >
                </span>
              </div>

              <div class="AddOnItem__Content">
                <p class="AddOnItem__Title">
                  {{ display_title }}
                  {%- if footnote != blank -%}
                    <span class="AddOnItem__Footnote">{{ footnote }}</span>
                  {%- endif -%}
                </p>

                {%- if subline != blank -%}
                  <div class="AddOnItem__Subline">{{ subline }}</div>
                {%- endif -%}
              </div>

              {%- if has_info -%}
                <button
                  class="AddOnItem__InfoBtn"
                  type="button"
                  aria-label="Info"
                  data-js-addon-info-button
                  data-addon-info-target="{{ info_id }}"
                >
                  <svg class="AddOnItem__InfoIcon" viewBox="0 0 19 18" fill="none" aria-hidden="true">
                    <path
                      d="M9.5 12.2V9M9.5 5.8H9.508M17.5 9C17.5 13.4183 13.9183 17 9.5 17C5.08172 17 1.5 13.4183 1.5 9C1.5 4.58172 5.08172 1 9.5 1C13.9183 1 17.5 4.58172 17.5 9Z"
                      stroke="#006750"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                    />
                  </svg>
                </button>
              {%- else -%}
                <span class="AddOnItem__InfoSpacer" aria-hidden="true"></span>
              {%- endif -%}

              <div class="AddOnItem__Price">
                {%- if has_discount -%}
                  <span class="AddOnItem__CompareAt">{{ compare_at | money }}</span>
                {%- endif -%}
                <span class="AddOnItem__CurrentPrice">
                  <span class="AddOnItem__PricePlus" aria-hidden="true">+&nbsp;</span>{{ price | money }}
                </span>
              </div>
            </div>
          </label>
        </div>

        {%- if has_info -%}
          <div class="AddOnTip" data-js-addon-tip="{{ info_id }}" role="dialog" aria-label="Info">
            <div class="AddOnTip__Arrow" aria-hidden="true"></div>

            <div class="AddOnTip__Inner">
              <div class="AddOnTip__Header">
                <p class="AddOnTip__Title">{{ info_question | default: display_title }}</p>
                <button class="AddOnTip__Close" type="button" aria-label="Close" data-js-addon-tip-close>×</button>
              </div>

              <div class="AddOnTip__Body">
                {{ info_answer }}
              </div>
            </div>
          </div>
        {%- endif -%}
      {%- endfor -%}
    </div>
  </div>
{%- endif -%}

qui il js

/**
 * Add-on products (CALLOUT)
 * - Merge add-ons into SAME cart request
 * - Reliable UI resync
 * - Tooltip popover
 * - Cart discount UI:
 *   product => use theme old price + discounted + badge
 *   add-ons => original striked + discounted
 */

(function () {
  const SELECTORS = {
    container: '[data-js-addon-container]',
    item: '[data-js-addon-item]',
    checkbox: 'input[type="checkbox"][data-addon-variant-id]',
    infoBtn: '[data-js-addon-info-button]',
    tip: '[data-js-addon-tip]',
    tipClose: '[data-js-addon-tip-close]',
    addonCurrent: '[data-js-addon-current]',
    addonDiscounted: '[data-js-addon-discounted]',
    priceOriginal: '[data-js-price-original]',
    discountPill: '[data-js-discount-pill]',
  };

  const STORAGE_KEY = 'lf_pending_addons_merge_callout_v1';
  const CART_CHANGED_EVENT = 'lf:cart-changed';

  const CART_MUT_RE = /\/cart\/(add|change|update|clear)(\.js)?(\?|$)/i;
  const CART_ADD_RE = /\/cart\/add(\.js)?(\?|$)/i;

  const HEADER_SEARCH_SELECTOR = [
    'sticky-header',
    '.header-wrapper',
    'header',
    'details-modal',
    '.header__search',
    '.search-modal',
    '.modal__toggle',
    '.modal-overlay',
    'predictive-search',
    '[data-predictive-search]',
    '#Search-In-Modal',
    'input[type="search"]',
    '.search__input',
    '.field__input',
    '.LIV-547-searchbar',
    '.LIV-547-searchbar-mobile',
    '#cart-icon-bubble',
    '.header__icon--cart',
  ].join(',');

  let lastCart = null;

  function isInHeaderOrSearch(el) {
    try {
      return !!(el && el.closest && el.closest(HEADER_SEARCH_SELECTOR));
    } catch (e) {
      return false;
    }
  }

  async function fetchCart() {
    const res = await fetch('/cart.js', { credentials: 'same-origin' });
    if (!res.ok) throw new Error('Failed to load cart');
    return res.json();
  }

  function toInt(val, fallback = 0) {
    const n = parseInt(String(val ?? '').replace(/[^\d-]/g, ''), 10);
    return Number.isFinite(n) ? n : fallback;
  }

  function formatMoney(cents, moneyFormat) {
    try {
      if (window.Shopify && typeof window.Shopify.formatMoney === 'function') {
        return window.Shopify.formatMoney(cents, moneyFormat);
      }
    } catch (e) {}
    const amount = (cents / 100).toFixed(2).replace('.', ',');
    return amount + ' €';
  }

  function getMoneyFormat(container) {
    return container.getAttribute('data-money-format') || '${{amount}}';
  }

  function getParentVariantId(container) {
    return String(container.getAttribute('data-parent-variant-id') || '');
  }

  function getBasePrice(container) {
    return toInt(container.getAttribute('data-base-price'), 0);
  }

  function getDuration(container) {
    const d = toInt(container.getAttribute('data-duration'), 0);
    return d > 0 ? d : 0;
  }

  function getPriceTarget(container) {
    const targetId = container.getAttribute('data-price-target-id');
    if (targetId) return document.getElementById(targetId);
    return null;
  }

  function getProductCard(container) {
    return container.closest('.SaftkurCallout__product-card');
  }

  function setPriceLoadingState(container, isLoading) {
    const card = getProductCard(container);
    if (!card) return;
    card.classList.toggle('is-price-loading', !!isLoading);
  }

  function setCartDiscountState(container, isActive) {
    const card = getProductCard(container);
    if (!card) return;
    card.classList.toggle('is-cart-discount-active', !!isActive);
  }

  function findCurrentProductPriceNode(priceRoot) {
    if (!priceRoot) return null;
    return (
      priceRoot.querySelector('.price__sale .price-item--sale.price-item--last') ||
      priceRoot.querySelector('.price__sale .price-item--sale') ||
      priceRoot.querySelector('.price__regular .price-item--regular') ||
      priceRoot.querySelector('.price-item--sale.price-item--last') ||
      priceRoot.querySelector('.price-item--sale') ||
      priceRoot.querySelector('.price-item--regular')
    );
  }

  function findRegularProductPriceNode(priceRoot) {
    if (!priceRoot) return null;
    return (
      priceRoot.querySelector('.price__regular .price-item--regular') ||
      priceRoot.querySelector('.price .price__regular .price-item') ||
      priceRoot.querySelector('.price .price-item--regular')
    );
  }

  function updatePricePerDay(priceRoot, centsTotal, duration, moneyFormat) {
    if (!priceRoot || !duration) return;
    const el = priceRoot.querySelector('.SaftkurCallout__price-per-day');
    if (!el) return;

    const perDay = Math.round(centsTotal / duration);
    el.textContent = (${formatMoney(perDay, moneyFormat)}/Tag);
  }

  function restorePerDayToRegularRow(priceRoot) {
    if (!priceRoot) return;

    const perDayEl = priceRoot.querySelector('.SaftkurCallout__price-per-day');
    const regularWrap = priceRoot.querySelector('.price__regular');
    const regularNode = findRegularProductPriceNode(priceRoot);

    if (!perDayEl || !regularWrap) return;
    if (regularWrap.contains(perDayEl)) return;

    if (regularNode && regularNode.parentNode === regularWrap) {
      regularNode.insertAdjacentElement('afterend', perDayEl);
      return;
    }

    regularWrap.appendChild(perDayEl);
  }

  function updateSelectedUI(container) {
    container.querySelectorAll(SELECTORS.item).forEach((row) => {
      const cb = row.querySelector(SELECTORS.checkbox);
      row.classList.toggle('is-selected', !!(cb && cb.checked));
    });
  }

  function getSessionDiscount() {
    try {
      var code = null;

      var cookieMatch = document.cookie
        .split('; ')
        .find(function (row) { return row.startsWith('discount_code='); });
      if (cookieMatch) code = cookieMatch.split('=')[1];

      if (!code) {
        var raw = sessionStorage.getItem('scDiscountData');
        if (raw) {
          var parsed = JSON.parse(raw);
          if (parsed && parsed.code) code = parsed.code;
        }
      }

      if (!code) return null;

      var codeValues = window.discountCodeValues;
      if (codeValues) {
        var lowerCode = code.toLowerCase();
        for (var key in codeValues) {
          if (key.toLowerCase() === lowerCode && codeValues[key] > 0) {
            var pct = codeValues[key] * 100;
            return { active: true, factor: 1 - codeValues[key], pct: window.roundDiscount(pct) };
          }
        }
      }

      if (typeof discountApplyPopupsObj !== 'undefined' && Array.isArray(discountApplyPopupsObj)) {
        var lc = code.toLowerCase();
        for (var i = 0; i < discountApplyPopupsObj.length; i++) {
          var obj = discountApplyPopupsObj[i];
          if (obj.discount && obj.discount.toLowerCase() === lc && parseFloat(obj.discountValue) > 0) {
            var pctVal = parseFloat(obj.discountValue);
            return { active: true, factor: 1 - pctVal / 100, pct: window.roundDiscount(pctVal) };
          }
        }
      }
    } catch (e) {}
    return null;
  }

  function getCartDiscount(cart) {
    const total = toInt(cart?.total_price, 0);
    const original = toInt(cart?.original_total_price, 0);

    if (original > 0 && total > 0 && total < original) {
      // Use the discount code's percentage value directly when available,
      // because cart-level ratio is diluted by non-discounted items (e.g. deposit)
      const items = cart?.items || [];
      for (const item of items) {
        const allocs = item.line_level_discount_allocations || [];
        for (const alloc of allocs) {
          const app = alloc.discount_application;
          if (app && app.value_type === 'percentage' && parseFloat(app.value) > 0) {
            const codePct = parseFloat(app.value);
            const codeFactor = 1 - codePct / 100;
            return { active: true, factor: codeFactor, pct: window.roundDiscount(codePct) };
          }
        }
      }

      // Fallback: calculate from cart totals (fixed_amount discounts or other cases)
      const factor = total / original;
      const pct = window.roundDiscount((1 - factor) * 100);
      return { active: true, factor, pct };
    }

    // Fallback: read discount from session/cookie when cart is empty or has no allocations
    const sessionDiscount = getSessionDiscount();
    if (sessionDiscount) return sessionDiscount;

    return { active: false, factor: 1, pct: 0 };
  }

  function movePerDayIntoSaleRow(priceRoot, saleWrap, saleCurrentNode, pillEl) {
    if (!priceRoot || !saleWrap) return;

    const perDayEl = priceRoot.querySelector('.SaftkurCallout__price-per-day');
    if (!perDayEl) return;

    if (saleWrap.contains(perDayEl)) return;

    if (pillEl && pillEl.parentNode === saleWrap) {
      saleWrap.insertBefore(perDayEl, pillEl);
      return;
    }

    if (saleCurrentNode && saleCurrentNode.parentNode === saleWrap) {
      saleCurrentNode.insertAdjacentElement('afterend', perDayEl);
      return;
    }

    saleWrap.appendChild(perDayEl);
  }

  function applyDiscountToProduct(container, cart) {
    const discount = getCartDiscount(cart);
    const priceRoot = getPriceTarget(container);
    if (!priceRoot) return;

    const row = priceRoot.closest('.SaftkurCallout__PriceRow');
    const originalEl = row ? row.querySelector(SELECTORS.priceOriginal) : null;
    const pillEl = row ? row.querySelector(SELECTORS.discountPill) : null;

    const basePrice = getBasePrice(container);
    const duration = getDuration(container);
    const moneyFormat = getMoneyFormat(container);

    const saleWrap = priceRoot.querySelector('.price__sale');
    const saleOldNode =
      priceRoot.querySelector('.price__sale .price-item--regular') ||
      priceRoot.querySelector('.price .price-item.price-item--regular');
    const saleCurrentNode =
      priceRoot.querySelector('.price__sale .price-item--sale.price-item--last') ||
      priceRoot.querySelector('.price__sale .price-item--sale') ||
      priceRoot.querySelector('.price-item--sale.price-item--last') ||
      priceRoot.querySelector('.price-item--sale') ||
      priceRoot.querySelector('.price__regular .price-item--regular') ||
      priceRoot.querySelector('.price-item--regular');

    const regularNode = findRegularProductPriceNode(priceRoot);

    if (!discount.active) {
      setCartDiscountState(container, false);

      if (originalEl) {
        originalEl.hidden = true;
        originalEl.textContent = '';
      }

      if (pillEl) {
        pillEl.hidden = true;
        pillEl.textContent = '';
      }

      if (regularNode) {
        regularNode.textContent = formatMoney(basePrice, moneyFormat);
      }

      if (duration) {
        updatePricePerDay(priceRoot, basePrice, duration, moneyFormat);
        restorePerDayToRegularRow(priceRoot);
      }

      return;
    }

    setCartDiscountState(container, true);

    const discounted = Math.round(basePrice * discount.factor);

    if (originalEl) {
      originalEl.hidden = true;
      originalEl.textContent = '';
    }

    if (saleOldNode) {
      saleOldNode.textContent = formatMoney(basePrice, moneyFormat);
    }

    if (saleCurrentNode) {
      saleCurrentNode.textContent = formatMoney(discounted, moneyFormat);
    }

    if (pillEl) {
      pillEl.hidden = false;
      pillEl.textContent = -${discount.pct}%;

      if (saleWrap && pillEl.parentNode !== saleWrap) {
        saleWrap.appendChild(pillEl);
      }
    }

    if (duration) updatePricePerDay(priceRoot, discounted, duration, moneyFormat);

    movePerDayIntoSaleRow(priceRoot, saleWrap, saleCurrentNode, pillEl);
  }

  function applyDiscountToAddons(container, cart) {
    const discount = getCartDiscount(cart);
    const moneyFormat = getMoneyFormat(container);

    container.querySelectorAll(SELECTORS.item).forEach((row) => {
      const cb = row.querySelector(SELECTORS.checkbox);
      const currentEl = row.querySelector(SELECTORS.addonCurrent);
      const discountedEl = row.querySelector(SELECTORS.addonDiscounted);

      if (!cb || !currentEl || !discountedEl) return;

      const addonCents = toInt(cb.getAttribute('data-addon-price'), 0);

      if (!discount.active || !addonCents) {
        row.classList.remove('is-cart-discount-active');
        discountedEl.hidden = true;
        discountedEl.textContent = '';
        return;
      }

      const discounted = Math.round(addonCents * discount.factor);

      row.classList.add('is-cart-discount-active');
      discountedEl.hidden = false;
      discountedEl.textContent = formatMoney(discounted, moneyFormat);
    });
  }

  function buildAddonOwnershipIndex(cart) {
    const owned = new Set();

    (cart?.items || []).forEach((it) => {
      const vid = String(it.variant_id || '');
      const props = it.properties || {};
      const isAddon = String(props?._addon || '') === 'true';
      const ownerParent = String(props?._addon_for_variant || '');
      if (isAddon && vid && ownerParent) {
        owned.add(${vid}::${ownerParent});
      }
    });

    return owned;
  }

  function applyCartStateToUI(container, cart) {
    lastCart = cart;

    const ownerSet = buildAddonOwnershipIndex(cart);
    const parentVariantId = getParentVariantId(container);

    container.querySelectorAll(SELECTORS.checkbox).forEach((cb) => {
      const addonVid = String(toInt(cb.getAttribute('data-addon-variant-id'), 0) || '');
      if (!addonVid) return;

      const shouldBeChecked =
        ownerSet.size > 0 ? ownerSet.has(${addonVid}::${parentVariantId}) : false;

      cb.checked = !!shouldBeChecked;
    });

    updateSelectedUI(container);
    applyDiscountToProduct(container, cart);
    applyDiscountToAddons(container, cart);
  }

  function createThrottled(fn, wait) {
    let t = null;
    return function () {
      if (t) return;
      t = setTimeout(() => {
        t = null;
        fn();
      }, wait);
    };
  }

  function bindCartResync(container) {
    const resync = createThrottled(async () => {
      try {
        setPriceLoadingState(container, true);
        const cart = await fetchCart();
        applyCartStateToUI(container, cart);
      } catch (e) {
      } finally {
        setPriceLoadingState(container, false);
      }
    }, 200);

    document.addEventListener(CART_CHANGED_EVENT, resync);
    document.addEventListener('cart:updated', resync);
    document.addEventListener('cart:refresh', resync);

    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') resync();
    });
    window.addEventListener('focus', resync);
  }

  function resetTipInlinePosition(tip) {
    if (!tip) return;
    tip.style.position = '';
    tip.style.top = '';
    tip.style.left = '';
    tip.style.removeProperty('--arrow-x');
    tip.style.visibility = '';
  }

  function closeAllTips(container) {
    container.querySelectorAll(SELECTORS.tip).forEach((t) => {
      t.classList.remove('is-open', 'is-above');
      t.setAttribute('aria-hidden', 'true');
      if (t.hasAttribute('inert')) t.removeAttribute('inert');
      resetTipInlinePosition(t);
    });
  }

  function closeAllTipsEverywhere() {
    document.querySelectorAll(SELECTORS.tip).forEach((t) => {
      t.classList.remove('is-open', 'is-above');
      t.setAttribute('aria-hidden', 'true');
      if (t.hasAttribute('inert')) t.removeAttribute('inert');
      resetTipInlinePosition(t);
    });
  }

  function ensureTipInteractive(tip) {
    if (!tip) return;
    tip.setAttribute('aria-hidden', 'false');
    if (tip.hasAttribute('inert')) tip.removeAttribute('inert');
  }

  function positionTipFixed(buttonEl, tipEl) {
    if (!buttonEl || !tipEl) return;

    const btnRect = buttonEl.getBoundingClientRect();

    const prevVisibility = tipEl.style.visibility;
    tipEl.style.visibility = 'hidden';
    tipEl.style.position = 'fixed';
    tipEl.classList.add('is-open');
    ensureTipInteractive(tipEl);

    const tipRect = tipEl.getBoundingClientRect();
    const vw = window.innerWidth;
    const vh = window.innerHeight;

    let top = btnRect.bottom + 10;
    let left = btnRect.left + btnRect.width / 2 - tipRect.width / 2;

    left = Math.max(12, Math.min(left, vw - tipRect.width - 12));

    if (top + tipRect.height + 12 > vh) {
      top = btnRect.top - tipRect.height - 10;
      tipEl.classList.add('is-above');
    } else {
      tipEl.classList.remove('is-above');
    }

    top = Math.max(8, top);

    tipEl.style.top = ${top}px;
    tipEl.style.left = ${left}px;

    const arrowCenter = btnRect.left + btnRect.width / 2 - left;
    tipEl.style.setProperty('--arrow-x', ${arrowCenter}px);

    tipEl.style.visibility = prevVisibility || '';
  }

  function openTip(buttonEl, tipEl) {
    if (!buttonEl || !tipEl) return;

    closeAllTipsEverywhere();

    tipEl.classList.add('is-open');
    ensureTipInteractive(tipEl);
    positionTipFixed(buttonEl, tipEl);

    setTimeout(() => {
      if (!tipEl.classList.contains('is-open')) return;
      ensureTipInteractive(tipEl);
      positionTipFixed(buttonEl, tipEl);
    }, 0);

    setTimeout(() => {
      if (!tipEl.classList.contains('is-open')) return;
      ensureTipInteractive(tipEl);
      positionTipFixed(buttonEl, tipEl);
    }, 50);
  }

  function toggleTip(container, infoBtn) {
    const id = infoBtn.getAttribute('data-addon-info-target');
    if (!id) return;

    const tip = container.querySelector([data-js-addon-tip="${CSS.escape(id)}"]);
    if (!tip) return;

    const wasOpen = tip.classList.contains('is-open');
    closeAllTipsEverywhere();

    if (!wasOpen) openTip(infoBtn, tip);
  }

  function bindTipHandlers(container) {
    container.addEventListener(
      'pointerdown',
      (e) => {
        const infoBtn = e.target.closest?.(SELECTORS.infoBtn);
        if (!infoBtn || !container.contains(infoBtn)) return;
        e.preventDefault();
        e.stopPropagation();
        if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
      },
      true
    );

    container.addEventListener('click', (e) => {
      const infoBtn = e.target.closest?.(SELECTORS.infoBtn);
      if (infoBtn && container.contains(infoBtn)) {
        e.preventDefault();
        e.stopPropagation();
        if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
        toggleTip(container, infoBtn);
        return;
      }

      const tipClose = e.target.closest?.(SELECTORS.tipClose);
      if (tipClose && container.contains(tipClose)) {
        e.preventDefault();
        e.stopPropagation();
        closeAllTips(container);
        return;
      }
    });
  }

  function ensureGlobalOutsideHandlers() {
    if (window.__lfAddonsCalloutGlobalOutsideBound_V9) return;
    window.__lfAddonsCalloutGlobalOutsideBound_V9 = true;

    document.addEventListener('click', (e) => {
      if (isInHeaderOrSearch(e.target)) return;

      const insideAddon = e.target && e.target.closest ? e.target.closest(SELECTORS.container) : null;
      if (insideAddon) return;

      closeAllTipsEverywhere();
    });

    window.addEventListener('resize', () => closeAllTipsEverywhere());
    window.addEventListener('scroll', () => closeAllTipsEverywhere(), { passive: true });

    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') closeAllTipsEverywhere();
    });
  }

  function writePending(payload) {
    try {
      sessionStorage.setItem(STORAGE_KEY, JSON.stringify(payload));
    } catch (e) {}
  }

  function readPending() {
    try {
      const raw = sessionStorage.getItem(STORAGE_KEY);
      if (!raw) return null;
      return JSON.parse(raw);
    } catch (e) {
      return null;
    }
  }

  function clearPending() {
    try {
      sessionStorage.removeItem(STORAGE_KEY);
    } catch (e) {}
  }

  function getSelectedAddonVariantIds(container) {
    const ids = [];
    container.querySelectorAll(SELECTORS.checkbox).forEach((cb) => {
      if (!cb.checked) return;
      const vid = toInt(cb.getAttribute('data-addon-variant-id'), 0);
      if (vid) ids.push(vid);
    });
    return ids;
  }

  function bindCheckboxUI(container) {
    container.addEventListener('change', (e) => {
      const cb =
        e.target && e.target.matches && e.target.matches(SELECTORS.checkbox) ? e.target : null;
      if (!cb) return;

      updateSelectedUI(container);

      if (lastCart) {
        applyDiscountToAddons(container, lastCart);
      }
    });
  }

  function bindFormCapture(container) {
    const formId = container.getAttribute('data-product-form-id');
    if (!formId) return;

    const form = document.getElementById(formId);
    if (!form) return;
    if (form.__lfAddonsCaptureBoundCallout) return;
    form.__lfAddonsCaptureBoundCallout = true;

    form.addEventListener(
      'submit',
      () => {
        const addonIds = getSelectedAddonVariantIds(container);
        if (!addonIds.length) {
          clearPending();
          return;
        }

        writePending({
          createdAt: Date.now(),
          addonVariantIds: addonIds,
          parentHandle: container.getAttribute('data-parent-handle') || '',
          parentVariantId: container.getAttribute('data-parent-variant-id') || '',
        });
      },
      true
    );
  }

  function dispatchCartChanged() {
    try {
      document.dispatchEvent(new CustomEvent(CART_CHANGED_EVENT));
    } catch (e) {}
  }

  function buildItemsFromFormData(fd) {
    const mainId = toInt(fd.get('id'), 0);
    const qty = toInt(fd.get('quantity'), 1) || 1;

    const properties = {};
    for (const [k, v] of fd.entries()) {
      const m = String(k).match(/^properties\[(.+)\]$/);
      if (m) properties[m[1]] = v;
    }

    const item = { id: mainId, quantity: qty };
    if (Object.keys(properties).length) item.properties = properties;

    return mainId ? [item] : [];
  }

  function buildItemsFromUrlEncoded(bodyStr) {
    const usp = new URLSearchParams(bodyStr);
    const fd = new FormData();
    for (const [k, v] of usp.entries()) fd.append(k, v);
    return buildItemsFromFormData(fd);
  }

  function tryParseJSONBody(body) {
    try {
      return JSON.parse(body);
    } catch (e) {
      return null;
    }
  }

  function ensureNetworkPatches() {
    if (window.__lfAddonsNetworkPatchedCalloutV7) return;
    window.__lfAddonsNetworkPatchedCalloutV7 = true;

    const originalFetch = window.fetch.bind(window);

    window.fetch = async function (input, init) {
      const url =
        typeof input === 'string' ? input : input && input.url ? input.url : '';
      const isCartMutation = CART_MUT_RE.test(url);
      const isCartAdd = CART_ADD_RE.test(url);

      if (
        isCartAdd &&
        !window.__lfAddonsMergingNowCallout &&
        init &&
        (init.method || 'POST').toUpperCase() === 'POST'
      ) {
        const pending = readPending();
        const isFresh = pending && Date.now() - (pending.createdAt || 0) <= 60 * 1000;
        const addonIds = isFresh && Array.isArray(pending.addonVariantIds) ? pending.addonVariantIds : [];

        if (addonIds.length) {
          try {
            window.__lfAddonsMergingNowCallout = true;

            let mainItems = [];
            const headers = new Headers(init.headers || {});
            const body = init.body;

            if (body instanceof FormData) {
              mainItems = buildItemsFromFormData(body);
            } else if (typeof body === 'string') {
              const json = tryParseJSONBody(body);
              if (json && Array.isArray(json.items)) {
                mainItems = json.items;
              } else {
                mainItems = buildItemsFromUrlEncoded(body);
              }
            } else if (body && typeof body === 'object') {
              if (Array.isArray(body.items)) mainItems = body.items;
            }

            const items = Array.isArray(mainItems) ? [...mainItems] : [];

            const parentHandle = pending.parentHandle || '';
            const parentVariantId = pending.parentVariantId || '';

            addonIds.forEach((vid) => {
              items.push({
                id: vid,
                quantity: 1,
                properties: {
                  _addon: 'true',
                  _addon_for: parentHandle,
                  _addon_for_variant: parentVariantId,
                },
              });
            });

            clearPending();

            headers.set('Content-Type', 'application/json');

            const newInit = {
              ...init,
              headers,
              body: JSON.stringify({ items }),
            };

            const res = await originalFetch(input, newInit);
            if (res && res.ok) dispatchCartChanged();
            return res;
          } catch (e) {
            clearPending();
            window.__lfAddonsMergingNowCallout = false;
            return originalFetch(input, init);
          } finally {
            window.__lfAddonsMergingNowCallout = false;
          }
        }
      }

      const res = await originalFetch(input, init);
      if (isCartMutation && res && res.ok) dispatchCartChanged();
      return res;
    };

    const OriginalXHR = window.XMLHttpRequest;
    function PatchedXHR() {
      const xhr = new OriginalXHR();
      let _url = '';

      const originalOpen = xhr.open;
      xhr.open = function (method, url) {
        _url = String(url || '');
        return originalOpen.apply(xhr, arguments);
      };

      xhr.addEventListener('load', function () {
        try {
          if (xhr.status >= 200 && xhr.status < 300 && CART_MUT_RE.test(_url)) {
            dispatchCartChanged();
          }
        } catch (e) {}
      });

      return xhr;
    }
    window.XMLHttpRequest = PatchedXHR;
  }

  async function initContainer(container) {
    ensureNetworkPatches();
    ensureGlobalOutsideHandlers();

    bindTipHandlers(container);
    bindCheckboxUI(container);
    bindFormCapture(container);
    bindCartResync(container);

    updateSelectedUI(container);

    try {
      setPriceLoadingState(container, true);
      const cart = await fetchCart();
      applyCartStateToUI(container, cart);
    } catch (e) {
    } finally {
      setPriceLoadingState(container, false);
    }
  }

  function boot() {
    const containers = document.querySelectorAll(SELECTORS.container);
    if (!containers.length) return;
    containers.forEach((c) => initContainer(c));
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', boot);
  } else {
    boot();
  }
})();

(function patchBestsellerInfoJump() {
  if (window.__lf_patchBestsellerInfoJumpBound_V5) return;
  window.__lf_patchBestsellerInfoJumpBound_V5 = true;

  function isBestsellerInfoButton(btn) {
    return !!(btn && btn.closest && btn.closest('.SaftkurCallout__product-card--bestseller'));
  }

  function getTipFromButton(btn) {
    const tipId = btn.getAttribute('data-addon-info-target');
    if (!tipId) return null;

    const container = btn.closest('[data-js-addon-container]');
    const selector = [data-js-addon-tip="${CSS.escape(tipId)}"];

    return (container && container.querySelector(selector)) || document.querySelector(selector);
  }

  function resetTipInlinePosition(tip) {
    if (!tip) return;
    tip.style.position = '';
    tip.style.top = '';
    tip.style.left = '';
    tip.style.removeProperty('--arrow-x');
    tip.style.visibility = '';
  }

  function closeAllTipsEverywhere() {
    document.querySelectorAll('[data-js-addon-tip]').forEach((tip) => {
      tip.classList.remove('is-open', 'is-above');
      tip.setAttribute('aria-hidden', 'true');
      if (tip.hasAttribute('inert')) tip.removeAttribute('inert');
      resetTipInlinePosition(tip);
    });
  }

  function openTipForButton(btn, tip) {
    if (!btn || !tip) return;

    tip.classList.add('is-open');
    tip.classList.remove('is-above');
    tip.setAttribute('aria-hidden', 'false');
    if (tip.hasAttribute('inert')) tip.removeAttribute('inert');

    const btnRect = btn.getBoundingClientRect();

    const prevVis = tip.style.visibility;
    tip.style.visibility = 'hidden';
    tip.style.position = 'fixed';

    const tipRect = tip.getBoundingClientRect();
    const vw = window.innerWidth;
    const vh = window.innerHeight;

    let top = btnRect.bottom + 10;
    let left = btnRect.left + btnRect.width / 2 - tipRect.width / 2;

    left = Math.max(12, Math.min(left, vw - tipRect.width - 12));

    if (top + tipRect.height + 12 > vh) {
      top = btnRect.top - tipRect.height - 10;
      tip.classList.add('is-above');
    }

    top = Math.max(8, top);

    tip.style.top = ${top}px;
    tip.style.left = ${left}px;

    const arrowCenter = btnRect.left + btnRect.width / 2 - left;
    tip.style.setProperty('--arrow-x', ${arrowCenter}px);

    tip.style.visibility = prevVis || '';
  }

  function hardStopEvent(e) {
    e.preventDefault();
    e.stopPropagation();
    if (typeof e.stopImmediatePropagation === 'function') {
      e.stopImmediatePropagation();
    }
  }

  document.addEventListener(
    'pointerdown',
    (e) => {
      const btn = e.target && e.target.closest ? e.target.closest('[data-js-addon-info-button]') : null;
      if (!btn || !isBestsellerInfoButton(btn)) return;
      hardStopEvent(e);
    },
    true
  );

  document.addEventListener(
    'mousedown',
    (e) => {
      const btn = e.target && e.target.closest ? e.target.closest('[data-js-addon-info-button]') : null;
      if (!btn || !isBestsellerInfoButton(btn)) return;
      hardStopEvent(e);
    },
    true
  );

  document.addEventListener(
    'click',
    (e) => {
      const btn = e.target && e.target.closest ? e.target.closest('[data-js-addon-info-button]') : null;
      if (!btn || !isBestsellerInfoButton(btn)) return;

      const tip = getTipFromButton(btn);
      if (!tip) return;

      hardStopEvent(e);

      try {
        btn.blur();
      } catch (err) {}

      const wasOpen = tip.classList.contains('is-open');
      closeAllTipsEverywhere();
      if (wasOpen) return;

      openTipForButton(btn, tip);
      setTimeout(() => openTipForButton(btn, tip), 0);
      setTimeout(() => openTipForButton(btn, tip), 50);
      setTimeout(() => openTipForButton(btn, tip), 150);
    },
    true
  );
})();

Quii il css

/* =======================================================================
   Add-on products (CALLOUT)
   Standalone CSS for callout cards
   Includes: rows, selection, price colors, tooltip
   ======================================================================= */

/* -----------------------------------------------------------------------
   BASE (shared class names)
   Keep generic styles minimal; callout-specific behavior is namespaced below.
   ----------------------------------------------------------------------- */

/* Base container */
.AddOnProducts {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 0;
  width: 100%;
  margin-bottom: 10px;
  box-sizing: border-box;
}

/* Title above add-ons (per product card) */
.AddOnProducts__Heading {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 12px;
  line-height: 20px;
  font-weight: 400;
  color: #5E5E5E;
  margin: 0;
}

.AddOnProducts__List {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  box-sizing: border-box;
}

/* Hide + near price when selected */
.AddOnItem.is-selected .AddOnItem__PricePlus {
  display: none;
}

/* Single row */
.AddOnItem {
  width: 100%;
  border: 1px solid #eeeeee;
  border-radius: 5px;
  background: #ffffff;
  overflow: hidden;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
  box-sizing: border-box;
}

.AddOnItem.is-selected {
  border-width: 2px;
  border-color: #125c46;
}

.AddOnItem__Label {
  cursor: pointer;
  display: block;
}

/* Inner layout (DEFAULT = 5 columns) */
.AddOnItem__Inner {
  display: grid;
  grid-template-columns: 24px max-content 18px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  height: 46px;
  box-sizing: border-box;
}

/* Selector */
.AddOnItem__Selector {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  position: relative;
}

.AddOnItem__Checkbox {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* Fake icon */
.AddOnItem__Mark {
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  flex: 0 0 20px;
}

.AddOnItem__MarkPlus {
  width: 20px;
  height: 20px;
  border-radius: 999px;
  border: 1px solid #181818;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  font-size: 14px;
  line-height: 1;
  color: #181818;
  background: #fff;
}

/* Check SVG hidden by default */
.AddOnItem__MarkCheck {
  display: none;
  width: 20px;
  height: 20px;
}

/* Selected: hide +, show check */
.AddOnItem.is-selected .AddOnItem__MarkPlus { display: none; }
.AddOnItem.is-selected .AddOnItem__MarkCheck { display: block; }

/* Content */
.AddOnItem__Content {
  min-width: 0;
  max-width: 260px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
}

.AddOnItem__Title {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 400;
  color: #181818;
  margin: 0;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.AddOnItem__Footnote {
  font-size: 12px;
  line-height: 1;
  font-weight: 400;
  color: inherit;
  margin-left: 2px;
}

.AddOnItem__Subline {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 12px;
  line-height: 15px;
  font-weight: 400;
  color: #6b6b6b;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Info icon column */
.AddOnItem__InfoBtn {
  width: 18px;
  height: 18px;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 18px;
}

.AddOnItem__InfoIcon {
  width: 17px;
  height: 17px;
  display: block;
}

/* When no info, keep spacing consistent */
.AddOnItem__InfoSpacer {
  width: 18px;
  height: 18px;
  display: block;
}

/* Price */
.AddOnItem__Price {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  white-space: nowrap;
}

/* Discount -> green */
.AddOnItem.is-discounted .AddOnItem__CurrentPrice {
  color: #125c46;
}

.AddOnItem__CompareAt {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  color: #8a8a8a;
  text-decoration: line-through;
}

.AddOnItem__CurrentPrice {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  color: #5e5e5e;
}

/* Selected (non-discount) should be black */
.AddOnItem.is-selected:not(.is-discounted) .AddOnItem__CurrentPrice {
  color: #181818;
}

/* ---------------- Tooltip (question + answer) ---------------- */
.AddOnTip {
  display: none;
  position: absolute;
  z-index: 10000;
  width: min(360px, calc(100vw - 24px));
  opacity: 0;
  pointer-events: none;
  transform: translateY(4px);
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.AddOnTip.is-open {
  display: block;
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.AddOnTip__Inner {
  background: #fff;
  border: 1px solid #e5e5e5;
  border-radius: 8px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
  overflow: hidden;
}

.AddOnTip__Header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border-bottom: 1px solid #e5e5e5;
}

.AddOnTip__Title {
  margin: 0;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  font-weight: 700;
  color: #181818;
}

.AddOnTip__Close {
  border: none;
  background: transparent;
  box-shadow: none;
  outline: none;
  font-size: 22px;
  line-height: 1;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #181818;
}

.AddOnTip__Close:focus { outline: none; }
.AddOnTip__Close:focus-visible {
  outline: 2px solid #125c46;
  outline-offset: 2px;
}

.AddOnTip__Body {
  padding: 10px 12px 12px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  color: #181818;
}

.AddOnTip__Body p {
  margin: 0;
  font-size: 16px;
}

/* Arrow */
.AddOnTip__Arrow {
  position: absolute;
  left: var(--arrow-x, 50%);
  top: -6px;
  width: 12px;
  height: 12px;
  transform: translateX(-50%) rotate(45deg);
  background: #fff;
  border-left: 1px solid #e5e5e5;
  border-top: 1px solid #e5e5e5;
}

.AddOnTip.is-above .AddOnTip__Arrow {
  top: auto;
  bottom: -6px;
  transform: translateX(-50%) rotate(225deg);
}

/* =======================================================================
   CALLOUT OVERRIDES (namespaced)
   ======================================================================= */

.SaftkurCallout--Adaptation .SaftkurCallout__product-card,
.SaftkurCallout--Adaptation .SaftkurCallout__product-card--center,
.SaftkurCallout--Adaptation .SaftkurCallout__product-card--top,
.SaftkurCallout--Adaptation .SaftkurCallout__product-card--bottom {
  overflow: visible !important;
  height: auto !important;
  min-height: 0 !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__product-card--center {
  display: flex !important;
  flex-direction: column !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__product-card--center > div[id^="saftkur-callout-price-"] {
  order: 1;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout {
  order: 2;
  display: flex !important;
  width: 100% !important;
  max-width: 100% !important;
  margin: 0 !important;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnProducts__Heading {
  margin-top: 6px;
  margin-bottom: 2px;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnItem {
  width: 100% !important;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnItem__Inner {
  padding: 0 10px !important;
  gap: 8px !important;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnItem__Content {
  max-width: none !important;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnItem__Title {
  font-size: 13px;
  line-height: 18px;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnItem__Subline {
  font-size: 12px;
  line-height: 14px;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnItem__CurrentPrice {
  font-size: 13px;
  line-height: 18px;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnItem__Price {
  gap: 6px;
}

.SaftkurCallout--Adaptation .AddOnProducts--Callout .AddOnProducts__List {
  margin-top: 2px;
}

/* =======================================================================
   PRICE META FIX (CALL OUT)
   - "inkl. MwSt. zzgl. Versand" + "14.50€ / l" on SAME row
   ======================================================================= */

.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .price__container{
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: flex-start !important;
  column-gap: 10px !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .price__regular,
.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .price__sale{
  flex: 0 0 100% !important;
  width: 100% !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .card__meta{
  flex: 0 0 auto !important;
  width: auto !important;
  max-width: 100% !important;
  margin: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .price__taxNotice{
  display: inline !important;
  white-space: nowrap !important;
  line-height: 1.2 !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .unit-price{
  flex: 0 0 auto !important;
  width: auto !important;
  margin: 0 !important;
  display: inline-flex !important;
  align-items: center !important;
  white-space: nowrap !important;
  opacity: 0.85;
}

.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .unit-price.caption{
  margin: 0 !important;
  padding: 0 !important;
}

.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .unit-price *,
.SaftkurCallout--Adaptation .SaftkurCallout__PriceWrap .price .card__meta *{
  white-space: inherit;
}

/* =======================================================================
   OPTIONAL: overlay safety
   ======================================================================= */

.AddOnOverlay {
  display: none;
}

.AddOnOverlay.is-open {
  display: block;
}

.AddOnItem__Selector { position: relative !important; }

.AddOnItem__Checkbox {
  position: absolute !important;
  top: 0 !important;
  left: 0 !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

.AddOnTip{
  top: 0;
  left: 0;
}

.AddOnTip__Header,
.AddOnTip__Close,
.AddOnTip * {
  outline: none !important;
}

.AddOnTip__Header {
  tabindex: unset !important;
}

/* =========================================================
   ADD-ON price when CART discount is active
   ========================================================= */

.AddOnItem__CurrentPrice {
  display: inline-flex;
  align-items: center;
  gap: 0;
}

.AddOnItem__CurrentValue {
  display: inline;
}

.AddOnItem__DiscountedPrice {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  color: #125c46;
  white-space: nowrap;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CompareAt {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__PricePlus {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentPrice {
  color: #8a8a8a !important;
  font-weight: 400 !important;
  text-decoration: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentValue {
  text-decoration: line-through;
}

.AddOnItem.is-cart-discount-active .AddOnItem__DiscountedPrice[hidden] {
  display: none !important;
}

/* Product cart discount UI */
.SaftkurCallout__PriceOriginal {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 16px;
  line-height: 24px;
  font-weight: 400;
  color: #8a8a8a;
  text-decoration: line-through;
  white-space: nowrap;
  margin-top: 1px;
}

.SaftkurCallout__PriceOriginal[hidden] {
  display: none !important;
}

.SaftkurCallout__DiscountPill[hidden] {
  display: none !important;
}

/* =========================================================
   NEW FIX: main product cart-discount layout
   - hide custom placeholder old price
   - use theme old price inside .price__sale
   - keep badge attached to price row
   - avoid initial flash before JS hydration
   - move price-per-day next to discounted price
   ========================================================= */

.SaftkurCallout__PriceOriginal {
  display: none !important;
}

.SaftkurCallout__PriceRow {
  display: block !important;
  width: auto !important;
}

.SaftkurCallout__PriceWrap {
  display: block !important;
}

/* prevent flash of regular block before JS decides the final state */
.SaftkurCallout__product-card.is-price-loading .SaftkurCallout__PriceWrap .price__regular {
  display: none !important;
}

/* while discount is active, regular block must stay hidden */
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price__regular {
  display: none !important;
}

/* NO DISCOUNT: show only regular, hide sale */
.SaftkurCallout__product-card:not(.is-cart-discount-active):not(.is-price-loading) .SaftkurCallout__PriceWrap .price__sale {
  display: none !important;
}

.SaftkurCallout__product-card:not(.is-cart-discount-active):not(.is-price-loading) .SaftkurCallout__PriceWrap .price__regular {
  display: block !important;
  width: auto !important;
}

/* NO DISCOUNT: regular price must be black and NOT crossed */
.SaftkurCallout__product-card:not(.is-cart-discount-active) .SaftkurCallout__PriceWrap .price__regular .price-item--regular,
.SaftkurCallout__product-card:not(.is-cart-discount-active) .SaftkurCallout__PriceWrap .price .price__regular .price-item,
.SaftkurCallout__product-card:not(.is-cart-discount-active) .SaftkurCallout__PriceWrap .price .price-item--regular {
  color: #181818 !important;
  text-decoration: none !important;
  font-weight: 700 !important;
}

/* DISCOUNT: sale row = old price + new price + per-day + badge */
.SaftkurCallout__PriceWrap .price__sale {
  display: inline-flex !important;
  align-items: center !important;
  gap: 6px !important;
  flex-wrap: nowrap !important;
}

/* old price from theme */
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price__sale .price-item--regular,
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price .price-item.price-item--regular {
  color: #8a8a8a !important;
  text-decoration: line-through !important;
  font-weight: 400 !important;
}

/* discounted/current price */
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price__sale .price-item--sale,
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price__sale .price-item--sale.price-item--last,
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price .price-item--sale,
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price .price-item--sale.price-item--last {
  color: #125c46 !important;
  font-weight: 700 !important;
}

/* when moved into sale row, keep per-day inline and aligned */
.SaftkurCallout__product-card.is-cart-discount-active .SaftkurCallout__PriceWrap .price__sale .SaftkurCallout__price-per-day {
  display: inline !important;
  margin: 0 !important;
  white-space: nowrap !important;
  color: #181818 !important;
}

/* NO DISCOUNT: per-day next to regular price */
.SaftkurCallout__product-card:not(.is-cart-discount-active) .SaftkurCallout__PriceWrap .price__regular .SaftkurCallout__price-per-day {
  display: inline !important;
  margin: 0 !important;
  white-space: nowrap !important;
  color: #181818 !important;
}

/* badge attached to sale row */
.SaftkurCallout__DiscountPill {
  display: inline-flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  padding: 3px 9px;
  gap: 2px;
  height: 18px;
  background: #D5841B;
  border-radius: 30px;
  font-family: BrandonTextWeb, sans-serif;
  font-weight: 700;
  font-size: 12px;
  line-height: 14px;
  color: #FFFFFF;
  white-space: nowrap;
  margin: 0 !important;
  vertical-align: middle;
}

Ragionato per 11s
Perfetto — qui sotto ti restituisco tutti i file completi per la PDP, già pronti da copiare e incollare.

Ho applicato solo questa modifica:

sotto al prezzo dell’add-on compare il dettaglio prezzo del prodotto

usa addon_variant.unit_price + addon_variant.unit_price_measurement

se il dato non esiste, non mostra nulla

non ho toccato le logiche JS esistenti

ho solo aggiornato snippet + CSS

il JS te lo lascio completo identico, così puoi fare copia/incolla senza pensieri

1) CSS completo
/* Add-on products container (PDP) */
.AddOnProducts {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 0;
  gap: 8px;
  width: 100%;
  margin-bottom: 10px;
  box-sizing: border-box;
}

.AddOnProducts__Heading {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 20px;
  font-weight: 400;
  color: #181818;
  margin: 0;
}

.AddOnProducts__List {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  box-sizing: border-box;
}

/* Nascondi + vicino al prezzo quando selezionato */
.AddOnItem.is-selected .AddOnItem__PricePlus {
  display: none;
}

/* Single row */
.AddOnItem {
  width: 100%;
  border: 1px solid #eeeeee;
  border-radius: 5px;
  background: #ffffff;
  overflow: hidden;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
  box-sizing: border-box;
}

.AddOnItem.is-selected {
  border-width: 2px;
  border-color: #125c46;
}

.AddOnItem__Label {
  cursor: pointer;
  display: block;
}

/* Inner layout: selector | content | info | price */
.AddOnItem__Inner {
  display: grid;
  grid-template-columns: 24px max-content 18px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  min-height: 46px;
  box-sizing: border-box;
}

/* Selector */
.AddOnItem__Selector {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  position: relative;
}

.AddOnItem__Checkbox {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* Fake icon */
.AddOnItem__Mark {
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  flex: 0 0 20px;
}

.AddOnItem__MarkPlus {
  width: 20px;
  height: 20px;
  border-radius: 999px;
  border: 1px solid #181818;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  font-size: 14px;
  line-height: 1;
  color: #181818;
  background: #fff;
}

/* Check SVG nascosto di default */
.AddOnItem__MarkCheck {
  display: none;
  width: 20px;
  height: 20px;
}

/* Selected: nascondi +, mostra SVG */
.AddOnItem.is-selected .AddOnItem__MarkPlus {
  display: none;
}

.AddOnItem.is-selected .AddOnItem__MarkCheck {
  display: block;
}

/* Content */
.AddOnItem__Content {
  min-width: 0;
  max-width: 260px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
}

.AddOnItem__Title {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 400;
  color: #181818;
  margin: 0;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.AddOnItem__Footnote {
  font-size: 12px;
  line-height: 1;
  font-weight: 400;
  color: inherit;
  margin-left: 2px;
}

.AddOnItem__Subline {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 12px;
  line-height: 15px;
  font-weight: 400;
  color: #6b6b6b;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Info icon column */
.AddOnItem__InfoBtn {
  width: 18px;
  height: 18px;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 18px;
}

.AddOnItem__InfoIcon {
  width: 16px;
  height: 16px;
  display: block;
}

/* When no info, keep spacing consistent */
.AddOnItem__InfoSpacer {
  width: 18px;
  height: 18px;
  display: block;
}

/* Price */
.AddOnItem__PriceWrap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  min-width: max-content;
}

.AddOnItem__Price {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  white-space: nowrap;
}

.AddOnItem__PriceDetail {
  margin-top: 2px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 10px;
  line-height: 12px;
  font-weight: 400;
  color: #8a8a8a;
  white-space: nowrap;
  text-align: right;
}

.AddOnItem.is-discounted .AddOnItem__CurrentPrice {
  color: #125c46;
}

.AddOnItem__CompareAt {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  color: #8a8a8a;
  text-decoration: line-through;
}

.AddOnItem__CurrentPrice {
  display: inline-flex;
  align-items: center;
  gap: 0;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  color: #5E5E5E;
}

.AddOnItem__CurrentValue {
  display: inline;
}

/* Selected (non-discount) should be black */
.AddOnItem.is-selected:not(.is-discounted) .AddOnItem__CurrentPrice {
  color: #181818;
}

.AddOnItem__DiscountedPrice {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  color: #125c46;
  white-space: nowrap;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CompareAt {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__PricePlus {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentPrice {
  color: #8a8a8a !important;
  font-weight: 400 !important;
  text-decoration: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentValue {
  text-decoration: line-through;
}

.AddOnItem.is-cart-discount-active .AddOnItem__DiscountedPrice[hidden] {
  display: none !important;
}

/* Overlay + modal (legacy) */
.AddOnOverlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 9998;
}

.AddOnOverlay.is-open {
  opacity: 1;
  pointer-events: auto;
}

.AddOnModal {
  position: fixed;
  left: 50%;
  top: 50%;
  width: min(520px, calc(100vw - 32px));
  transform: translate(-50%, -50%);
  background: #fff;
  border-radius: 10px;
  border: 1px solid #e5e5e5;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.22);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 9999;
}

.AddOnModal.is-open {
  opacity: 1;
  pointer-events: auto;
}

.AddOnModal__Header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 14px 10px;
  border-bottom: 1px solid #eee;
}

.AddOnModal__Title {
  margin: 0;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 20px;
  font-weight: 700;
  color: #181818;
}

.AddOnModal__Close {
  border: none;
  background: transparent;
  cursor: pointer;
  padding: 6px;
  line-height: 1;
  font-size: 18px;
}

.AddOnModal__Body {
  padding: 12px 14px 14px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  color: #181818;
}

html.AddonModalOpen {
  overflow: hidden;
}

/* ---------------- NEW Tooltip (question + answer) ---------------- */
.AddOnTip {
  position: absolute;
  z-index: 10000;
  width: min(360px, calc(100vw - 24px));
  opacity: 0;
  pointer-events: none;
  transform: translateY(4px);
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.AddOnTip.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.AddOnTip__Inner {
  background: #fff;
  border: 1px solid #E5E5E5;
  border-radius: 8px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
  overflow: hidden;
}

.AddOnTip__Header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border-bottom: 1px solid #E5E5E5;
}

.AddOnTip__Title {
  margin: 0;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  font-weight: 700;
  color: #181818;
}

.AddOnTip__Close {
  border: none;
  background: transparent;
  box-shadow: none;
  outline: none;
  font-size: 22px;
  line-height: 1;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #181818;
}

.AddOnTip__Close:focus {
  outline: none;
}
.AddOnTip__Close:focus-visible {
  outline: 2px solid #125c46;
  outline-offset: 2px;
}

.AddOnTip__Body {
  padding: 10px 12px 12px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  color: #181818;
}

.AddOnTip__Body p { margin: 0; font-size:16px; }

.AddOnTip__Arrow {
  position: absolute;
  left: var(--arrow-x, 50%);
  top: -6px;
  width: 12px;
  height: 12px;
  transform: translateX(-50%) rotate(45deg);
  background: #fff;
  border-left: 1px solid #E5E5E5;
  border-top: 1px solid #E5E5E5;
}

.AddOnTip.is-above .AddOnTip__Arrow {
  top: auto;
  bottom: -6px;
  transform: translateX(-50%) rotate(225deg);
}

/* =========================================================
   PDP main price cart-discount UI
   ========================================================= */

.AddOnProducts__MainPriceRow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
}

.AddOnProducts__MainPriceOriginal {
  color: #8a8a8a;
  text-decoration: line-through;
  font-weight: 400;
  white-space: nowrap;
}

.AddOnProducts__MainPriceDiscounted {
  color: #125c46;
  font-weight: 700;
  white-space: nowrap;
}

.AddOnProducts__MainPriceOriginal[hidden],
.AddOnProducts__MainPriceDiscounted[hidden] {
  display: none !important;
}
2) JS completo
/**
 * Add-on products (CALLOUT) - merge add-ons into SAME cart request + reliable deselection sync
 * + Tooltip (question + answer) via AddOnTip
 *
 * FIX (Search jump / weird behavior):
 * - Do NOT run outside-click cleanup in capture phase (prevents interfering with <summary>/<details> search)
 * - Ignore clicks/focus inside header/search UI
 * - Keep only ONE global listener set
 *
 * EXTRA FIX (discount code input on PDP / cart drawer):
 * - Do NOT interfere with cart drawer / cart notification / discount code UI
 * - Do NOT use global focusin cleanup (can break coupon input focus)
 *
 * EXTRA FIX (PDP main price discount UI):
 * - show original main price striked
 * - show discounted main price
 *
 * EXTRA FIX:
 * - add-ons must NOT change main product price
 *
 * EXTRA FIX (scroll jump):
 * - closed tooltips are fully non-focusable (hidden + aria-hidden + inert)
 * - guard against external accessibility scripts forcing focus into closed tips
 */

(function () {
  const SELECTORS = {
    container: '[data-js-addon-container]',
    item: '[data-js-addon-item]',
    checkbox: 'input[type="checkbox"][data-addon-variant-id]',
    infoBtn: '[data-js-addon-info-button]',
    modal: '[data-js-addon-modal]',
    modalClose: '[data-js-addon-modal-close]',
    overlay: '[data-js-addon-overlay]',
    tip: '[data-js-addon-tip]',
    tipClose: '[data-js-addon-tip-close]',
  };

  const STORAGE_KEY = 'lf_pending_addons_merge_callout_v1';
  const CART_CHANGED_EVENT = 'lf:cart-changed';

  const CART_MUT_RE = /\/cart\/(add|change|update|clear)(\.js)?(\?|$)/i;
  const CART_ADD_RE = /\/cart\/add(\.js)?(\?|$)/i;

  const HEADER_SEARCH_SELECTOR = [
    'sticky-header',
    '.header-wrapper',
    'header',
    'details-modal',
    '.header__search',
    '.search-modal',
    '.modal__toggle',
    '.modal-overlay',
    'predictive-search',
    '[data-predictive-search]',
    '#Search-In-Modal',
    'input[type="search"]',
    '.search__input',
    '.field__input',
    '.LIV-547-searchbar',
    '.LIV-547-searchbar-mobile',
  ].join(',');

  const PROTECTED_UI_SELECTOR = [
    HEADER_SEARCH_SELECTOR,
    'cart-drawer',
    '#CartDrawer',
    '.cart-drawer',
    '.drawer',
    '.drawer__inner',
    '.drawer__header',
    '.drawer__content',
    '.drawer__footer',
    'cart-notification',
    '.cart-notification',
    '.cart-notification-wrapper',
    '.cart-count-bubble',
    'cart-items',
    '.cart-items',
    '.totals',
    '.cart__footer',
    '.cart__blocks',
    '.cart__ctas',
    '.discounts',
    '[data-discount]',
    '[data-discount-form]',
    '[name="discount"]',
    '[name="discount_code"]',
    'input[name*="discount"]',
    'input[id*="discount"]',
    'input[autocomplete="off"]',
    'details',
    'summary',
    'input',
    'textarea',
    'select',
    'button',
    'label',
    '[contenteditable="true"]',
  ].join(',');

  function isInHeaderOrSearch(el) {
    try {
      return !!(el && el.closest && el.closest(HEADER_SEARCH_SELECTOR));
    } catch (e) {
      return false;
    }
  }

  function isInProtectedUi(el) {
    try {
      return !!(el && el.closest && el.closest(PROTECTED_UI_SELECTOR));
    } catch (e) {
      return false;
    }
  }

  function toInt(val, fallback = 0) {
    const n = parseInt(String(val ?? '').replace(/[^\d-]/g, ''), 10);
    return Number.isFinite(n) ? n : fallback;
  }

  function formatMoney(cents, moneyFormat) {
    try {
      if (window.Shopify && typeof window.Shopify.formatMoney === 'function') {
        return window.Shopify.formatMoney(cents, moneyFormat);
      }
    } catch (e) {}
    const amount = (cents / 100).toFixed(2).replace('.', ',');
    return amount + ' €';
  }

  async function fetchCart() {
    const res = await fetch('/cart.js', { credentials: 'same-origin' });
    if (!res.ok) throw new Error('Failed to load cart');
    return res.json();
  }

  function getMoneyFormat(container) {
    return container.getAttribute('data-money-format') || '${{amount}}';
  }

  function getBasePrice(container) {
    return toInt(container.getAttribute('data-base-price'), 0);
  }

  function setBasePrice(container, cents) {
    container.setAttribute('data-base-price', String(toInt(cents, 0)));
  }

  function getPriceTarget(container) {
    const targetId = container.getAttribute('data-price-target-id');
    if (targetId) return document.getElementById(targetId);

    const sectionId = container.getAttribute('data-section-id');
    if (sectionId) return document.getElementById(`price-${sectionId}`);

    return null;
  }

  function findThemePriceNodes(priceRoot) {
    if (!priceRoot) {
      return {
        regular: null,
        saleCurrent: null,
        saleCompare: null,
        fallback: null,
      };
    }

    const regular =
      priceRoot.querySelector('.price__regular .price-item--regular') ||
      priceRoot.querySelector('.price__regular .price-item') ||
      priceRoot.querySelector('.price-item--regular');

    const saleCurrent =
      priceRoot.querySelector('.price__sale .price-item--sale.price-item--last') ||
      priceRoot.querySelector('.price__sale .price-item--sale') ||
      priceRoot.querySelector('.price-item--sale.price-item--last') ||
      priceRoot.querySelector('.price-item--sale');

    const saleCompare =
      priceRoot.querySelector('.price__sale .price-item--regular') ||
      null;

    const fallback =
      saleCurrent ||
      regular ||
      priceRoot.querySelector('.price-item') ||
      priceRoot.querySelector('.price') ||
      priceRoot;

    return { regular, saleCurrent, saleCompare, fallback };
  }

  function getStablePriceContainer(priceRoot) {
    if (!priceRoot) return null;
    return (
      priceRoot.querySelector(':scope > .price') ||
      priceRoot.querySelector('.price') ||
      priceRoot.querySelector('.price__container') ||
      priceRoot
    );
  }

  function getOrCreateMainPriceUi(priceRoot) {
    if (!priceRoot) return {};

    let host = priceRoot.querySelector(':scope > .AddOnProducts__MainPriceRow');
    if (!host) {
      const stableContainer = getStablePriceContainer(priceRoot);

      host = document.createElement('span');
      host.className = 'AddOnProducts__MainPriceRow';
      host.setAttribute('data-js-main-price-ui', 'true');
      host.hidden = true;

      if (stableContainer && stableContainer !== priceRoot && stableContainer.parentNode === priceRoot) {
        priceRoot.insertBefore(host, stableContainer);
      } else {
        priceRoot.prepend(host);
      }
    }

    let original = host.querySelector('.AddOnProducts__MainPriceOriginal');
    if (!original) {
      original = document.createElement('span');
      original.className = 'AddOnProducts__MainPriceOriginal';
      original.hidden = true;
      host.appendChild(original);
    }

    let discounted = host.querySelector('.AddOnProducts__MainPriceDiscounted');
    if (!discounted) {
      discounted = document.createElement('span');
      discounted.className = 'AddOnProducts__MainPriceDiscounted';
      discounted.hidden = true;
      host.appendChild(discounted);
    }

    return { host, original, discounted };
  }

  function updateSelectedUI(container) {
    container.querySelectorAll(SELECTORS.item).forEach((row) => {
      const cb = row.querySelector(SELECTORS.checkbox);
      row.classList.toggle('is-selected', !!(cb && cb.checked));
    });
  }

  function getSessionDiscount() {
    try {
      var code = null;

      var cookieMatch = document.cookie
        .split('; ')
        .find(function (row) { return row.startsWith('discount_code='); });
      if (cookieMatch) code = cookieMatch.split('=')[1];

      if (!code) {
        var raw = sessionStorage.getItem('scDiscountData');
        if (raw) {
          var parsed = JSON.parse(raw);
          if (parsed && parsed.code) code = parsed.code;
        }
      }

      if (!code) return null;

      var codeValues = window.discountCodeValues;
      if (codeValues) {
        var lowerCode = code.toLowerCase();
        for (var key in codeValues) {
          if (key.toLowerCase() === lowerCode && codeValues[key] > 0) {
            var pct = codeValues[key] * 100;
            return { active: true, factor: 1 - codeValues[key], pct: window.roundDiscount(pct) };
          }
        }
      }

      if (typeof discountApplyPopupsObj !== 'undefined' && Array.isArray(discountApplyPopupsObj)) {
        var lc = code.toLowerCase();
        for (var i = 0; i < discountApplyPopupsObj.length; i++) {
          var obj = discountApplyPopupsObj[i];
          if (obj.discount && obj.discount.toLowerCase() === lc && parseFloat(obj.discountValue) > 0) {
            var pctVal = parseFloat(obj.discountValue);
            return { active: true, factor: 1 - pctVal / 100, pct: window.roundDiscount(pctVal) };
          }
        }
      }
    } catch (e) {}
    return null;
  }

  function getCartDiscount(cart) {
    const total = toInt(cart?.total_price, 0);
    const original = toInt(cart?.original_total_price, 0);

    if (original > 0 && total > 0 && total < original) {
      // Use the discount code's percentage value directly when available,
      // because cart-level ratio is diluted by non-discounted items (e.g. deposit)
      const items = cart?.items || [];
      for (const item of items) {
        const allocs = item.line_level_discount_allocations || [];
        for (const alloc of allocs) {
          const app = alloc.discount_application;
          if (app && app.value_type === 'percentage' && parseFloat(app.value) > 0) {
            const codePct = parseFloat(app.value);
            const codeFactor = 1 - codePct / 100;
            return { active: true, factor: codeFactor, pct: window.roundDiscount(codePct) };
          }
        }
      }

      // Fallback: calculate from cart totals (fixed_amount discounts or other cases)
      const factor = total / original;
      const pct = window.roundDiscount((1 - factor) * 100);
      return { active: true, factor, pct };
    }

    // Fallback: read discount from session/cookie when cart is empty or has no allocations
    const sessionDiscount = getSessionDiscount();
    if (sessionDiscount) return sessionDiscount;

    return { active: false, factor: 1, pct: 0 };
  }

  function updateMainPrice(container, cart) {
    const base = getBasePrice(container);

    const priceRoot = getPriceTarget(container);
    if (!priceRoot) return;

    const moneyFormat = getMoneyFormat(container);
    const ui = getOrCreateMainPriceUi(priceRoot);
    const theme = findThemePriceNodes(priceRoot);

    if (!cart) {
      if (theme.regular) theme.regular.textContent = formatMoney(base, moneyFormat);
      if (theme.saleCurrent) theme.saleCurrent.textContent = formatMoney(base, moneyFormat);
      if (theme.saleCompare) theme.saleCompare.textContent = formatMoney(base, moneyFormat);

      if (ui.original) {
        ui.original.hidden = true;
        ui.original.textContent = '';
      }
      if (ui.discounted) {
        ui.discounted.hidden = true;
        ui.discounted.textContent = '';
      }
      if (ui.host) ui.host.hidden = true;
      return;
    }

    const discount = getCartDiscount(cart);

    if (!discount.active) {
      if (theme.regular) theme.regular.textContent = formatMoney(base, moneyFormat);
      if (theme.saleCurrent) theme.saleCurrent.textContent = formatMoney(base, moneyFormat);
      if (theme.saleCompare) theme.saleCompare.textContent = formatMoney(base, moneyFormat);

      if (ui.original) {
        ui.original.hidden = true;
        ui.original.textContent = '';
      }
      if (ui.discounted) {
        ui.discounted.hidden = true;
        ui.discounted.textContent = '';
      }
      if (ui.host) ui.host.hidden = true;
      return;
    }

    const discountedBase = Math.round(base * discount.factor);

    if (theme.regular) theme.regular.textContent = '';
    if (theme.saleCurrent) theme.saleCurrent.textContent = '';
    if (theme.saleCompare) theme.saleCompare.textContent = '';

    if (ui.original) {
      ui.original.hidden = false;
      ui.original.textContent = formatMoney(base, moneyFormat);
    }

    if (ui.discounted) {
      ui.discounted.hidden = false;
      ui.discounted.textContent = formatMoney(discountedBase, moneyFormat);
    }

    if (ui.host) ui.host.hidden = false;
  }

  function applyDiscountToAddonRows(container, cart) {
    const discount = getCartDiscount(cart);
    const moneyFormat = getMoneyFormat(container);

    container.querySelectorAll(SELECTORS.item).forEach((row) => {
      const cb = row.querySelector(SELECTORS.checkbox);
      const priceWrap = row.querySelector('.AddOnItem__Price');
      const currentEl = row.querySelector('.AddOnItem__CurrentPrice');
      if (!cb || !priceWrap || !currentEl) return;

      let discountedEl = row.querySelector('.AddOnItem__DiscountedPrice');
      if (!discountedEl) {
        discountedEl = document.createElement('span');
        discountedEl.className = 'AddOnItem__DiscountedPrice';
        discountedEl.hidden = true;
        priceWrap.appendChild(discountedEl);
      }

      const addonCents = toInt(cb.getAttribute('data-addon-price'), 0);

      if (!discount.active || !addonCents) {
        row.classList.remove('is-cart-discount-active');
        discountedEl.hidden = true;
        discountedEl.textContent = '';
        return;
      }

      const discounted = Math.round(addonCents * discount.factor);
      row.classList.add('is-cart-discount-active');
      discountedEl.hidden = false;
      discountedEl.textContent = formatMoney(discounted, moneyFormat);
    });
  }

  function applyCartStateToUI(container, cart) {
    const inCart = new Set((cart?.items || []).map((it) => it.variant_id));

    container.querySelectorAll(SELECTORS.checkbox).forEach((cb) => {
      const vid = toInt(cb.getAttribute('data-addon-variant-id'), 0);
      cb.checked = inCart.has(vid);
    });

    updateSelectedUI(container);
    updateMainPrice(container, cart);
    applyDiscountToAddonRows(container, cart);
  }

  function createThrottled(fn, wait) {
    let t = null;
    return function () {
      if (t) return;
      t = setTimeout(() => {
        t = null;
        fn();
      }, wait);
    };
  }

  function bindCartResync(container) {
    const resync = createThrottled(async () => {
      try {
        const cart = await fetchCart();
        window.__lfAddonsLastKnownCartPdp = cart;
        applyCartStateToUI(container, cart);
      } catch (e) {}
    }, 200);

    document.addEventListener(CART_CHANGED_EVENT, resync);
    document.addEventListener('cart:updated', resync);
    document.addEventListener('cart:refresh', resync);

    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') resync();
    });
    window.addEventListener('focus', resync);
  }

  function openModal(container, id) {
    const overlay = container.querySelector(SELECTORS.overlay);
    const modal = container.querySelector(`[data-js-addon-modal="${CSS.escape(id)}"]`);
    if (overlay) overlay.classList.add('is-open');
    if (modal) modal.classList.add('is-open');
    document.documentElement.classList.add('AddonModalOpen');
  }

  function closeAllModals(container) {
    const overlay = container.querySelector(SELECTORS.overlay);
    if (overlay) overlay.classList.remove('is-open');
    container.querySelectorAll(SELECTORS.modal).forEach((m) => m.classList.remove('is-open'));

    if (document.documentElement.classList.contains('AddonModalOpen')) {
      document.documentElement.classList.remove('AddonModalOpen');
    }
  }

  function setTipClosedState(tip) {
    if (!tip) return;
    tip.classList.remove('is-open', 'is-above');
    tip.hidden = true;
    tip.setAttribute('aria-hidden', 'true');
    tip.setAttribute('inert', '');
    tip.style.top = '';
    tip.style.left = '';
    tip.style.removeProperty('--arrow-x');
  }

  function setTipOpenState(tip) {
    if (!tip) return;
    tip.hidden = false;
    tip.classList.add('is-open');
    tip.setAttribute('aria-hidden', 'false');
    tip.removeAttribute('inert');
  }

  function closeAllTips(container) {
    container.querySelectorAll(SELECTORS.tip).forEach((t) => {
      setTipClosedState(t);
    });
  }

  function closeAllTipsEverywhere() {
    document.querySelectorAll(SELECTORS.container).forEach((c) => closeAllTips(c));
  }

  function positionTip(buttonEl, tipEl) {
    if (!buttonEl || !tipEl) return;

    const btnRect = buttonEl.getBoundingClientRect();

    const wasClosed = tipEl.hidden || !tipEl.classList.contains('is-open');
    if (wasClosed) setTipOpenState(tipEl);

    const tipRect = tipEl.getBoundingClientRect();

    const vw = window.innerWidth;
    const vh = window.innerHeight;

    let top = btnRect.bottom + 10;
    let left = btnRect.left + btnRect.width / 2 - tipRect.width / 2;

    left = Math.max(12, Math.min(left, vw - tipRect.width - 12));

    if (top + tipRect.height + 12 > vh) {
      top = btnRect.top - tipRect.height - 10;
      tipEl.classList.add('is-above');
    } else {
      tipEl.classList.remove('is-above');
    }

    top = Math.max(8, top);

    tipEl.style.top = `${top + window.scrollY}px`;
    tipEl.style.left = `${left + window.scrollX}px`;

    const arrowCenter = btnRect.left + btnRect.width / 2 - left;
    tipEl.style.setProperty('--arrow-x', `${arrowCenter}px`);
  }

  function bindTipHandlers(container) {
    container.addEventListener('click', (e) => {
      const infoBtn = e.target.closest(SELECTORS.infoBtn);
      if (infoBtn && container.contains(infoBtn)) {
        e.preventDefault();
        e.stopPropagation();

        const id = infoBtn.getAttribute('data-addon-info-target');
        const tip = container.querySelector(`[data-js-addon-tip="${CSS.escape(id)}"]`);

        if (!tip) {
          if (id) openModal(container, id);
          return;
        }

        const wasOpen = !tip.hidden && tip.classList.contains('is-open');
        closeAllTipsEverywhere();

        if (!wasOpen) {
          setTipOpenState(tip);
          requestAnimationFrame(() => positionTip(infoBtn, tip));
        }
        return;
      }

      const tipClose = e.target.closest(SELECTORS.tipClose);
      if (tipClose && container.contains(tipClose)) {
        e.preventDefault();
        closeAllTips(container);
        return;
      }

      const modalClose = e.target.closest(SELECTORS.modalClose);
      if (modalClose && container.contains(modalClose)) {
        e.preventDefault();
        closeAllModals(container);
        return;
      }

      const overlay = e.target.closest(SELECTORS.overlay);
      if (overlay && container.contains(overlay)) {
        e.preventDefault();
        closeAllModals(container);
      }
    });

    container.addEventListener('mouseleave', () => {
      closeAllTips(container);
    });
  }

  function ensureGlobalOutsideHandlers() {
    if (window.__lfAddonsCalloutGlobalOutsideBoundV4) return;
    window.__lfAddonsCalloutGlobalOutsideBoundV4 = true;

    document.addEventListener('click', (e) => {
      const target = e.target;

      if (isInHeaderOrSearch(target)) return;
      if (isInProtectedUi(target)) return;

      const insideAddon = target && target.closest ? target.closest(SELECTORS.container) : null;
      if (insideAddon) return;

      closeAllTipsEverywhere();
    });

    document.addEventListener(
      'focusin',
      (e) => {
        const tip = e.target && e.target.closest ? e.target.closest(SELECTORS.tip) : null;
        if (!tip) return;

        if (tip.hidden || tip.getAttribute('aria-hidden') === 'true' || tip.hasAttribute('inert')) {
          try {
            if (document.activeElement && typeof document.activeElement.blur === 'function') {
              document.activeElement.blur();
            }
          } catch (err) {}
        }
      },
      true
    );

    window.addEventListener('resize', () => closeAllTipsEverywhere());
    window.addEventListener('scroll', () => closeAllTipsEverywhere(), { passive: true });

    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') closeAllTipsEverywhere();
    });
  }

  function writePending(payload) {
    try {
      sessionStorage.setItem(STORAGE_KEY, JSON.stringify(payload));
    } catch (e) {}
  }

  function readPending() {
    try {
      const raw = sessionStorage.getItem(STORAGE_KEY);
      if (!raw) return null;
      return JSON.parse(raw);
    } catch (e) {
      return null;
    }
  }

  function clearPending() {
    try {
      sessionStorage.removeItem(STORAGE_KEY);
    } catch (e) {}
  }

  function getSelectedAddonVariantIds(container) {
    const ids = [];
    container.querySelectorAll(SELECTORS.checkbox).forEach((cb) => {
      if (!cb.checked) return;
      const vid = toInt(cb.getAttribute('data-addon-variant-id'), 0);
      if (vid) ids.push(vid);
    });
    return ids;
  }

  function bindCheckboxUI(container) {
    container.addEventListener('change', (e) => {
      const cb = e.target && e.target.matches && e.target.matches(SELECTORS.checkbox) ? e.target : null;
      if (!cb) return;

      updateSelectedUI(container);

      if (window.__lfAddonsLastKnownCartPdp) {
        updateMainPrice(container, window.__lfAddonsLastKnownCartPdp);
        applyDiscountToAddonRows(container, window.__lfAddonsLastKnownCartPdp);
      } else {
        updateMainPrice(container, null);
      }
    });
  }

  function bindFormCapture(container) {
    const formId = container.getAttribute('data-product-form-id');
    if (!formId) return;

    const form = document.getElementById(formId);
    if (!form) return;
    if (form.__lfAddonsCaptureBoundCallout) return;
    form.__lfAddonsCaptureBoundCallout = true;

    form.addEventListener(
      'submit',
      () => {
        const addonIds = getSelectedAddonVariantIds(container);
        if (!addonIds.length) {
          clearPending();
          return;
        }

        writePending({
          createdAt: Date.now(),
          addonVariantIds: addonIds,
          parentHandle: container.getAttribute('data-parent-handle') || '',
          parentVariantId: container.getAttribute('data-parent-variant-id') || '',
        });
      },
      true
    );
  }

  function bindVariantListeners(container) {
    document.addEventListener('variant:change', (e) => {
      const v = e.detail && e.detail.variant;
      if (!v || typeof v.price === 'undefined') return;
      setBasePrice(container, v.price);

      if (window.__lfAddonsLastKnownCartPdp) {
        updateMainPrice(container, window.__lfAddonsLastKnownCartPdp);
        applyDiscountToAddonRows(container, window.__lfAddonsLastKnownCartPdp);
      } else {
        updateMainPrice(container, null);
      }
    });
  }

  function buildItemsFromFormData(fd) {
    const mainId = toInt(fd.get('id'), 0);
    const qty = toInt(fd.get('quantity'), 1) || 1;

    const properties = {};
    for (const [k, v] of fd.entries()) {
      const m = String(k).match(/^properties\[(.+)\]$/);
      if (m) properties[m[1]] = v;
    }

    const item = { id: mainId, quantity: qty };
    if (Object.keys(properties).length) item.properties = properties;

    return mainId ? [item] : [];
  }

  function buildItemsFromUrlEncoded(bodyStr) {
    const usp = new URLSearchParams(bodyStr);
    const fd = new FormData();
    for (const [k, v] of usp.entries()) fd.append(k, v);
    return buildItemsFromFormData(fd);
  }

  function tryParseJSONBody(body) {
    try {
      return JSON.parse(body);
    } catch (e) {
      return null;
    }
  }

  function dispatchCartChanged() {
    try {
      document.dispatchEvent(new CustomEvent(CART_CHANGED_EVENT));
    } catch (e) {}
  }

  function ensureNetworkPatches() {
    if (!window.__lfAddonsNetworkPatchedCalloutV1) {
      window.__lfAddonsNetworkPatchedCalloutV1 = true;

      const originalFetch = window.fetch.bind(window);

      window.fetch = async function (input, init) {
        const url = typeof input === 'string' ? input : input && input.url ? input.url : '';
        const isCartMutation = CART_MUT_RE.test(url);
        const isCartAdd = CART_ADD_RE.test(url);

        if (
          isCartAdd &&
          !window.__lfAddonsMergingNowCallout &&
          init &&
          (init.method || 'POST').toUpperCase() === 'POST'
        ) {
          const pending = readPending();
          const isFresh = pending && Date.now() - (pending.createdAt || 0) <= 60 * 1000;
          const addonIds = isFresh && Array.isArray(pending.addonVariantIds) ? pending.addonVariantIds : [];

          if (addonIds.length) {
            try {
              window.__lfAddonsMergingNowCallout = true;

              let mainItems = [];
              const headers = new Headers(init.headers || {});
              const body = init.body;

              if (body instanceof FormData) {
                mainItems = buildItemsFromFormData(body);
              } else if (typeof body === 'string') {
                const json = tryParseJSONBody(body);
                if (json && Array.isArray(json.items)) {
                  mainItems = json.items;
                } else {
                  mainItems = buildItemsFromUrlEncoded(body);
                }
              } else if (body && typeof body === 'object') {
                if (Array.isArray(body.items)) mainItems = body.items;
              }

              const items = Array.isArray(mainItems) ? [...mainItems] : [];

              const parentHandle = pending.parentHandle || '';
              const parentVariantId = pending.parentVariantId || '';

              addonIds.forEach((vid) => {
                items.push({
                  id: vid,
                  quantity: 1,
                  properties: {
                    _addon: 'true',
                    _addon_for: parentHandle,
                    _addon_for_variant: parentVariantId,
                  },
                });
              });

              clearPending();

              headers.set('Content-Type', 'application/json');

              const newInit = {
                ...init,
                headers,
                body: JSON.stringify({ items }),
              };

              const res = await originalFetch(input, newInit);
              if (res && res.ok) dispatchCartChanged();
              return res;
            } catch (e) {
              clearPending();
              window.__lfAddonsMergingNowCallout = false;
              return originalFetch(input, init);
            } finally {
              window.__lfAddonsMergingNowCallout = false;
            }
          }
        }

        const res = await originalFetch(input, init);
        if (isCartMutation && res && res.ok) dispatchCartChanged();
        return res;
      };

      const OriginalXHR = window.XMLHttpRequest;
      function PatchedXHR() {
        const xhr = new OriginalXHR();
        let _url = '';

        const originalOpen = xhr.open;
        xhr.open = function (method, url) {
          _url = String(url || '');
          return originalOpen.apply(xhr, arguments);
        };

        xhr.addEventListener('load', function () {
          try {
            if (xhr.status >= 200 && xhr.status < 300 && CART_MUT_RE.test(_url)) {
              dispatchCartChanged();
            }
          } catch (e) {}
        });

        return xhr;
      }
      window.XMLHttpRequest = PatchedXHR;
    }
  }

  async function initContainer(container) {
    ensureNetworkPatches();
    ensureGlobalOutsideHandlers();

    bindTipHandlers(container);
    bindCheckboxUI(container);
    bindFormCapture(container);
    bindVariantListeners(container);
    bindCartResync(container);

    updateSelectedUI(container);
    closeAllTips(container);

    try {
      const cart = await fetchCart();
      window.__lfAddonsLastKnownCartPdp = cart;
      applyCartStateToUI(container, cart);
    } catch (e) {
      updateMainPrice(container, null);
    }
  }

  function boot() {
    const containers = document.querySelectorAll(SELECTORS.container);
    if (!containers.length) return;
    containers.forEach((c) => initContainer(c));
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', boot);
  } else {
    boot();
  }
})();
3) Snippet completo
{%- comment -%}
  Add-on products block (PDP)
  Requirements for JS:
  - Wrapper: [data-js-addon-container] with data-section-id, data-base-price, data-money-format
  - Each item: [data-js-addon-item] + checkbox with data-addon-variant-id + data-addon-price + data-addon-compare-at
  - Info modal (legacy): data-js-addon-overlay, data-js-addon-modal="id", data-js-addon-modal-close
  - Info tooltip (new): data-js-addon-tip="id", data-js-addon-tip-close
{%- endcomment -%}

{%- liquid
  assign money_format_escaped = shop.money_format | escape
  assign base_variant = product.selected_or_first_available_variant
-%}

<div
  class="AddOnProducts"
  data-js-addon-container
  data-section-id="{{ section.id }}"
  data-money-format="{{ money_format_escaped }}"
  data-base-price="{{ base_variant.price }}"
  data-parent-handle="{{ product.handle }}"
  data-parent-variant-id="{{ base_variant.id }}"
  data-product-form-id="{{ product_form_id }}"
>
  {%- if block.settings.heading != blank -%}
    <p class="AddOnProducts__Heading">{{ block.settings.heading }}</p>
  {%- endif -%}

  <div class="AddOnProducts__List">
    {%- assign preselect = block.settings.preselect -%}

    {%- for i in (1..6) -%}
      {%- assign p_key = 'addon_' | append: i | append: '_product' -%}
      {%- assign t_key = 'addon_' | append: i | append: '_title_override' -%}
      {%- assign f_key = 'addon_' | append: i | append: '_footnote' -%}
      {%- assign s_key = 'addon_' | append: i | append: '_subline' -%}

      {%- assign info_key = 'addon_' | append: i | append: '_info' -%}
      {%- assign iq_key = 'addon_' | append: i | append: '_info_question' -%}
      {%- assign ia_key = 'addon_' | append: i | append: '_info_answer' -%}

      {%- assign addon_product = block.settings[p_key] -%}
      {%- if addon_product == blank -%}
        {%- continue -%}
      {%- endif -%}

      {%- assign addon_variant = addon_product.selected_or_first_available_variant -%}
      {%- if addon_variant == blank -%}
        {%- continue -%}
      {%- endif -%}

      {%- assign title_override = block.settings[t_key] -%}
      {%- assign footnote = block.settings[f_key] -%}
      {%- assign subline = block.settings[s_key] -%}

      {%- assign info_content_legacy = block.settings[info_key] -%}
      {%- assign info_question = block.settings[iq_key] -%}
      {%- assign info_answer = block.settings[ia_key] -%}

      {%- assign has_info = false -%}
      {%- if info_question != blank or info_answer != blank or info_content_legacy != blank -%}
        {%- assign has_info = true -%}
      {%- endif -%}

      {%- assign display_title = addon_product.title -%}
      {%- if title_override != blank -%}
        {%- assign display_title = title_override -%}
      {%- endif -%}

      {%- assign price = addon_variant.price -%}
      {%- assign compare_at = addon_variant.compare_at_price -%}
      {%- assign has_discount = false -%}
      {%- if compare_at and compare_at > price -%}
        {%- assign has_discount = true -%}
      {%- endif -%}

      {%- assign info_id = section.id | append: '-addon-' | append: i -%}
      {%- assign checked_attr = '' -%}
      {%- if preselect -%}
        {%- assign checked_attr = 'checked' -%}
      {%- endif -%}

      <div class="AddOnItem{% if preselect %} is-selected{% endif %}{% if has_discount %} is-discounted{% endif %}" data-js-addon-item>
        <label class="AddOnItem__Label">
          <div class="AddOnItem__Inner">

            <div class="AddOnItem__Selector">
              <input
                class="AddOnItem__Checkbox"
                type="checkbox"
                name="addon_variant_id"
                value="{{ addon_variant.id }}"
                data-addon-variant-id="{{ addon_variant.id }}"
                data-addon-price="{{ price }}"
                {% if has_discount %}data-addon-compare-at="{{ compare_at }}"{% endif %}
                {{ checked_attr }}
              >
              <span class="AddOnItem__Mark" aria-hidden="true">
                <span class="AddOnItem__MarkPlus">＋</span>
                <img
                  class="AddOnItem__MarkCheck"
                  src="{{ 'check-circle.svg' | asset_url }}"
                  alt=""
                  width="20"
                  height="20"
                  loading="lazy"
                >
              </span>
            </div>

            <div class="AddOnItem__Content">
              <p class="AddOnItem__Title">
                {{ display_title }}
                {%- if footnote != blank -%}
                  <span class="AddOnItem__Footnote">{{ footnote }}</span>
                {%- endif -%}
              </p>

              {%- if subline != blank -%}
                <div class="AddOnItem__Subline">{{ subline }}</div>
              {%- endif -%}
            </div>

            {%- if has_info -%}
              <button
                class="AddOnItem__InfoBtn"
                type="button"
                aria-label="Info"
                data-js-addon-info-button
                data-addon-info-target="{{ info_id }}"
              >
                <svg class="AddOnItem__InfoIcon" viewBox="0 0 19 18" fill="none" aria-hidden="true">
                  <path
                    d="M9.5 12.2V9M9.5 5.8H9.508M17.5 9C17.5 13.4183 13.9183 17 9.5 17C5.08172 17 1.5 13.4183 1.5 9C1.5 4.58172 5.08172 1 9.5 1C13.9183 1 17.5 4.58172 17.5 9Z"
                    stroke="#006750"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  />
                </svg>
              </button>
            {%- else -%}
              <span class="AddOnItem__InfoSpacer" aria-hidden="true"></span>
            {%- endif -%}

            <div class="AddOnItem__PriceWrap">
              <div class="AddOnItem__Price">
                {%- if has_discount -%}
                  <span class="AddOnItem__CompareAt" data-js-addon-compare-at>
                    {{ compare_at | money }}
                  </span>
                {%- endif -%}

                <span class="AddOnItem__CurrentPrice" data-js-addon-current>
                  <span class="AddOnItem__PricePlus" aria-hidden="true">+&nbsp;</span>
                  <span class="AddOnItem__CurrentValue">{{ price | money }}</span>
                </span>

                <span class="AddOnItem__DiscountedPrice" data-js-addon-discounted hidden></span>
              </div>

              {%- if addon_variant.unit_price_measurement and addon_variant.unit_price -%}
                <div class="AddOnItem__PriceDetail">
                  {{ addon_variant.unit_price | money }}
                  /
                  {%- if addon_variant.unit_price_measurement.reference_value != 1 -%}
                    {{ addon_variant.unit_price_measurement.reference_value }}
                  {%- endif -%}
                  {{ addon_variant.unit_price_measurement.reference_unit }}
                </div>
              {%- endif -%}
            </div>

          </div>
        </label>
      </div>

      {%- if has_info -%}
        <div class="AddOnTip" data-js-addon-tip="{{ info_id }}" role="dialog" aria-label="Info">
          <div class="AddOnTip__Arrow" aria-hidden="true"></div>

          <div class="AddOnTip__Inner">
            <div class="AddOnTip__Header">
              <p class="AddOnTip__Title">
                {{ info_question | default: display_title }}
              </p>
              <button class="AddOnTip__Close" type="button" aria-label="Close" data-js-addon-tip-close>×</button>
            </div>

            <div class="AddOnTip__Body">
              {%- if info_answer != blank -%}
                {{ info_answer }}
              {%- elsif info_content_legacy != blank -%}
                {{ info_content_legacy }}
              {%- endif -%}
            </div>
          </div>
        </div>

        <div class="AddOnModal" data-js-addon-modal="{{ info_id }}" role="dialog" aria-modal="true" aria-label="Info">
          <div class="AddOnModal__Header">
            <p class="AddOnModal__Title">{{ display_title }}</p>
            <button class="AddOnModal__Close" type="button" aria-label="Close" data-js-addon-modal-close>×</button>
          </div>
          <div class="AddOnModal__Body">
            {%- if info_content_legacy != blank -%}
              {{ info_content_legacy }}
            {%- elsif info_answer != blank -%}
              {{ info_answer }}
            {%- endif -%}
          </div>
        </div>
      {%- endif -%}

    {%- endfor -%}
  </div>

  <div class="AddOnOverlay" data-js-addon-overlay></div>
</div>
La modifica chiave qui è questa parte nuova:

<div class="AddOnItem__PriceWrap">
  <div class="AddOnItem__Price">
    ...
  </div>

  {%- if addon_variant.unit_price_measurement and addon_variant.unit_price -%}
    <div class="AddOnItem__PriceDetail">
      {{ addon_variant.unit_price | money }}
      /
      {%- if addon_variant.unit_price_measurement.reference_value != 1 -%}
        {{ addon_variant.unit_price_measurement.reference_value }}
      {%- endif -%}
      {{ addon_variant.unit_price_measurement.reference_unit }}
    </div>
  {%- endif -%}
</div>
e nel CSS:

.AddOnItem__PriceWrap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  min-width: max-content;
}

.AddOnItem__PriceDetail {
  margin-top: 2px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 10px;
  line-height: 12px;
  font-weight: 400;
  color: #8a8a8a;
  white-space: nowrap;
  text-align: right;
}
Se vuoi, nel prossimo messaggio posso prepararti anche una versione con fallback manuale tipo 1.45€ / 100 ml preso da metafield, nel caso alcuni add-on non abbiano unit_price_measurement valorizzato in Shopify.


oggi 7:25
image(90).png
il cliente mi ha chiesto un nuovo blocco, sarebbe come il precedente ma con più info.

ma non dobbiamo sostituire il vecchio semplicemente aggiungere un blocco diverso.

Dimmi quali file devo passarti cosi partiamo da li per modificare

Per aggiungere un nuovo blocco PDP separato, senza sostituire quello vecchio, passami questi file completi:

La section principale della PDP
Quella che contiene il ciclo dei blocchi, generalmente uno di questi file:

sections/main-product.liquid

sections/product-information.liquid

oppure il file equivalente del vostro tema.

Mi serve soprattutto per vedere:

il {% case block.type %}

dove viene renderizzato il blocco add-on attuale

lo {% schema %} completo con la definizione del vecchio blocco.

Lo snippet del blocco add-on attuale
Quello che mi hai già mostrato, ma passami il file originale completo, per esempio:

snippets/add-on-products.liquid

snippets/product-addons.liquid

o il nome reale.

Il CSS completo del vecchio blocco
Per esempio:

assets/component-add-on-products.css

oppure il nome reale del CSS PDP.

Il JavaScript completo del vecchio blocco
Per esempio:

assets/add-on-products.js

oppure il nome reale.

Il file che gestisce la selezione della durata
Nello screenshot ci sono i pulsanti:

3 Tage

5 Tage

7 Tage

Mi serve il Liquid o lo snippet che genera questa selezione, perché il nuovo blocco dovrà probabilmente aggiornare:

prezzi degli upgrade;

unit price;

prodotto o variante associata;

eventuale stato selezionato.

Il JavaScript che gestisce il cambio durata o variante
Cerca file che contengono eventi o stringhe come:

variant:change
variantChange
selectedVariant
product-form
product-info
option-value
Potrebbe essere:

global.js

product-info.js

product-form.js

un file custom dedicato alla Saftkur.

La parte dello schema relativa ai blocchi PDP
Se è già inclusa nella section principale non serve separatamente. Mi interessano in particolare:

il blocco add-on esistente;

il blocco della durata;

eventuali impostazioni prodotto, immagine, titolo, descrizione e preselection.

Per costruire il nuovo blocco dello screenshot
Il nuovo blocco dovrebbe probabilmente avere, per ogni upgrade:

prodotto Shopify;

immagine;

titolo personalizzato;

sottotitolo;

nota o footnote;

contenuto del popup informativo;

testo del pulsante;

eventuale selezione predefinita;

prezzo dinamico;

prezzo unitario;

collegamento alla durata selezionata;

fino a un certo numero di upgrade.

Quindi partirei creando un nuovo tipo di blocco, ad esempio:

{
  "type": "product_upgrades_v2",
  "name": "Optional upgrades v2"
}
e un nuovo snippet, ad esempio:

{% render 'product-upgrades-v2' %}
In questo modo il blocco vecchio rimane disponibile nel Theme Editor e il cliente può aggiungere il nuovo soltanto alle PDP desiderate.

Mandami per primo il file completo della section principale PDP, compreso tutto lo {% schema %}.


image(91).png
image(92).png

Pasted code(4).js
JavaScript

Pasted text (2)(1).txt
Documento
allora da ricordare avevamo quello del pdp e quello del callout che era sulla homepage.

Noi dobbiamo dmodificare quello del pdp.

Allora add on product è questo

{%- comment -%}
  Add-on products block (PDP)
{%- endcomment -%}

{%- liquid
  assign money_format_escaped = shop.money_format | escape
  assign base_variant = product.selected_or_first_available_variant

  assign lf04_days = ''
  if product.metafields.custom.duration != blank
    assign lf04_days = product.metafields.custom.duration | strip_html | strip | split: ' ' | first
  elsif product.title contains '3 Tage'
    assign lf04_days = '3'
  elsif product.title contains '5 Tage'
    assign lf04_days = '5'
  elsif product.title contains '7 Tage'
    assign lf04_days = '7'
  endif
-%}

<div
  class="AddOnProducts"
  data-js-addon-container
  data-section-id="{{ section.id }}"
  data-money-format="{{ money_format_escaped }}"
  data-base-price="{{ base_variant.price }}"
  data-parent-handle="{{ product.handle }}"
  data-parent-variant-id="{{ base_variant.id }}"
  data-product-form-id="{{ product_form_id }}"
  data-lf04-days="{{ lf04_days }}"
>
  {%- if block.settings.heading != blank -%}
    <p class="AddOnProducts__Heading">{{ block.settings.heading }}</p>
  {%- endif -%}

  <div class="AddOnProducts__List">
    {%- assign preselect = block.settings.preselect -%}

    {%- for i in (1..6) -%}
      {%- assign p_key = 'addon_' | append: i | append: '_product' -%}
      {%- assign t_key = 'addon_' | append: i | append: '_title_override' -%}
      {%- assign f_key = 'addon_' | append: i | append: '_footnote' -%}
      {%- assign s_key = 'addon_' | append: i | append: '_subline' -%}
      {%- assign info_key = 'addon_' | append: i | append: '_info' -%}
      {%- assign iq_key = 'addon_' | append: i | append: '_info_question' -%}
      {%- assign ia_key = 'addon_' | append: i | append: '_info_answer' -%}

      {%- assign addon_product = block.settings[p_key] -%}
      {%- if addon_product == blank -%}
        {%- continue -%}
      {%- endif -%}

      {%- assign addon_variant = addon_product.selected_or_first_available_variant -%}
      {%- if addon_variant == blank -%}
        {%- continue -%}
      {%- endif -%}

      {%- assign title_override = block.settings[t_key] -%}
      {%- assign footnote = block.settings[f_key] -%}
      {%- assign subline = block.settings[s_key] -%}
      {%- assign info_content_legacy = block.settings[info_key] -%}
      {%- assign info_question = block.settings[iq_key] -%}
      {%- assign info_answer = block.settings[ia_key] -%}

      {%- assign has_info = false -%}
      {%- if info_question != blank or info_answer != blank or info_content_legacy != blank -%}
        {%- assign has_info = true -%}
      {%- endif -%}

      {%- assign display_title = addon_product.title -%}
      {%- if title_override != blank -%}
        {%- assign display_title = title_override -%}
      {%- endif -%}

      {%- assign addon_label = display_title | handleize -%}
      {%- assign addon_handle = addon_product.handle -%}

      {%- assign price = addon_variant.price -%}
      {%- assign compare_at = addon_variant.compare_at_price -%}
      {%- assign has_discount = false -%}
      {%- if compare_at and compare_at > price -%}
        {%- assign has_discount = true -%}
      {%- endif -%}

      {%- assign info_id = section.id | append: '-addon-' | append: i -%}
      {%- assign checked_attr = '' -%}
      {%- if preselect -%}
        {%- assign checked_attr = 'checked' -%}
      {%- endif -%}

      <div
        class="AddOnItem{% if preselect %} is-selected{% endif %}{% if has_discount %} is-discounted{% endif %}"
        data-js-addon-item
      >
        <label class="AddOnItem__Label">
          <div class="AddOnItem__Inner">

            <div class="AddOnItem__Selector">
              <input
                class="AddOnItem__Checkbox"
                type="checkbox"
                name="addon_variant_id"
                value="{{ addon_variant.id }}"
                data-addon-variant-id="{{ addon_variant.id }}"
                data-addon-price="{{ price }}"
                data-lf04-addon-parent-days="{{ lf04_days }}"
                data-lf04-addon-product="{{ addon_handle }}"
                data-lf04-addon-label="{{ addon_label }}"
                {% if has_discount %}data-addon-compare-at="{{ compare_at }}"{% endif %}
                {{ checked_attr }}
              >
              <span class="AddOnItem__Mark" aria-hidden="true">
                <span class="AddOnItem__MarkPlus">＋</span>
                <img
                  class="AddOnItem__MarkCheck"
                  src="{{ 'check-circle.svg' | asset_url }}"
                  alt=""
                  width="20"
                  height="20"
                  loading="lazy"
                >
              </span>
            </div>

            <div class="AddOnItem__Content">
              <p class="AddOnItem__Title">
                {{ display_title }}
                {%- if footnote != blank -%}
                  <span class="AddOnItem__Footnote">{{ footnote }}</span>
                {%- endif -%}
              </p>

              {%- if subline != blank -%}
                <div class="AddOnItem__Subline">{{ subline }}</div>
              {%- endif -%}
            </div>

            {%- if has_info -%}
              <button
                class="AddOnItem__InfoBtn"
                type="button"
                aria-label="Info"
                data-js-addon-info-button
                data-addon-info-target="{{ info_id }}"
              >
                <svg class="AddOnItem__InfoIcon" viewBox="0 0 19 18" fill="none" aria-hidden="true">
                  <path
                    d="M9.5 12.2V9M9.5 5.8H9.508M17.5 9C17.5 13.4183 13.9183 17 9.5 17C5.08172 17 1.5 13.4183 1.5 9C1.5 4.58172 5.08172 1 9.5 1C13.9183 1 17.5 4.58172 17.5 9Z"
                    stroke="#006750"
                    stroke-width="2"
                    stroke-linecap="round"
                    stroke-linejoin="round"
                  />
                </svg>
              </button>
            {%- else -%}
              <span class="AddOnItem__InfoSpacer" aria-hidden="true"></span>
            {%- endif -%}

            <div class="AddOnItem__PriceWrap">
              <div class="AddOnItem__Price">
                {%- if has_discount -%}
                  <span class="AddOnItem__CompareAt" data-js-addon-compare-at>
                    {{ compare_at | money }}
                  </span>
                {%- endif -%}

                <span class="AddOnItem__CurrentPrice" data-js-addon-current>
                  <span class="AddOnItem__PricePlus" aria-hidden="true">+&nbsp;</span>
                  <span class="AddOnItem__CurrentValue">{{ price | money }}</span>
                </span>

                <span class="AddOnItem__DiscountedPrice" data-js-addon-discounted hidden></span>
              </div>

              {%- if addon_variant.unit_price_measurement and addon_variant.unit_price -%}
                <div class="AddOnItem__PriceDetail">
                  {{ addon_variant.unit_price | money }}
                  /
                  {%- if addon_variant.unit_price_measurement.reference_value != 1 -%}
                    {{ addon_variant.unit_price_measurement.reference_value }}
                  {%- endif -%}
                  {{ addon_variant.unit_price_measurement.reference_unit }}
                </div>
              {%- endif -%}
            </div>

          </div>
        </label>
      </div>

      {%- if has_info -%}
        <div class="AddOnTip" data-js-addon-tip="{{ info_id }}" role="dialog" aria-label="Info">
          <div class="AddOnTip__Arrow" aria-hidden="true"></div>
          <div class="AddOnTip__Inner">
            <div class="AddOnTip__Header">
              <p class="AddOnTip__Title">{{ info_question | default: display_title }}</p>
              <button class="AddOnTip__Close" type="button" aria-label="Close" data-js-addon-tip-close>×</button>
            </div>
            <div class="AddOnTip__Body">
              {%- if info_answer != blank -%}
                {{ info_answer }}
              {%- elsif info_content_legacy != blank -%}
                {{ info_content_legacy }}
              {%- endif -%}
            </div>
          </div>
        </div>

        <div class="AddOnModal" data-js-addon-modal="{{ info_id }}" role="dialog" aria-modal="true" aria-label="Info">
          <div class="AddOnModal__Header">
            <p class="AddOnModal__Title">{{ display_title }}</p>
            <button class="AddOnModal__Close" type="button" aria-label="Close" data-js-addon-modal-close>×</button>
          </div>
          <div class="AddOnModal__Body">
            {%- if info_content_legacy != blank -%}
              {{ info_content_legacy }}
            {%- elsif info_answer != blank -%}
              {{ info_answer }}
            {%- endif -%}
          </div>
        </div>
      {%- endif -%}

    {%- endfor -%}
  </div>

  <div class="AddOnOverlay" data-js-addon-overlay></div>
</div>

col suo js in allegato

e invece questo è il suo css

/* Add-on products container (PDP) */
.AddOnProducts {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 0;
  gap: 8px;
  width: 100%;
  margin-bottom: 10px;
  box-sizing: border-box;
}

.AddOnProducts__Heading {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 20px;
  font-weight: 400;
  color: #181818;
  margin: 0;
}

.AddOnProducts__List {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  box-sizing: border-box;
}

/* Nascondi + vicino al prezzo quando selezionato */
.AddOnItem.is-selected .AddOnItem__PricePlus {
  display: none;
}

/* Single row */
.AddOnItem {
  width: 100%;
  border: 1px solid #eeeeee;
  border-radius: 5px;
  background: #ffffff;
  overflow: hidden;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
  box-sizing: border-box;
}

.AddOnItem.is-selected {
  border-width: 2px;
  border-color: #125c46;
}

.AddOnItem__Label {
  cursor: pointer;
  display: block;
}

/* Inner layout: selector | content | info | price */
.AddOnItem__Inner {
  display: grid;
  grid-template-columns: 24px max-content 18px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  min-height: 46px;
  box-sizing: border-box;
}

/* Selector */
.AddOnItem__Selector {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  position: relative;
}

.AddOnItem__Checkbox {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* Fake icon */
.AddOnItem__Mark {
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  flex: 0 0 20px;
}

.AddOnItem__MarkPlus {
  width: 20px;
  height: 20px;
  border-radius: 999px;
  border: 1px solid #181818;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  font-size: 14px;
  line-height: 1;
  color: #181818;
  background: #fff;
}

/* Check SVG nascosto di default */
.AddOnItem__MarkCheck {
  display: none;
  width: 20px;
  height: 20px;
}

/* Selected: nascondi +, mostra SVG */
.AddOnItem.is-selected .AddOnItem__MarkPlus {
  display: none;
}

.AddOnItem.is-selected .AddOnItem__MarkCheck {
  display: block;
}

/* Content */
.AddOnItem__Content {
  min-width: 0;
  max-width: 260px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
}

.AddOnItem__Title {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 400;
  color: #181818;
  margin: 0;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.AddOnItem__Footnote {
  font-size: 12px;
  line-height: 1;
  font-weight: 400;
  color: inherit;
  margin-left: 2px;
}

.AddOnItem__Subline {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 12px;
  line-height: 15px;
  font-weight: 400;
  color: #6b6b6b;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Info icon column */
.AddOnItem__InfoBtn {
  width: 18px;
  height: 18px;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 18px;
}

.AddOnItem__InfoIcon {
  width: 16px;
  height: 16px;
  display: block;
}

/* When no info, keep spacing consistent */
.AddOnItem__InfoSpacer {
  width: 18px;
  height: 18px;
  display: block;
}

/* Price */
.AddOnItem__PriceWrap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  min-width: max-content;
}

.AddOnItem__Price {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  white-space: nowrap;
}

.AddOnItem__PriceDetail {
  margin-top: 2px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 10px;
  line-height: 12px;
  font-weight: 400;
  color: #8a8a8a;
  white-space: nowrap;
  text-align: right;
}

.AddOnItem.is-discounted .AddOnItem__CurrentPrice {
  color: #125c46;
}

.AddOnItem__CompareAt {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 12px;
  line-height: 16px;
  font-weight: 400;
  color: #8a8a8a;
  text-decoration: line-through;
}

.AddOnItem__CurrentPrice {
  display: inline-flex;
  align-items: center;
  gap: 0;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  color: #5E5E5E;
}

.AddOnItem__CurrentValue {
  display: inline;
}

/* Selected (non-discount) should be black */
.AddOnItem.is-selected:not(.is-discounted) .AddOnItem__CurrentPrice {
  color: #181818;
}

.AddOnItem__DiscountedPrice {
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  color: #125c46;
  white-space: nowrap;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CompareAt {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__PricePlus {
  display: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentPrice {
  color: #8a8a8a !important;
  font-weight: 400 !important;
  text-decoration: none !important;
}

.AddOnItem.is-cart-discount-active .AddOnItem__CurrentValue {
  text-decoration: line-through;
}

.AddOnItem.is-cart-discount-active .AddOnItem__DiscountedPrice[hidden] {
  display: none !important;
}

/* Overlay + modal (legacy) */
.AddOnOverlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 9998;
}

.AddOnOverlay.is-open {
  opacity: 1;
  pointer-events: auto;
}

.AddOnModal {
  position: fixed;
  left: 50%;
  top: 50%;
  width: min(520px, calc(100vw - 32px));
  transform: translate(-50%, -50%);
  background: #fff;
  border-radius: 10px;
  border: 1px solid #e5e5e5;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.22);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 9999;
}

.AddOnModal.is-open {
  opacity: 1;
  pointer-events: auto;
}

.AddOnModal__Header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 14px 10px;
  border-bottom: 1px solid #eee;
}

.AddOnModal__Title {
  margin: 0;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 20px;
  font-weight: 700;
  color: #181818;
}

.AddOnModal__Close {
  border: none;
  background: transparent;
  cursor: pointer;
  padding: 6px;
  line-height: 1;
  font-size: 18px;
}

.AddOnModal__Body {
  padding: 12px 14px 14px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  color: #181818;
}

html.AddonModalOpen {
  overflow: hidden;
}

/* ---------------- NEW Tooltip (question + answer) ---------------- */
.AddOnTip {
  position: absolute;
  z-index: 10000;
  width: min(360px, calc(100vw - 24px));
  opacity: 0;
  pointer-events: none;
  transform: translateY(4px);
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.AddOnTip.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.AddOnTip__Inner {
  background: #fff;
  border: 1px solid #E5E5E5;
  border-radius: 8px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
  overflow: hidden;
}

.AddOnTip__Header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border-bottom: 1px solid #E5E5E5;
}

.AddOnTip__Title {
  margin: 0;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  font-weight: 700;
  color: #181818;
}

.AddOnTip__Close {
  border: none;
  background: transparent;
  box-shadow: none;
  outline: none;
  font-size: 22px;
  line-height: 1;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #181818;
}

.AddOnTip__Close:focus {
  outline: none;
}
.AddOnTip__Close:focus-visible {
  outline: 2px solid #125c46;
  outline-offset: 2px;
}

.AddOnTip__Body {
  padding: 10px 12px 12px;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 13px;
  line-height: 18px;
  color: #181818;
}

.AddOnTip__Body p { margin: 0; font-size:16px; }

.AddOnTip__Arrow {
  position: absolute;
  left: var(--arrow-x, 50%);
  top: -6px;
  width: 12px;
  height: 12px;
  transform: translateX(-50%) rotate(45deg);
  background: #fff;
  border-left: 1px solid #E5E5E5;
  border-top: 1px solid #E5E5E5;
}

.AddOnTip.is-above .AddOnTip__Arrow {
  top: auto;
  bottom: -6px;
  transform: translateX(-50%) rotate(225deg);
}

/* =========================================================
   PDP main price cart-discount UI
   ========================================================= */

.AddOnProducts__MainPriceRow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
}

.AddOnProducts__MainPriceOriginal {
  color: #8a8a8a;
  text-decoration: line-through;
  font-weight: 400;
  white-space: nowrap;
}

.AddOnProducts__MainPriceDiscounted {
  color: #125c46;
  font-weight: 700;
  white-space: nowrap;
}

.AddOnProducts__MainPriceOriginal[hidden],
.AddOnProducts__MainPriceDiscounted[hidden] {
  display: none !important;
}


poi ti allego il file del pdp (ne lseconfo allegato)questo sarebbe il codice del pezzo in foto allegato, 

ti ho passato il css dal Figma per aiuto /* Section */

/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 24px 0px 18px;
gap: 16px;

width: 351px;
height: 331px;


/* Inside auto layout */
flex: none;
order: 4;
align-self: stretch;
flex-grow: 0;

la seconda foto è quando si clicca

Elaborato per 1m 40s
Ho mantenuto intatto il blocco PDP precedente e aggiunto un nuovo blocco separato chiamato “Optional upgrades v2”.

Il nuovo design include:

titolo superiore “OPTIONALE UPGRADES”;

descrizione configurabile;

immagine prodotto;

titolo e sottotitolo;

icona informativa con tooltip esistente;

prezzo e prezzo unitario;

pulsante + Auswählen;

stato selezionato verde ✓ Ausgewählt;

stessa logica esistente di checkbox, sincronizzazione carrello e aggiunta nello stesso /cart/add;

fino a 6 add-on configurabili;

immagine personalizzata opzionale per ciascun add-on.

La section è stata modificata partendo dal file PDP completo che mi hai passato, mentre il JavaScript mantiene integralmente la logica esistente. 

 


1. Section PDP completa modificata
Sostituisci il file attuale della section con questo:

Scarica bs-product-gallery-meta-modified.liquid

Nel tema dovrai rinominarlo con il nome reale della section attuale, presumibilmente:

sections/bs-product-gallery-meta.liquid
2. Nuovo snippet completo
Crea questo nuovo file:

snippets/add-on-products-v2.liquid
Scarica add-on-products-v2.liquid

3. Nuovo CSS completo
Crea questo nuovo asset:

assets/component-add-on-products-v2.css
component-add-on-products-v2.css

È un CSS separato e namespaced, quindi non modifica graficamente il vecchio blocco Add-on products.

4. JavaScript completo
Il JavaScript non ha richiesto modifiche: il nuovo blocco riutilizza volutamente gli stessi attributi data-js-addon-*, quindi conserva tutta la logica già presente.

Te lo lascio comunque completo, così hai tutti i file pronti:

add-on-products.js

Configurazione nel Theme Editor
Dopo aver caricato i file:

Apri il template prodotto nel Theme Editor.

Seleziona la section PDP.

Clicca su Add block.

Aggiungi Optional upgrades v2.

Configura i prodotti add-on.

Rimuovi dal template il vecchio blocco solo nelle PDP in cui vuoi mostrare il nuovo design.

Il vecchio tipo di blocco:

Add-on products
rimane disponibile e non è stato sostituito.

Il nuovo è:

Optional upgrades v2
Per ogni add-on puoi impostare prodotto, immagine alternativa, titolo, footnote, sottotitolo, domanda informativa e risposta. Se non carichi un’immagine alternativa, viene utilizzata automaticamente la featured image del prodotto.

dammeli qui in modo

Libreria
/
LiveFresh
/
component-add-on-products-v2.css


/* ======================================================================
   Add-on products V2 (PDP only)
   Separate visual design; existing Add-on products block remains intact.
   ====================================================================== */

.AddOnProducts--V2 {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  padding: 24px 0 18px;
  gap: 16px;
  margin: 0;
  box-sizing: border-box;
}

.AddOnProductsV2__Header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  width: 100%;
  margin-bottom:5px;
}

.AddOnProductsV2__Eyebrow {
  margin: 0;
  color: #125c46;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 11px;
  line-height: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.AddOnProductsV2__Heading {
  margin: 0;
  color: #181818;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 15px;
  line-height: 21px;
  font-weight: 400;
}

.AddOnProductsV2__List {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.AddOnProducts--V2 .AddOnItem--V2 {
  width: 100%;
  border: 1px solid #e5e5e5;
  border-radius: 6px;
  background: #ffffff;
  overflow: visible;
  box-sizing: border-box;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.AddOnProducts--V2 .AddOnItem--V2.is-selected {
  border-color: #125c46;
  box-shadow: inset 0 0 0 1px #125c46;
}

.AddOnItemV2__Label {
  display: block;
  width: 100%;
  cursor: pointer;
}

.AddOnItemV2__Checkbox {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.AddOnItemV2__Inner {
  display: grid;
  grid-template-columns: 68px minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 126px;
  padding: 14px;
  box-sizing: border-box;
}

.AddOnItemV2__ImageWrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 68px;
  height: 84px;
  overflow: hidden;
}

.AddOnItemV2__Image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.AddOnItemV2__Content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 5px;
  min-width: 0;
}

.AddOnItemV2__TitleRow {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
}

.AddOnItemV2__Title {
  margin: 0;
  color: #181818;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 16px;
  line-height: 21px;
  font-weight: 700;
  white-space: normal;
  overflow-wrap: anywhere;
}

.AddOnItemV2__Subline {
  margin: 0;
  color: #6b6b6b;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 14px;
  line-height: 19px;
  font-weight: 400;
  white-space: normal;
}

.AddOnItemV2__InfoBtn {
  flex: 0 0 18px;
  width: 18px;
  height: 18px;
}

.AddOnProducts--V2 .AddOnItem__InfoIcon {
  width: 16px;
  height: 16px;
}

.AddOnItemV2__Action {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  gap: 10px;
  min-width: 132px;
}

.AddOnItemV2__PriceWrap {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
}

.AddOnItemV2__Price {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  white-space: nowrap;
}

.AddOnProducts--V2 .AddOnItem__CurrentPrice,
.AddOnProducts--V2 .AddOnItem__DiscountedPrice {
  font-size: 16px;
  line-height: 20px;
  font-weight: 700;
}

.AddOnItemV2__PriceDetail {
  margin-top: 2px;
  color: #8a8a8a;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 10px;
  line-height: 12px;
  font-weight: 400;
  text-align: right;
  white-space: nowrap;
}

.AddOnItemV2__Button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 130px;
  min-height: 46px;
  padding: 10px 14px;
  border: 2px solid #125c46;
  border-radius: 5px;
  color: #125c46;
  background: #ffffff;
  box-sizing: border-box;
  font-family: BrandonTextWeb, sans-serif;
  font-size: 15px;
  line-height: 20px;
  font-weight: 700;
  transition: color 0.2s ease, background-color 0.2s ease;
}

.AddOnItemV2__ButtonDefault,
.AddOnItemV2__ButtonSelected {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  white-space: nowrap;
}

.AddOnItemV2__ButtonSelected {
  display: none;
}

.AddOnItemV2__ButtonSelected svg {
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
}

.AddOnItemV2__ButtonIcon {
  font-size: 19px;
  line-height: 1;
  font-weight: 400;
}

.AddOnProducts--V2 .AddOnItem--V2.is-selected .AddOnItemV2__Button {
  color: #ffffff;
  background: #125c46;
}

.AddOnProducts--V2 .AddOnItem--V2.is-selected .AddOnItemV2__ButtonDefault {
  display: none;
}

.AddOnProducts--V2 .AddOnItem--V2.is-selected .AddOnItemV2__ButtonSelected {
  display: inline-flex;
}

.AddOnProducts--V2 .AddOnItem--V2.is-selected .AddOnItem__PricePlus {
  display: none;
}

.AddOnProducts--V2 .AddOnItem--V2:focus-within {
  outline: 2px solid rgba(18, 92, 70, 0.25);
  outline-offset: 2px;
}

@media screen and (max-width: 749px) {
  .AddOnProducts--V2 {
    padding: 24px 0 18px;
    gap: 16px;
  }

  .AddOnProductsV2__List {
    gap: 12px;
  }

  .AddOnItemV2__Inner {
    grid-template-columns: 58px minmax(0, 1fr) auto;
    gap: 10px;
    min-height: 112px;
    padding: 12px;
  }

  .AddOnItemV2__ImageWrap {
    width: 58px;
    height: 76px;
  }

  .AddOnItemV2__Title {
    font-size: 14px;
    line-height: 19px;
  }

  .AddOnItemV2__Subline {
    font-size: 12px;
    line-height: 17px;
  }

  .AddOnItemV2__Action {
    gap: 8px;
    min-width: 118px;
  }

  .AddOnProducts--V2 .AddOnItem__CurrentPrice,
  .AddOnProducts--V2 .AddOnItem__DiscountedPrice {
    font-size: 14px;
    line-height: 18px;
  }

  .AddOnItemV2__Button {
    min-width: 116px;
    min-height: 42px;
    padding: 8px 10px;
    font-size: 13px;
    line-height: 18px;
  }
}

@media screen and (max-width: 420px) {
  .AddOnItemV2__Inner {
    grid-template-columns: 54px minmax(0, 1fr) 108px;
    gap: 8px;
    padding: 10px;
  }

  .AddOnItemV2__ImageWrap {
    width: 54px;
    height: 70px;
  }

  .AddOnItemV2__Action {
    min-width: 108px;
  }

  .AddOnItemV2__Button {
    min-width: 106px;
    padding: 8px;
  }
}
