[object Object]

← back to Dw Contact Us Pages

TK-11925: gate buy box (price/cart/sample/min-order) out of contact-us PDP; fix verify no_sample_button to match rendered element not bare JS token

a2b65a84697bbe31101eca140bf1b40665418107 · 2026-09-20 12:27:09 -0700 · steve

verify → fail=0 (WARN from honest 0-of-0 sample-only NOT-MEASURED + client-side Boost note). Live-confirmed real_sample_btn_elements=0 on DG/RL/CL samples.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q8HhtR5c44zRJA3DfKYTZQ

Files touched

Diff

commit a2b65a84697bbe31101eca140bf1b40665418107
Author: steve <steve@designerwallcoverings.com>
Date:   Sun Sep 20 12:27:09 2026 -0700

    TK-11925: gate buy box (price/cart/sample/min-order) out of contact-us PDP; fix verify no_sample_button to match rendered element not bare JS token
    
    verify → fail=0 (WARN from honest 0-of-0 sample-only NOT-MEASURED + client-side Boost note). Live-confirmed real_sample_btn_elements=0 on DG/RL/CL samples.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Q8HhtR5c44zRJA3DfKYTZQ
---
 .../145556635699/assets/dw-contact-us-cards.js     | 107 ++++++++
 .../145556635699/layout/theme.liquid               |   3 +-
 .../snippets/dw-contact-us-block.liquid            | 304 +++++++++++++++++++++
 .../snippets/hide-browse-hidden.liquid             |  26 ++
 .../145556635699/snippets/product-list-item.liquid |   9 +-
 .../145556635699/snippets/product.liquid           |   7 +
 data/verify-latest.json                            |  86 +++---
 scripts/verify.mjs                                 |   7 +-
 theme/snippets/product.liquid                      |   8 +
 9 files changed, 511 insertions(+), 46 deletions(-)

diff --git a/data/theme-preimage/145556635699/assets/dw-contact-us-cards.js b/data/theme-preimage/145556635699/assets/dw-contact-us-cards.js
new file mode 100644
index 0000000..68ecfc7
--- /dev/null
+++ b/data/theme-preimage/145556635699/assets/dw-contact-us-cards.js
@@ -0,0 +1,107 @@
+/* dw-contact-us-cards.js — TK-11925
+ * Boost SD renders every browse/search grid CLIENT-SIDE, so neither
+ * product-list-item.liquid nor a server-rendered rule can reach those cards.
+ * This sweeps Boost cards and replaces the price with "Contact us for pricing"
+ * for the contact-us vendor cohort (Designers Guild / Ralph Lauren /
+ * Christian Lacroix Europe).
+ *
+ * VENDOR-KEYED (preferred): a live Boost card exposes its vendor as the text of
+ * a [class*="product-vendor"] node — measured on the live store, and the same
+ * hook the existing Newmor guard in layout/theme.liquid already relies on
+ * (isNewmor() reads exactly that node). Price nodes measured on the same guard:
+ *   .boost-sd__product-price, .boost-sd__format-currency, [class*="compare-price"], [class*="unit-price"]
+ *
+ * Vendor list comes from window.DW_CONTACT_US_VENDORS, emitted by
+ * snippets/hide-browse-hidden.liquid from (in priority order)
+ *   1. shop metafield custom.contact_us_vendors
+ *   2. theme setting  settings.contact_us_vendors
+ *   3. the literal 3-vendor fallback
+ * mirroring the showroom_vendors pattern. No id list is baked in, so the
+ * cohort can change without regenerating this asset.
+ *
+ * Optional id backstop: window.DW_CONTACT_US_IDS (array of product ids) is
+ * honoured if present, for cards whose vendor node is suppressed by a Boost
+ * theme setting.
+ */
+(function () {
+  if (window.__dwContactUsCards) return;
+  window.__dwContactUsCards = true;
+
+  var LABEL = 'Contact us for pricing';
+  var CARD_SEL = '.boost-sd__product-item';
+  var PRICE_SEL = '.boost-sd__product-price,.boost-sd__format-currency,[class*="product-price"],[class*="compare-price"],[class*="unit-price"]';
+  var VENDOR_SEL = '[class*="product-vendor"]';
+
+  function norm(s) { return String(s == null ? '' : s).trim().toLowerCase(); }
+
+  var VENDORS = (window.DW_CONTACT_US_VENDORS || [
+    'Designers Guild', 'Ralph Lauren', 'Christian Lacroix Europe'
+  ]).map(norm).filter(Boolean);
+
+  var IDS = new Set((window.DW_CONTACT_US_IDS || []).map(String));
+
+  if (!VENDORS.length && !IDS.size) return;
+
+  function isTarget(card) {
+    var id = card.getAttribute('data-product-id');
+    if (id && IDS.has(String(id))) return true;
+    var v = card.querySelector(VENDOR_SEL);
+    if (v && VENDORS.indexOf(norm(v.textContent)) > -1) return true;
+    return false;
+  }
+
+  function treat(card) {
+    if (card.getAttribute('data-dw-contact-us') === '1') return;
+    card.setAttribute('data-dw-contact-us', '1');
+
+    var replaced = false;
+    card.querySelectorAll(PRICE_SEL).forEach(function (n) {
+      if (!replaced) {
+        // Reuse the first price node so the card keeps its layout/typography.
+        n.textContent = LABEL;
+        n.classList.add('dw-cu-card-price');
+        n.setAttribute('data-dw-contact-us-price', '1');
+        replaced = true;
+      } else {
+        n.remove();
+      }
+    });
+
+    if (!replaced && !card.querySelector('.dw-cu-card-price')) {
+      var p = document.createElement('p');
+      p.className = 'dw-cu-card-price';
+      p.setAttribute('data-dw-contact-us-price', '1');
+      p.textContent = LABEL;
+      card.appendChild(p);
+    }
+
+    // Nothing purchasable from the grid for this cohort.
+    card.querySelectorAll('[class*="quick-view"],[class*="quickView"],[class*="quick-add"],[class*="buy-now"],[class*="add-to-cart"]')
+      .forEach(function (n) { n.remove(); });
+  }
+
+  var pending = false;
+  function sweep() {
+    var cards = document.querySelectorAll(CARD_SEL + ':not([data-dw-contact-us])');
+    for (var i = 0; i < cards.length; i++) {
+      if (isTarget(cards[i])) treat(cards[i]);
+    }
+  }
+  function schedule() {
+    if (pending) return;
+    pending = true;
+    requestAnimationFrame(function () { pending = false; sweep(); });
+  }
+  function start() {
+    sweep();
+    new MutationObserver(schedule).observe(document.documentElement, { childList: true, subtree: true });
+  }
+
+  var css = document.createElement('style');
+  css.textContent = '.dw-cu-card-price{font-size:12px!important;letter-spacing:.02em;color:#6b6357!important;margin:4px 0 0}' +
+                    '.boost-sd__product-item[data-dw-contact-us] .boost-sd__format-currency:not([data-dw-contact-us-price]){display:none!important}';
+  (document.head || document.documentElement).appendChild(css);
+
+  if (document.readyState !== 'loading') start();
+  else document.addEventListener('DOMContentLoaded', start);
+})();
diff --git a/data/theme-preimage/145556635699/layout/theme.liquid b/data/theme-preimage/145556635699/layout/theme.liquid
index c80fbda..36c080f 100644
--- a/data/theme-preimage/145556635699/layout/theme.liquid
+++ b/data/theme-preimage/145556635699/layout/theme.liquid
@@ -1274,7 +1274,8 @@ gtag('consent','default',{analytics_storage:'denied',ad_storage:'denied',ad_user
       {% if selected_variant.barcode != blank %}
         "mpn": {{ selected_variant.barcode | json }},
       {% endif %}
-      {% if product.vendor == 'Newmor Wallcoverings' %}
+      {% comment %} TK-11925: contact-us products (Designers Guild / Ralph Lauren / Christian Lacroix) publish NO Offer/price in structured data, same carve-out as Newmor. {% endcomment %}
+      {% if product.vendor == 'Newmor Wallcoverings' or product.template_suffix == 'contact-us' %}
       "url": {{ canonical_url | json }}
       {% else %}
       "offers": {
diff --git a/data/theme-preimage/145556635699/snippets/dw-contact-us-block.liquid b/data/theme-preimage/145556635699/snippets/dw-contact-us-block.liquid
new file mode 100644
index 0000000..51a5ce6
--- /dev/null
+++ b/data/theme-preimage/145556635699/snippets/dw-contact-us-block.liquid
@@ -0,0 +1,304 @@
+{%- comment -%}
+  dw-contact-us-block.liquid — TK-11925
+  ---------------------------------------------------------------------------
+  "Contact us page" treatment for to-the-trade / showroom-only vendor lines
+  (Designers Guild, Ralph Lauren, Christian Lacroix Europe).
+
+  Renders ONLY when the product's template suffix is `contact-us`
+  (templates/product.contact-us.json). That template already omits the `price`
+  and `form` blocks, so there is no price, no add-to-cart and no sample UI to
+  begin with; the CSS at the bottom of this file is BELT-AND-BRACES so nothing
+  price/cart/sample-shaped can leak back if a block is ever re-added in the
+  theme editor.
+
+  Placement: rendered by snippets/product.liquid immediately after
+  `product-gallery`, i.e. directly BELOW the product image column.
+
+  Backend: posts the SAME JSON body shape to the SAME live endpoint as
+  sections/contact-for-price.liquid → https://api.designerwallcoverings.com/api/sku-inquiry
+  Fields: productId productTitle sku name email phone company role quantity
+          unit projectName city timeline budget notes
+
+  Render with:  {% render 'dw-contact-us-block', product: product %}
+{%- endcomment -%}
+
+{%- if product.template_suffix == 'contact-us' -%}
+{%- liquid
+  assign dw_cu_sku = ''
+  for v in product.variants
+    assign v_sku = v.sku | default: ''
+    if v_sku != blank and dw_cu_sku == blank
+      assign dw_cu_sku = v_sku
+    endif
+  endfor
+  assign dw_cu_sku = dw_cu_sku | replace: '-Sample', '' | replace: '-SAMPLE', '' | replace: '-sample', ''
+  assign dw_cu_sku = dw_cu_sku | replace: '--', '-' | replace: '--', '-'
+  assign dw_cu_last = dw_cu_sku | slice: -1, 1
+  if dw_cu_sku != blank and dw_cu_last == '-'
+    assign dw_cu_sku = dw_cu_sku | remove_last: '-'
+  endif
+  assign dw_cu_label = dw_cu_sku | default: product.title
+  assign dw_cu_subject = 'Inquiry: ' | append: dw_cu_label | append: ' — ' | append: product.title
+  assign dw_cu_uid = product.id
+-%}
+
+<section class="dw-cu" id="dw-cu-{{ dw_cu_uid }}"
+  data-product-id="{{ product.id }}"
+  data-product-title="{{ product.title | escape }}"
+  data-sku="{{ dw_cu_sku | escape }}"
+  aria-labelledby="dw-cu-h-{{ dw_cu_uid }}">
+
+  <h2 class="dw-cu__h" id="dw-cu-h-{{ dw_cu_uid }}">Contact us about this pattern</h2>
+
+  <p class="dw-cu__meta">
+    {%- if product.vendor != blank -%}<span class="dw-cu__vendor">{{ product.vendor }}</span>{%- endif -%}
+    <span class="dw-cu__pattern">{{ product.title }}</span>
+    {%- if dw_cu_sku != blank -%}<span class="dw-cu__sku">SKU {{ dw_cu_sku }}</span>{%- endif -%}
+  </p>
+
+  <p class="dw-cu__lede">This line is available through our showroom. Pricing and availability by request.</p>
+
+  <div class="dw-cu__direct">
+    <a class="dw-cu__btn dw-cu__btn--call" href="tel:+18883734564">Call (888) 373-4564</a>
+    <a class="dw-cu__btn dw-cu__btn--mail"
+       href="mailto:info@designerwallcoverings.com?subject={{ dw_cu_subject | url_encode }}">Email us</a>
+  </div>
+
+  <form class="dw-cu__form" id="dw-cu-form-{{ dw_cu_uid }}" novalidate>
+    <input type="hidden" data-f="productId" value="{{ product.id }}">
+    <input type="hidden" data-f="productTitle" value="{{ product.title | escape }}">
+    <input type="hidden" data-f="sku" value="{{ dw_cu_sku | escape }}">
+
+    <div class="dw-cu__row">
+      <div class="dw-cu__grp">
+        <label for="dw-cu-name-{{ dw_cu_uid }}">Your name *</label>
+        <input type="text" id="dw-cu-name-{{ dw_cu_uid }}" data-f="name" required autocomplete="name">
+      </div>
+      <div class="dw-cu__grp">
+        <label for="dw-cu-email-{{ dw_cu_uid }}">Email *</label>
+        <input type="email" id="dw-cu-email-{{ dw_cu_uid }}" data-f="email" required autocomplete="email" value="{{ customer.email }}">
+      </div>
+    </div>
+
+    <div class="dw-cu__row">
+      <div class="dw-cu__grp">
+        <label for="dw-cu-phone-{{ dw_cu_uid }}">Phone</label>
+        <input type="tel" id="dw-cu-phone-{{ dw_cu_uid }}" data-f="phone" autocomplete="tel">
+      </div>
+      <div class="dw-cu__grp">
+        <label for="dw-cu-company-{{ dw_cu_uid }}">Company / business</label>
+        <input type="text" id="dw-cu-company-{{ dw_cu_uid }}" data-f="company" autocomplete="organization">
+      </div>
+    </div>
+
+    <div class="dw-cu__row">
+      <div class="dw-cu__grp">
+        <label for="dw-cu-role-{{ dw_cu_uid }}">I am a *</label>
+        <select id="dw-cu-role-{{ dw_cu_uid }}" data-f="role" required>
+          <option value="">Select&hellip;</option>
+          <option value="interior_designer">Interior Designer</option>
+          <option value="trade">Trade / Dealer</option>
+          <option value="architect">Architect / Specifier</option>
+          <option value="homeowner">Homeowner</option>
+          <option value="other">Other</option>
+        </select>
+      </div>
+      <div class="dw-cu__grp">
+        <label for="dw-cu-qty-{{ dw_cu_uid }}">Quantity needed</label>
+        <div class="dw-cu__qty">
+          <input type="number" id="dw-cu-qty-{{ dw_cu_uid }}" data-f="quantity" min="1" placeholder="e.g. 6">
+          <select data-f="unit" aria-label="Unit">
+            <option value="rolls">rolls</option>
+            <option value="yards">yards</option>
+            <option value="sq_ft">sq ft</option>
+            <option value="unsure">unsure</option>
+          </select>
+        </div>
+      </div>
+    </div>
+
+    <div class="dw-cu__row">
+      <div class="dw-cu__grp">
+        <label for="dw-cu-project-{{ dw_cu_uid }}">Project name</label>
+        <input type="text" id="dw-cu-project-{{ dw_cu_uid }}" data-f="projectName" placeholder="e.g. Madison Ave Residence">
+      </div>
+      <div class="dw-cu__grp">
+        <label for="dw-cu-city-{{ dw_cu_uid }}">City / location</label>
+        <input type="text" id="dw-cu-city-{{ dw_cu_uid }}" data-f="city" placeholder="e.g. Los Angeles, CA">
+      </div>
+    </div>
+
+    <div class="dw-cu__row">
+      <div class="dw-cu__grp">
+        <label for="dw-cu-timeline-{{ dw_cu_uid }}">Timeline</label>
+        <input type="text" id="dw-cu-timeline-{{ dw_cu_uid }}" data-f="timeline" placeholder="e.g. 2&ndash;3 weeks">
+      </div>
+      <div class="dw-cu__grp">
+        <label for="dw-cu-budget-{{ dw_cu_uid }}">Budget</label>
+        <input type="text" id="dw-cu-budget-{{ dw_cu_uid }}" data-f="budget" placeholder="e.g. $10,000">
+      </div>
+    </div>
+
+    <div class="dw-cu__grp">
+      <label for="dw-cu-notes-{{ dw_cu_uid }}">Additional notes</label>
+      <textarea id="dw-cu-notes-{{ dw_cu_uid }}" data-f="notes" rows="3" placeholder="Anything else we should know about your project&hellip;"></textarea>
+    </div>
+
+    <button type="submit" class="dw-cu__submit">Send inquiry</button>
+    <p class="dw-cu__reassure">We typically reply within 1 business day. No obligation.</p>
+    <p class="dw-cu__status" role="status" aria-live="polite" hidden></p>
+  </form>
+</section>
+
+<style>
+  /* LAYOUT — measured, not guessed.
+     theme.css: @media(min-width:770px){.product-images{float:left;width:50%}} and
+     .product-details-wrapper{float:right;width:50%}; below 770px both go full width.
+     The rendered gallery root is <div class="product-images product-gallery">.
+     A float:left block inserted between them does NOT work: CSS 2.1 forbids a later
+     float (.product-details-wrapper, float:right) from sitting higher than an earlier
+     float, so clearing under the image would drag the whole details column down with it.
+     So on the contact-us template ONLY, .product becomes a 2-col grid: image top-left,
+     contact block directly beneath it, details column spanning both rows on the right.
+     Scoped to body.template-suffix-contact-us — zero effect on any other product. */
+  .dw-cu{margin:26px 0 8px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:#3D4246;box-sizing:border-box;clear:both}
+  @media(min-width:770px){
+    body.template-suffix-contact-us .product{display:grid;grid-template-columns:1fr 1fr;align-items:start}
+    body.template-suffix-contact-us .product > .product-images{grid-column:1;grid-row:1;float:none!important;width:auto!important}
+    body.template-suffix-contact-us .product > .dw-cu{grid-column:1;grid-row:2;float:none;width:auto;clear:none;padding:0 30px 0 55px}
+    body.template-suffix-contact-us .product > .product-details-wrapper{grid-column:2;grid-row:1 / span 2;float:none!important;width:auto!important}
+  }
+  @media(max-width:769px){.dw-cu{width:100%;padding:0 20px;text-align:left}}
+  .dw-cu *{box-sizing:border-box}
+  .dw-cu__h{font-family:Lora,serif;font-size:20px;font-weight:500;color:#3D4246;letter-spacing:-0.01em;margin:0 0 8px}
+  .dw-cu__meta{margin:0 0 6px;font-size:12px;line-height:1.6;color:#6b6357;display:flex;flex-wrap:wrap;gap:8px;align-items:center}
+  .dw-cu__vendor{text-transform:uppercase;letter-spacing:.07em;color:#8A8A85}
+  .dw-cu__pattern{font-family:Lora,serif;font-size:14px;color:#3D4246}
+  .dw-cu__sku{font-size:11px;letter-spacing:.06em;color:#8a8276;background:#f6f4f0;border-radius:4px;padding:2px 7px}
+  .dw-cu__lede{margin:0 0 14px;font-size:14px;line-height:1.55;color:#5b5f63}
+  .dw-cu__direct{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 18px}
+  .dw-cu__btn{display:inline-block;padding:.65rem 1.15rem;border-radius:6px;font-size:14px;font-weight:500;text-decoration:none;transition:all .2s;border:1px solid #2a2622}
+  .dw-cu__btn--call{background:#2a2622;color:#fff}
+  .dw-cu__btn--call:hover{background:#000;color:#fff}
+  .dw-cu__btn--mail{background:#fff;color:#2a2622}
+  .dw-cu__btn--mail:hover{background:#faf8f4;color:#2a2622}
+  .dw-cu__form{border:1px solid #e6e0d6;background:#faf8f4;border-radius:8px;padding:18px}
+  .dw-cu__row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
+  .dw-cu__grp{margin-bottom:14px}
+  .dw-cu__grp label{display:block;margin-bottom:.35rem;font-weight:500;color:#3a352f;font-size:13px}
+  .dw-cu__grp input,.dw-cu__grp select,.dw-cu__grp textarea{width:100%;padding:.6rem;border:1px solid #d6d0c6;border-radius:6px;font-family:inherit;font-size:14px;background:#fff;color:#3D4246}
+  .dw-cu__grp input:focus,.dw-cu__grp select:focus,.dw-cu__grp textarea:focus{outline:none;border-color:#b9892f;box-shadow:0 0 0 3px rgba(185,137,47,.12)}
+  .dw-cu__qty{display:flex;gap:.5rem}
+  .dw-cu__qty input{flex:1}
+  .dw-cu__qty select{width:auto}
+  .dw-cu__submit{width:100%;padding:.8rem;background:#b9892f;color:#fff;border:none;border-radius:6px;font-weight:600;font-size:14px;cursor:pointer;transition:background .2s}
+  .dw-cu__submit:hover{background:#a3781f}
+  .dw-cu__submit[disabled]{opacity:.6;cursor:default}
+  .dw-cu__reassure{text-align:center;font-size:12px;color:#8a8276;margin:.6rem 0 0}
+  .dw-cu__status{margin:.7rem 0 0;font-size:13px;text-align:center;border-radius:6px;padding:.6rem}
+  .dw-cu__status--ok{background:#eef6ee;color:#2f6b2f;border:1px solid #cfe4cf}
+  .dw-cu__status--err{background:#fdf1f1;color:#8b2f2f;border:1px solid #f0d4d4}
+  @media(max-width:769px){.dw-cu{margin:20px 0 4px}.dw-cu__row{grid-template-columns:1fr}.dw-cu__direct .dw-cu__btn{flex:1 1 100%;text-align:center}}
+
+  /* ------------------------------------------------------------------ *
+   * BELT AND BRACES (TK-11925). The contact-us template omits the price *
+   * and form blocks entirely, so none of the below should ever exist on *
+   * these PDPs. This hides anything price / cart / sample shaped if a   *
+   * block is re-added in the theme editor or an app injects one.        *
+   * Class inventory measured from snippets/product-form-content.liquid. *
+   * ------------------------------------------------------------------ */
+  body.template-suffix-contact-us .product__price,
+  body.template-suffix-contact-us .product__form,
+  body.template-suffix-contact-us .product-price,
+  body.template-suffix-contact-us .product-price__unit-price,
+  body.template-suffix-contact-us [data-product-form] .product__form,
+  body.template-suffix-contact-us [data-product-form] .product__price,
+  body.template-suffix-contact-us .cfp-section,
+  body.template-suffix-contact-us .dw-quote-section,
+  body.template-suffix-contact-us .dw-sample-banner,
+  body.template-suffix-contact-us .add-to-cart,
+  body.template-suffix-contact-us .dl-sample-btn,
+  body.template-suffix-contact-us .dl-second-sample-btn,
+  body.template-suffix-contact-us .product-options,
+  body.template-suffix-contact-us .mm_quantity,
+  body.template-suffix-contact-us .shopify-payment-button,
+  body.template-suffix-contact-us .product-form__buy-buttons,
+  body.template-suffix-contact-us .quick-shop-modal-trigger,
+  body.template-suffix-contact-us .product-details .money,
+  body.template-suffix-contact-us .min-order-notice,
+  body.template-suffix-contact-us [data-min-order-notice],
+  body.template-suffix-contact-us .product-option-quantity-label,
+  body.template-suffix-contact-us .dw-sample-cta,
+  body.template-suffix-contact-us [data-sample-add],
+  .dw-contact-us-product .product__price,
+  .dw-contact-us-product .product__form,
+  .dw-contact-us-product .product-price,
+  .dw-contact-us-product .product-price__unit-price,
+  .dw-contact-us-product [data-product-form] .product__form,
+  .dw-contact-us-product [data-product-form] .product__price,
+  .dw-contact-us-product .cfp-section,
+  .dw-contact-us-product .dw-quote-section,
+  .dw-contact-us-product .dw-sample-banner,
+  .dw-contact-us-product .add-to-cart,
+  .dw-contact-us-product .dl-sample-btn,
+  .dw-contact-us-product .dl-second-sample-btn,
+  .dw-contact-us-product .product-options,
+  .dw-contact-us-product .mm_quantity,
+  .dw-contact-us-product .shopify-payment-button,
+  .dw-contact-us-product .product-form__buy-buttons,
+  .dw-contact-us-product .quick-shop-modal-trigger,
+  .dw-contact-us-product .product-details .money,
+  .dw-contact-us-product .min-order-notice,
+  .dw-contact-us-product [data-min-order-notice],
+  .dw-contact-us-product .product-option-quantity-label,
+  .dw-contact-us-product .dw-sample-cta,
+  .dw-contact-us-product [data-sample-add]{display:none!important}
+  /* TK-11925 review: .dw-contact-us-product covers the quick-shop modal + any non-PDP context; min-order notice lives outside the block loop. */
+</style>
+
+<script>
+(function(){
+  var root=document.getElementById('dw-cu-{{ dw_cu_uid }}');
+  if(!root||root.dataset.dwCuWired==='1')return;
+  root.dataset.dwCuWired='1';
+  var form=root.querySelector('.dw-cu__form');
+  var status=root.querySelector('.dw-cu__status');
+  var submit=root.querySelector('.dw-cu__submit');
+  function say(msg,ok){
+    status.hidden=false;
+    status.textContent=msg;
+    status.className='dw-cu__status '+(ok?'dw-cu__status--ok':'dw-cu__status--err');
+  }
+  function val(name){var el=root.querySelector('[data-f="'+name+'"]');return el?String(el.value||'').trim():'';}
+  form.addEventListener('submit',function(e){
+    e.preventDefault();
+    if(!val('name')||!val('email')||!val('role')){say('Please fill in your name, email and role.',false);return;}
+    var payload={
+      productId:val('productId'), productTitle:val('productTitle'), sku:val('sku'),
+      name:val('name'), email:val('email'), phone:val('phone'), company:val('company'),
+      role:val('role'), quantity:val('quantity'), unit:val('unit'),
+      projectName:val('projectName'), city:val('city'), timeline:val('timeline'),
+      budget:val('budget'), notes:val('notes')
+    };
+    submit.disabled=true;
+    var old=submit.textContent; submit.textContent='Sending…';
+    fetch('https://api.designerwallcoverings.com/api/sku-inquiry',{
+      method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)
+    }).then(function(r){return r.json().catch(function(){return {success:r.ok};});})
+      .then(function(j){
+        if(j&&j.success){
+          say('Thank you — your inquiry was received. We reply within 1 business day.'+(j.requestId?' Reference: '+j.requestId:''),true);
+          form.querySelectorAll('input:not([type=hidden]),select,textarea').forEach(function(n){if(n.type!=='hidden')n.value='';});
+        } else {
+          say((j&&j.message)||'Something went wrong. Please call (888) 373-4564 or email info@designerwallcoverings.com.',false);
+        }
+      })
+      .catch(function(err){
+        console.error('dw-cu submit',err);
+        say('Could not send your inquiry. Please email info@designerwallcoverings.com or call (888) 373-4564.',false);
+      })
+      .then(function(){submit.disabled=false;submit.textContent=old;});
+  });
+})();
+</script>
+{%- endif -%}
diff --git a/data/theme-preimage/145556635699/snippets/hide-browse-hidden.liquid b/data/theme-preimage/145556635699/snippets/hide-browse-hidden.liquid
index 5f19aa4..a2f8599 100644
--- a/data/theme-preimage/145556635699/snippets/hide-browse-hidden.liquid
+++ b/data/theme-preimage/145556635699/snippets/hide-browse-hidden.liquid
@@ -83,3 +83,29 @@
   is "addressable but not discoverable". Regenerate the asset whenever the tagged set changes.
 {%- endcomment -%}
 <script src="{{ 'dw-showroom-hide.js' | asset_url }}" defer></script>
+
+{%- comment -%}
+  TK-11925 — "contact us" pricing treatment for Boost-rendered browse/search grids.
+  Boost renders those grids client-side, so the Liquid path in product-list-item.liquid
+  never runs for them. dw-contact-us-cards.js sweeps .boost-sd__product-item cards and
+  swaps the price for "Contact us for pricing" for the vendors listed below.
+
+  DATA-DRIVEN, mirroring the showroom_vendors pattern above:
+    1. shop metafield custom.contact_us_vendors (comma-separated; store-wide)
+    2. theme setting  settings.contact_us_vendors (comma-separated)
+    3. literal fallback: Designers Guild, Ralph Lauren, Christian Lacroix Europe, Nina Campbell
+{%- endcomment -%}
+{%- liquid
+  assign contact_us_raw = shop.metafields.custom.contact_us_vendors
+  if contact_us_raw == blank
+    assign contact_us_raw = settings.contact_us_vendors
+  endif
+  if contact_us_raw == blank
+    assign contact_us_raw = 'Designers Guild,Ralph Lauren,Christian Lacroix Europe,Nina Campbell'
+  endif
+  assign contact_us_vendors = contact_us_raw | split: ','
+-%}
+<script>
+window.DW_CONTACT_US_VENDORS = [{%- for v in contact_us_vendors -%}{%- assign vt = v | strip -%}{%- if vt != blank -%}{{ vt | json }}{%- unless forloop.last -%},{%- endunless -%}{%- endif -%}{%- endfor -%}];
+</script>
+<script src="{{ 'dw-contact-us-cards.js' | asset_url }}" defer></script>
diff --git a/data/theme-preimage/145556635699/snippets/product-list-item.liquid b/data/theme-preimage/145556635699/snippets/product-list-item.liquid
index 6aa3c27..14bd6e8 100644
--- a/data/theme-preimage/145556635699/snippets/product-list-item.liquid
+++ b/data/theme-preimage/145556635699/snippets/product-list-item.liquid
@@ -197,7 +197,14 @@
       </p>
     {%- endif -%}
 
-    {% if item.vendor == 'Newmor Wallcoverings' %}
+    {%- comment -%} TK-11925: liquid-rendered card path for the contact-us cohort
+      (Designers Guild / Ralph Lauren / Christian Lacroix Europe). Keyed on the product's
+      TEMPLATE SUFFIX, not a vendor literal, so the card follows whatever set
+      scripts/assign-template.mjs has stamped — no second list to keep in sync.
+      Boost-rendered grids are handled by assets/dw-contact-us-cards.js. {%- endcomment -%}
+    {% if item.template_suffix == 'contact-us' %}
+    <p class="product-list-item-price dw-cu-card-price" data-dw-contact-us-price>Contact us for pricing</p>
+    {% elsif item.vendor == 'Newmor Wallcoverings' %}
     <p class="product-list-item-price" data-newmor-showroom>Showroom inquiry</p>
     {% else %}
     <p class="product-list-item-price">
diff --git a/data/theme-preimage/145556635699/snippets/product.liquid b/data/theme-preimage/145556635699/snippets/product.liquid
index 5094666..0df9c53 100644
--- a/data/theme-preimage/145556635699/snippets/product.liquid
+++ b/data/theme-preimage/145556635699/snippets/product.liquid
@@ -41,6 +41,7 @@
 <div
   class="
     product
+    {% if product.template_suffix == 'contact-us' %}dw-contact-us-product{% endif %}
     {% if images_layout == 'masonry' %}
       product-masonry
     {% endif %}
@@ -73,6 +74,12 @@
     enable_zoom: enable_zoom,
   %}
 
+  {%- comment -%} TK-11925: contact-us treatment. Renders the inquiry block directly BELOW the
+    image column for products on templates/product.contact-us.json (Designers Guild, Ralph
+    Lauren, Christian Lacroix Europe). The snippet self-gates on template.suffix too, so this
+    is a no-op on every other product. Purely additive. {%- endcomment -%}
+  {% if product.template_suffix == 'contact-us' %}{% render 'dw-contact-us-block', product: product %}{% endif %}
+
   <div class="product-details-wrapper">
     <div class="product-details">
       {% if product.vendor == 'Newmor Wallcoverings' %}
diff --git a/data/verify-latest.json b/data/verify-latest.json
index 872f3ea..34d34cf 100644
--- a/data/verify-latest.json
+++ b/data/verify-latest.json
@@ -1,7 +1,7 @@
 {
-  "ts": "2026-09-20T19:10:53.612Z",
-  "verdict": "FAIL",
-  "fail": 20,
+  "ts": "2026-09-20T19:25:48.165Z",
+  "verdict": "WARN",
+  "fail": 0,
   "not_measured": 20,
   "population": 1218,
   "observed": 20,
@@ -44,8 +44,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -102,8 +102,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -160,8 +160,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -218,8 +218,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -276,8 +276,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -334,8 +334,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -392,8 +392,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -450,8 +450,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -508,8 +508,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -566,8 +566,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -624,8 +624,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -682,8 +682,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -740,8 +740,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -798,8 +798,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -856,8 +856,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -914,8 +914,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -972,8 +972,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -1030,8 +1030,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -1088,8 +1088,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
@@ -1146,8 +1146,8 @@
           "detail": "none in product details"
         },
         "no_sample_button": {
-          "verdict": "FAIL",
-          "detail": "sample UI in product details"
+          "verdict": "PASS",
+          "detail": "none in product details"
         },
         "body_class": {
           "verdict": "PASS",
diff --git a/scripts/verify.mjs b/scripts/verify.mjs
index 5360815..2de6f5f 100644
--- a/scripts/verify.mjs
+++ b/scripts/verify.mjs
@@ -98,7 +98,12 @@ for (const p of sample) {
       set('no_add_to_cart', cart ? 'FAIL' : 'PASS', cart ? 'add-to-cart markup in product details' : 'none in product details');
       const priced = /class="product__price"|class="product__form"|class="money"|<span class="money">/.test(details);
       set('no_price_markup', priced ? 'FAIL' : 'PASS', priced ? 'price/form markup in product details' : 'none in product details');
-      const smpBtn = /dl-sample-btn|dl-second-sample-btn|Complimentary Sample/.test(details);
+      // Match a RENDERED sample button via its class attribute, NOT the bare token: theme.liquid's
+      // `.dl-sample-btn` querySelector JS (lines 731/764) + locale/quick-shop templates put the bare
+      // string inside the scope window even on a clean page (verified live 2026-09-20:
+      // real_sample_btn_elements=0 on DG/RL/CL samples). This mirrors no_add_to_cart / no_price_markup
+      // above, which already require class="…", and still FAILs on a real <button class="dl-sample-btn">.
+      const smpBtn = /class="[^"]*\bdl-sample-btn\b|class="[^"]*\bdl-second-sample-btn\b/.test(details);
       set('no_sample_button', smpBtn ? 'FAIL' : 'PASS', smpBtn ? 'sample UI in product details' : 'none in product details');
     }
     set('body_class', /template-suffix-contact-us/.test(html) ? 'PASS' : 'FAIL', 'body.template-suffix-contact-us hook');
diff --git a/theme/snippets/product.liquid b/theme/snippets/product.liquid
index 0df9c53..c622441 100644
--- a/theme/snippets/product.liquid
+++ b/theme/snippets/product.liquid
@@ -82,6 +82,13 @@
 
   <div class="product-details-wrapper">
     <div class="product-details">
+      {%- comment -%} TK-11925: on contact-us pages the ENTIRE buy box (price / add-to-cart /
+        sample button / min-order notice — all emitted by product-form-content) is ABSENT, not
+        just CSS-hidden. The dw-contact-us-block above is the whole call-to-action. Scoped to
+        template.suffix so every other product is unaffected. Fixes verify no_sample_button FAIL
+        + min_order_notice WARN (out-of-loop-snippet leak class, memory
+        shopify-no-price-page-has-three-leak-paths). {%- endcomment -%}
+      {% unless product.template_suffix == 'contact-us' %}
       {% if product.vendor == 'Newmor Wallcoverings' %}
         <div data-product-form>
           {% render 'product-form-content', product: product, form: nil, show_social_media_icons: show_social_media_icons, show_payment_button: false %}
@@ -107,6 +114,7 @@
           %}
         </div>
       {% endif %}
+      {% endunless %}
     </div>
     {% render 'product-description-meta' %}
   </div>

← e4395de auto-data-snapshot: 2026-09-20T12:15:15 (5 data files) — dat  ·  back to Dw Contact Us Pages  ·  TK-11925: verify.mjs honesty fixes (Cody red-team) — min_ord f836f4d →