[object Object]

← back to Designer Wallcoverings

Theme MOQ fix: custom PDP quantity reads order-min metafields (min/step/value + clamp script) — staged section + live/dev backups

0bc56eb7e5116774f218296589962466bc83514d · 2026-06-22 13:55:46 -0700 · Steve Abrams

Files touched

Diff

commit 0bc56eb7e5116774f218296589962466bc83514d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jun 22 13:55:46 2026 -0700

    Theme MOQ fix: custom PDP quantity reads order-min metafields (min/step/value + clamp script) — staged section + live/dev backups
---
 .../theme-moq/sections-product.DEV-original.liquid | 322 +++++++++++++++++
 shopify/theme-moq/sections-product.FIXED.liquid    | 380 +++++++++++++++++++++
 .../sections-product.LIVE-original.liquid          | 333 ++++++++++++++++++
 3 files changed, 1035 insertions(+)

diff --git a/shopify/theme-moq/sections-product.DEV-original.liquid b/shopify/theme-moq/sections-product.DEV-original.liquid
new file mode 100644
index 00000000..4f20d4ab
--- /dev/null
+++ b/shopify/theme-moq/sections-product.DEV-original.liquid
@@ -0,0 +1,322 @@
+{% render 'breadcrumbs' %}
+
+{% liquid
+  assign enable_zoom = section.settings.enable_zoom
+  assign enable_cart_redirection = section.settings.enable_cart_redirection
+  assign images_layout = section.settings.images_layout
+  assign enable_video_autoplay = section.settings.enable_video_autoplay
+  assign enable_video_looping = section.settings.enable_video_looping
+  assign enable_linked_options = true
+  assign show_vendor = settings.show_vendor
+  assign show_social_media_icons = section.settings.show_social_media_icons
+  assign show_payment_button = section.settings.show_payment_button
+
+  for block in section.blocks
+    if block.type == 'complementary_products'
+      assign product_recommendation_limit = block.settings.product_recommendation_limit
+      break
+    endif
+  endfor
+%}
+
+{% if images_layout == 'masonry' %}
+  {% comment %}Related products in masonry grid must be below product{% endcomment %}
+  {% assign related_products_position_right = false %}
+{% endif %}
+
+<script
+  type="application/json"
+  data-section-type="product"
+  data-section-id="{{ section.id }}"
+  data-section-data
+>
+  {
+    "product": {{ product | json }},
+    "product_settings": {
+      "addToCartText": {{ 'products.product.add_to_cart' | t | json }},
+      "enableHistory": true,
+      "processingText": {{ 'products.product.processing' | t | json }},
+      "setQuantityText": {{ 'products.product.set_quantity' | t | json }},
+      "soldOutText": {{ 'products.product.sold_out' | t | json }},
+      "unavailableText": {{ 'products.product.unavailable' | t | json }}
+    },
+    "images_layout": {{ images_layout | json }},
+    "enable_zoom": {{ enable_zoom | json }},
+    "enable_video_autoplay": {{ enable_video_autoplay | json }},
+    "enable_video_looping": {{ enable_video_looping | json }},
+    "enable_cart_redirection": {{ enable_cart_redirection | json }},
+    "enable_fixed_positioning": true,
+    "product_recommendation_limit": {{ product_recommendation_limit | json }}
+  }
+</script>
+
+{% render 'product-success-labels' %}
+<section class="product-container">
+  {%
+    render 'product',
+    product: product,
+    enable_zoom: enable_zoom,
+    images_layout: images_layout,
+    enable_linked_options: enable_linked_options,
+    show_vendor: show_vendor,
+    show_social_media_icons: show_social_media_icons,
+    show_payment_button: show_payment_button,
+  %}
+
+  <div
+    class="product-recommendations-wrapper--right"
+    data-product-recommendations-right
+  >
+  </div>
+</section>
+
+{% schema %}
+{
+  "name": "Product pages",
+  "settings": [
+    {
+      "type": "checkbox",
+      "id": "enable_cart_redirection",
+      "label": "Enable cart redirection",
+      "info": "Automatically sends users to the Cart page after adding a product.",
+      "default": false
+    },
+    {
+      "type": "checkbox",
+      "id": "show_payment_button",
+      "label": "Show dynamic checkout button",
+      "info": "Each customer will see their preferred payment method from those available on your store, such as PayPal or Apple Pay. [Learn more](https://help.shopify.com/manual/using-themes/change-the-layout/dynamic-checkout)",
+      "default": true
+    },
+    {
+      "type": "header",
+      "content": "Media"
+    },
+    {
+      "type": "paragraph",
+      "content": "Learn more about [media types](https://help.shopify.com/en/manual/products/product-media/product-media-types)"
+    },
+    {
+      "type": "select",
+      "id": "images_layout",
+      "label": "Layout",
+      "options": [
+        {
+          "label": "Slideshow",
+          "value": "slideshow"
+        },
+        {
+          "label": "List",
+          "value": "list"
+        },
+        {
+          "label": "Masonry",
+          "value": "masonry"
+        }
+      ],
+      "default": "slideshow"
+    },
+    {
+      "type": "checkbox",
+      "id": "enable_zoom",
+      "label": "Enable image zoom",
+      "info": "Zoom only works with the slideshow image layout"
+    },
+    {
+      "type": "checkbox",
+      "id": "enable_video_autoplay",
+      "label": "Enable video autoplay",
+      "default": true
+    },
+    {
+      "type": "checkbox",
+      "id": "enable_video_looping",
+      "label": "Enable video looping"
+    }
+  ],
+  "blocks": [
+    {
+      "type": "@app"
+    },
+    {
+      "type": "collapsible-tab",
+      "name": "Collapsible tab",
+      "settings": [
+        {
+          "type": "text",
+          "id": "collapsible_tab_heading",
+          "label": "Heading",
+          "default": "Collapsible tab"
+        },
+        {
+          "type": "richtext",
+          "id": "collapsible_tab_text",
+          "label": "Text",
+          "default": "<p>Use this text to share information about your product.</p>"
+        }
+      ]
+    },
+    {
+      "type": "custom-liquid",
+      "name": "Custom liquid",
+      "settings": [
+        {
+          "type": "liquid",
+          "id": "custom_liquid",
+          "label": "Custom liquid",
+          "info": "Add app snippets or other Liquid code to create advanced customizations."
+        }
+      ]
+    },
+    {
+      "type": "tabs",
+      "name": "Tabs",
+      "limit": 1,
+      "settings": [
+        {
+          "type": "checkbox",
+          "id": "show_product_description",
+          "label": "Show product description",
+          "default": false
+        },
+        {
+          "type": "header",
+          "content": "Tab"
+        },
+        {
+          "type": "text",
+          "id": "tab_heading_1",
+          "label": "Heading",
+          "default": "Tab 1"
+        },
+        {
+          "type": "richtext",
+          "id": "tab_text_1",
+          "label": "Text",
+          "default": "<p>Tab 1 content goes here.</p>"
+        },
+        {
+          "type": "header",
+          "content": "Tab"
+        },
+        {
+          "type": "text",
+          "id": "tab_heading_2",
+          "label": "Heading",
+          "default": "Tab 2"
+        },
+        {
+          "type": "richtext",
+          "id": "tab_text_2",
+          "label": "Text",
+          "default": "<p>Tab 2 content goes here.</p>"
+        },
+        {
+          "type": "header",
+          "content": "Tab"
+        },
+        {
+          "type": "text",
+          "id": "tab_heading_3",
+          "label": "Heading",
+          "default": "Tab 3"
+        },
+        {
+          "type": "richtext",
+          "id": "tab_text_3",
+          "label": "Text",
+          "default": "<p>Tab 3 content goes here.</p>"
+        }
+      ]
+    },
+    {
+      "type": "title",
+      "name": "Title",
+      "limit": 1
+    },
+    {
+      "type": "vendor",
+      "name": "Vendor",
+      "limit": 1
+    },
+    {
+      "type": "social",
+      "name": "Social",
+      "limit": 1
+    },
+    {
+      "type": "description",
+      "name": "Description",
+      "limit": 1
+    },
+    {
+      "type": "price",
+      "name": "Price",
+      "limit": 1
+    },
+    {
+      "type": "form",
+      "name": "Form",
+      "limit": 1,
+      "settings": [
+        {
+          "type": "paragraph",
+          "content": "Customize form features for the product in the products portion of the theme settings."
+        },
+        {
+          "type": "checkbox",
+          "id": "show_gift_card_recipient_form",
+          "label": "t:sections.product.blocks.form.show_gift_card_recipient_form.label",
+          "info": "t:sections.product.blocks.form.show_gift_card_recipient_form.info",
+          "default": false
+        }
+      ]
+    },
+    {
+      "type": "rating",
+      "name": "Product rating",
+      "limit": 1,
+      "settings": [
+        {
+          "type": "paragraph",
+          "content": "To display a rating, add a product rating app. [Learn more](https://apps.shopify.com/product-reviews)"
+        }
+      ]
+    },
+    {
+      "type": "complementary_products",
+      "name": "Complementary products",
+      "limit": 1,
+      "settings": [
+        {
+          "type": "paragraph",
+          "content": "To select complementary products, add the Search & Discovery app. [Learn more](https:\/\/shopify.dev\/themes\/product-merchandising\/recommendations)"
+        },
+        {
+          "type": "text",
+          "id": "heading",
+          "label": "Heading",
+          "default": "Pairs well with"
+        },
+        {
+          "type": "range",
+          "id": "product_recommendation_limit",
+          "label": "Maximum products to show",
+          "min": 1,
+          "max": 10,
+          "default": 5
+        },
+        {
+          "type": "range",
+          "id": "products_per_slide",
+          "label": "Number of products per page",
+          "min": 1,
+          "max": 3,
+          "default": 2
+        }
+      ]
+    }
+  ]
+}
+
+{% endschema %}
\ No newline at end of file
diff --git a/shopify/theme-moq/sections-product.FIXED.liquid b/shopify/theme-moq/sections-product.FIXED.liquid
new file mode 100644
index 00000000..2df9e130
--- /dev/null
+++ b/shopify/theme-moq/sections-product.FIXED.liquid
@@ -0,0 +1,380 @@
+<section class="product-section">
+  <div class="product-container">
+    <div class="breadcrumb">
+      <a href="/">HOME</a> / <a href="/collections/products">PRODUCTS</a> / {{ product.vendor | upcase }} | {{ product.title | upcase }}
+    </div>
+
+    <div class="product-grid">
+      <!-- LEFT: Product Image -->
+      <div class="product-gallery">
+        {% if product.featured_image %}
+          <img src="{{ product.featured_image | img_url: '600x600' }}" alt="{{ product.title }}" class="product-main-image">
+        {% endif %}
+        
+        <!-- Color swatches -->
+        {% if product.images.size > 1 %}
+          <div class="product-swatches">
+            <p class="swatch-label">Other Colorways</p>
+            <div class="swatch-grid">
+              {% for image in product.images %}
+                <img src="{{ image | img_url: '100x100' }}" alt="{{ product.title }}" class="swatch-image">
+              {% endfor %}
+            </div>
+          </div>
+        {% endif %}
+      </div>
+
+      <!-- RIGHT: Product Details -->
+      <div class="product-details">
+        <div class="product-header">
+          <p class="brand">{{ product.vendor }}</p>
+          <h1 class="product-title">{{ product.title }}</h1>
+        </div>
+
+        <!-- SKU & Price -->
+        <div class="product-meta">
+          {% if product.selected_or_first_available_variant.sku %}
+            <p class="sku"><strong>SKU:</strong> {{ product.selected_or_first_available_variant.sku }}</p>
+          {% endif %}
+          <p class="price"><strong>PRICE:</strong> {{ product.selected_or_first_available_variant.price | money }}</p>
+        </div>
+
+        <!-- Form -->
+        <form method="post" action="/cart/add" id="product-form">
+          <!-- Size/Variant Selector -->
+          {% if product.available %}
+            <div class="form-group">
+              <label class="form-label">SIZE:</label>
+              <div class="variant-buttons">
+                {% for variant in product.variants %}
+                  <button type="button" class="variant-btn {% if variant == product.selected_or_first_available_variant %}active{% endif %}" data-variant-id="{{ variant.id }}">
+                    {{ variant.title }}
+                  </button>
+                {% endfor %}
+              </div>
+            </div>
+
+            <!-- Quantity (DW MOQ 2026-06-22: read order-min metafields) -->
+            {%- liquid
+              assign moq_min_raw = product.metafields.global.v_prods_quantity_order_min
+              assign moq_step_raw = product.metafields.global.v_prods_quantity_order_units
+              if moq_min_raw.value
+                assign moq_min_raw = moq_min_raw.value
+              endif
+              if moq_step_raw.value
+                assign moq_step_raw = moq_step_raw.value
+              endif
+              assign moq_min = moq_min_raw | plus: 0
+              assign moq_step = moq_step_raw | plus: 0
+              if moq_min < 1
+                assign moq_min = 1
+              endif
+              if moq_step < 1
+                assign moq_step = 1
+              endif
+            -%}
+            <div class="form-group">
+              <label class="form-label">QUANTITY:{% if moq_min > 1 %} <span class="moq-note">(min {{ moq_min }}{% if moq_step > 1 %}, in {{ moq_step }}s{% endif %})</span>{% endif %}</label>
+              <div class="quantity-control">
+                <button type="button" class="qty-btn minus">−</button>
+                <input type="number" name="quantity" value="{{ moq_min }}" min="{{ moq_min }}" step="{{ moq_step }}" data-min="{{ moq_min }}" data-step="{{ moq_step }}" class="qty-input">
+                <button type="button" class="qty-btn plus">+</button>
+              </div>
+            </div>
+
+            <!-- Buttons -->
+            <div class="form-actions">
+              <button type="button" class="btn btn-secondary">REQUEST SAMPLE</button>
+              <button type="button" class="btn btn-secondary">SPEC SHEET</button>
+            </div>
+            <button type="submit" class="btn btn-primary" id="add-to-cart">ADD TO CART</button>
+
+            <input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
+          {% endif %}
+        </form>
+
+        <!-- Specifications -->
+        <div class="specifications">
+          <h3>SPECIFICATIONS</h3>
+          <dl>
+            {% if product.metafields.custom.width %}
+              <dt>Width</dt>
+              <dd>{{ product.metafields.custom.width }}</dd>
+            {% endif %}
+            {% if product.metafields.custom.length %}
+              <dt>Length</dt>
+              <dd>{{ product.metafields.custom.length }}</dd>
+            {% endif %}
+            {% if product.metafields.custom.material %}
+              <dt>Material</dt>
+              <dd>{{ product.metafields.custom.material }}</dd>
+            {% endif %}
+            {% if product.vendor %}
+              <dt>Designer</dt>
+              <dd>{{ product.vendor }}</dd>
+            {% endif %}
+            {% if product.metafields.custom.unit %}
+              <dt>Unit</dt>
+              <dd>{{ product.metafields.custom.unit }}</dd>
+            {% endif %}
+          </dl>
+        </div>
+      </div>
+    </div>
+  </div>
+</section>
+
+<style>
+.product-section {
+  padding: 2rem;
+  max-width: 1400px;
+  margin: 0 auto;
+}
+
+.breadcrumb {
+  font-size: 0.875rem;
+  margin-bottom: 2rem;
+  color: #666;
+}
+
+.breadcrumb a {
+  color: #333;
+  text-decoration: none;
+}
+
+.product-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 4rem;
+  margin-bottom: 3rem;
+}
+
+.product-gallery {
+  display: flex;
+  flex-direction: column;
+  gap: 2rem;
+}
+
+.product-main-image {
+  width: 100%;
+  height: auto;
+  display: block;
+}
+
+.swatch-label {
+  font-size: 0.875rem;
+  font-weight: 600;
+  margin-bottom: 1rem;
+}
+
+.swatch-grid {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 1rem;
+}
+
+.swatch-image {
+  width: 100%;
+  height: auto;
+  cursor: pointer;
+  border: 2px solid #eee;
+  transition: border-color 0.2s;
+}
+
+.swatch-image:hover {
+  border-color: #333;
+}
+
+.product-header {
+  margin-bottom: 1.5rem;
+}
+
+.brand {
+  font-size: 0.875rem;
+  color: #999;
+  margin: 0 0 0.5rem 0;
+}
+
+.product-title {
+  font-size: 1.5rem;
+  font-weight: 400;
+  margin: 0;
+  line-height: 1.2;
+}
+
+.product-meta {
+  display: grid;
+  gap: 0.5rem;
+  margin-bottom: 2rem;
+  font-size: 0.95rem;
+}
+
+.product-meta p {
+  margin: 0;
+}
+
+.form-group {
+  margin-bottom: 1.5rem;
+}
+
+.form-label {
+  display: block;
+  font-weight: 600;
+  font-size: 0.875rem;
+  margin-bottom: 0.75rem;
+}
+
+.variant-buttons {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 1rem;
+}
+
+.variant-btn {
+  padding: 1rem;
+  border: 2px solid #333;
+  background: white;
+  color: #333;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.2s;
+  font-size: 0.875rem;
+}
+
+.variant-btn.active {
+  background: #333;
+  color: white;
+}
+
+.quantity-control {
+  display: grid;
+  grid-template-columns: auto 1fr auto;
+  gap: 0.5rem;
+  max-width: 200px;
+}
+
+.qty-btn {
+  background: white;
+  border: 1px solid #ddd;
+  width: 2.5rem;
+  height: 2.5rem;
+  cursor: pointer;
+  font-size: 1.2rem;
+}
+
+.qty-input {
+  border: 1px solid #ddd;
+  text-align: center;
+  font-weight: 600;
+}
+
+.moq-note { font-weight: 400; color: #888; font-size: 0.8em; }
+
+.form-actions {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 1rem;
+  margin-bottom: 1rem;
+}
+
+.btn {
+  padding: 1rem;
+  border: none;
+  border-radius: 50px;
+  font-weight: 600;
+  font-size: 0.875rem;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+.btn-primary {
+  background: #333;
+  color: white;
+  width: 100%;
+}
+
+.btn-primary:hover {
+  background: #000;
+}
+
+.btn-secondary {
+  background: #333;
+  color: white;
+}
+
+.btn-secondary:hover {
+  background: #000;
+}
+
+.specifications {
+  margin-top: 3rem;
+  border-top: 1px solid #eee;
+  padding-top: 2rem;
+}
+
+.specifications h3 {
+  font-size: 0.875rem;
+  font-weight: 700;
+  margin-bottom: 1.5rem;
+  letter-spacing: 0.05em;
+}
+
+.specifications dl {
+  display: grid;
+  grid-template-columns: auto 1fr;
+  gap: 1rem 2rem;
+}
+
+.specifications dt {
+  font-weight: 600;
+  font-size: 0.875rem;
+}
+
+.specifications dd {
+  margin: 0;
+  font-size: 0.875rem;
+  color: #666;
+}
+
+@media (max-width: 768px) {
+  .product-grid {
+    grid-template-columns: 1fr;
+    gap: 2rem;
+  }
+  
+  .variant-buttons {
+    grid-template-columns: 1fr;
+  }
+  
+  .form-actions {
+    grid-template-columns: 1fr;
+  }
+}
+</style>
+
+
+<script>
+/* DW MOQ 2026-06-22: enforce order minimum + increment on the custom PDP quantity box.
+   Conflict-safe: re-clamps to data-min / data-step after any +/- click, on change/blur,
+   and before form submit — regardless of any other handlers. */
+(function(){
+  var q = document.querySelector('.quantity-control .qty-input');
+  if(!q) return;
+  var min = parseInt(q.getAttribute('data-min'),10) || 1;
+  var step = parseInt(q.getAttribute('data-step'),10) || 1;
+  function clamp(){
+    var v = parseInt(q.value,10);
+    if(isNaN(v) || v < min){ v = min; }
+    var r = (v - min) % step;
+    if(r !== 0){ v = v - r + step; }
+    q.value = v;
+  }
+  clamp();
+  var ctrl = q.closest('.quantity-control');
+  if(ctrl){ ctrl.addEventListener('click', function(){ setTimeout(clamp, 0); }); }
+  q.addEventListener('change', clamp);
+  q.addEventListener('blur', clamp);
+  var form = document.getElementById('product-form');
+  if(form){ form.addEventListener('submit', clamp, true); }
+})();
+</script>
diff --git a/shopify/theme-moq/sections-product.LIVE-original.liquid b/shopify/theme-moq/sections-product.LIVE-original.liquid
new file mode 100644
index 00000000..68ba1bc9
--- /dev/null
+++ b/shopify/theme-moq/sections-product.LIVE-original.liquid
@@ -0,0 +1,333 @@
+<section class="product-section">
+  <div class="product-container">
+    <div class="breadcrumb">
+      <a href="/">HOME</a> / <a href="/collections/products">PRODUCTS</a> / {{ product.vendor | upcase }} | {{ product.title | upcase }}
+    </div>
+
+    <div class="product-grid">
+      <!-- LEFT: Product Image -->
+      <div class="product-gallery">
+        {% if product.featured_image %}
+          <img src="{{ product.featured_image | img_url: '600x600' }}" alt="{{ product.title }}" class="product-main-image">
+        {% endif %}
+        
+        <!-- Color swatches -->
+        {% if product.images.size > 1 %}
+          <div class="product-swatches">
+            <p class="swatch-label">Other Colorways</p>
+            <div class="swatch-grid">
+              {% for image in product.images %}
+                <img src="{{ image | img_url: '100x100' }}" alt="{{ product.title }}" class="swatch-image">
+              {% endfor %}
+            </div>
+          </div>
+        {% endif %}
+      </div>
+
+      <!-- RIGHT: Product Details -->
+      <div class="product-details">
+        <div class="product-header">
+          <p class="brand">{{ product.vendor }}</p>
+          <h1 class="product-title">{{ product.title }}</h1>
+        </div>
+
+        <!-- SKU & Price -->
+        <div class="product-meta">
+          {% if product.selected_or_first_available_variant.sku %}
+            <p class="sku"><strong>SKU:</strong> {{ product.selected_or_first_available_variant.sku }}</p>
+          {% endif %}
+          <p class="price"><strong>PRICE:</strong> {{ product.selected_or_first_available_variant.price | money }}</p>
+        </div>
+
+        <!-- Form -->
+        <form method="post" action="/cart/add" id="product-form">
+          <!-- Size/Variant Selector -->
+          {% if product.available %}
+            <div class="form-group">
+              <label class="form-label">SIZE:</label>
+              <div class="variant-buttons">
+                {% for variant in product.variants %}
+                  <button type="button" class="variant-btn {% if variant == product.selected_or_first_available_variant %}active{% endif %}" data-variant-id="{{ variant.id }}">
+                    {{ variant.title }}
+                  </button>
+                {% endfor %}
+              </div>
+            </div>
+
+            <!-- Quantity -->
+            <div class="form-group">
+              <label class="form-label">QUANTITY:</label>
+              <div class="quantity-control">
+                <button type="button" class="qty-btn minus">−</button>
+                <input type="number" name="quantity" value="1" min="1" class="qty-input">
+                <button type="button" class="qty-btn plus">+</button>
+              </div>
+            </div>
+
+            <!-- Buttons -->
+            <div class="form-actions">
+              <button type="button" class="btn btn-secondary">REQUEST SAMPLE</button>
+              <button type="button" class="btn btn-secondary">SPEC SHEET</button>
+            </div>
+            <button type="submit" class="btn btn-primary" id="add-to-cart">ADD TO CART</button>
+
+            <input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
+          {% endif %}
+        </form>
+
+        <!-- Specifications -->
+        <div class="specifications">
+          <h3>SPECIFICATIONS</h3>
+          <dl>
+            {% if product.metafields.custom.width %}
+              <dt>Width</dt>
+              <dd>{{ product.metafields.custom.width }}</dd>
+            {% endif %}
+            {% if product.metafields.custom.length %}
+              <dt>Length</dt>
+              <dd>{{ product.metafields.custom.length }}</dd>
+            {% endif %}
+            {% if product.metafields.custom.material %}
+              <dt>Material</dt>
+              <dd>{{ product.metafields.custom.material }}</dd>
+            {% endif %}
+            {% if product.vendor %}
+              <dt>Designer</dt>
+              <dd>{{ product.vendor }}</dd>
+            {% endif %}
+            {% if product.metafields.custom.unit %}
+              <dt>Unit</dt>
+              <dd>{{ product.metafields.custom.unit }}</dd>
+            {% endif %}
+          </dl>
+        </div>
+      </div>
+    </div>
+  </div>
+</section>
+
+<style>
+.product-section {
+  padding: 2rem;
+  max-width: 1400px;
+  margin: 0 auto;
+}
+
+.breadcrumb {
+  font-size: 0.875rem;
+  margin-bottom: 2rem;
+  color: #666;
+}
+
+.breadcrumb a {
+  color: #333;
+  text-decoration: none;
+}
+
+.product-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 4rem;
+  margin-bottom: 3rem;
+}
+
+.product-gallery {
+  display: flex;
+  flex-direction: column;
+  gap: 2rem;
+}
+
+.product-main-image {
+  width: 100%;
+  height: auto;
+  display: block;
+}
+
+.swatch-label {
+  font-size: 0.875rem;
+  font-weight: 600;
+  margin-bottom: 1rem;
+}
+
+.swatch-grid {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 1rem;
+}
+
+.swatch-image {
+  width: 100%;
+  height: auto;
+  cursor: pointer;
+  border: 2px solid #eee;
+  transition: border-color 0.2s;
+}
+
+.swatch-image:hover {
+  border-color: #333;
+}
+
+.product-header {
+  margin-bottom: 1.5rem;
+}
+
+.brand {
+  font-size: 0.875rem;
+  color: #999;
+  margin: 0 0 0.5rem 0;
+}
+
+.product-title {
+  font-size: 1.5rem;
+  font-weight: 400;
+  margin: 0;
+  line-height: 1.2;
+}
+
+.product-meta {
+  display: grid;
+  gap: 0.5rem;
+  margin-bottom: 2rem;
+  font-size: 0.95rem;
+}
+
+.product-meta p {
+  margin: 0;
+}
+
+.form-group {
+  margin-bottom: 1.5rem;
+}
+
+.form-label {
+  display: block;
+  font-weight: 600;
+  font-size: 0.875rem;
+  margin-bottom: 0.75rem;
+}
+
+.variant-buttons {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 1rem;
+}
+
+.variant-btn {
+  padding: 1rem;
+  border: 2px solid #333;
+  background: white;
+  color: #333;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.2s;
+  font-size: 0.875rem;
+}
+
+.variant-btn.active {
+  background: #333;
+  color: white;
+}
+
+.quantity-control {
+  display: grid;
+  grid-template-columns: auto 1fr auto;
+  gap: 0.5rem;
+  max-width: 200px;
+}
+
+.qty-btn {
+  background: white;
+  border: 1px solid #ddd;
+  width: 2.5rem;
+  height: 2.5rem;
+  cursor: pointer;
+  font-size: 1.2rem;
+}
+
+.qty-input {
+  border: 1px solid #ddd;
+  text-align: center;
+  font-weight: 600;
+}
+
+.form-actions {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 1rem;
+  margin-bottom: 1rem;
+}
+
+.btn {
+  padding: 1rem;
+  border: none;
+  border-radius: 50px;
+  font-weight: 600;
+  font-size: 0.875rem;
+  cursor: pointer;
+  transition: all 0.2s;
+}
+
+.btn-primary {
+  background: #333;
+  color: white;
+  width: 100%;
+}
+
+.btn-primary:hover {
+  background: #000;
+}
+
+.btn-secondary {
+  background: #333;
+  color: white;
+}
+
+.btn-secondary:hover {
+  background: #000;
+}
+
+.specifications {
+  margin-top: 3rem;
+  border-top: 1px solid #eee;
+  padding-top: 2rem;
+}
+
+.specifications h3 {
+  font-size: 0.875rem;
+  font-weight: 700;
+  margin-bottom: 1.5rem;
+  letter-spacing: 0.05em;
+}
+
+.specifications dl {
+  display: grid;
+  grid-template-columns: auto 1fr;
+  gap: 1rem 2rem;
+}
+
+.specifications dt {
+  font-weight: 600;
+  font-size: 0.875rem;
+}
+
+.specifications dd {
+  margin: 0;
+  font-size: 0.875rem;
+  color: #666;
+}
+
+@media (max-width: 768px) {
+  .product-grid {
+    grid-template-columns: 1fr;
+    gap: 2rem;
+  }
+  
+  .variant-buttons {
+    grid-template-columns: 1fr;
+  }
+  
+  .form-actions {
+    grid-template-columns: 1fr;
+  }
+}
+</style>

← d9616965 Apply compact layout fix to all theme variants  ·  back to Designer Wallcoverings  ·  Harden MOQ Liquid: use append-coercion for legacy global met f9ca2f62 →