← back to Dw Unbuyable Recovery Pilot
TK-11041: portal-pull script written + self-tested (7/7), waiting only on the credential paste
0e2141a63c7b53a7bb4b170cc084c87e381a999c · 2026-09-11 11:19:47 -0700 · Steve Abrams
Converts the runbook from prose into a one-command run. Ships with negative tests:
the real captured logged-out /item/costine page must classify SESSION_FAILURE and yield
no price, and a $0.00 token must be rejected — a positive-only test on a detector
proves nothing. Credential-absent run exits 2 without opening a session ($0).
Corrects the runbook: Browserbase solves the reCAPTCHA natively (solveCaptchas:true),
no separate 2captcha call needed. 39 live items resolve to 7 pattern pages, one session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGo6pAQho6w9xgqghMgNKh
Files touched
M tk11041-innovations-reconcile/rescrape/PORTAL-PULL-RUNBOOK.mdA tk11041-innovations-reconcile/rescrape/fixtures/logged-out-costine.htmlA tk11041-innovations-reconcile/rescrape/innovations-trade-pull.js
Diff
commit 0e2141a63c7b53a7bb4b170cc084c87e381a999c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Sep 11 11:19:47 2026 -0700
TK-11041: portal-pull script written + self-tested (7/7), waiting only on the credential paste
Converts the runbook from prose into a one-command run. Ships with negative tests:
the real captured logged-out /item/costine page must classify SESSION_FAILURE and yield
no price, and a $0.00 token must be rejected — a positive-only test on a detector
proves nothing. Credential-absent run exits 2 without opening a session ($0).
Corrects the runbook: Browserbase solves the reCAPTCHA natively (solveCaptchas:true),
no separate 2captcha call needed. 39 live items resolve to 7 pattern pages, one session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGo6pAQho6w9xgqghMgNKh
---
.../rescrape/PORTAL-PULL-RUNBOOK.md | 65 +-
.../rescrape/fixtures/logged-out-costine.html | 1401 ++++++++++++++++++++
.../rescrape/innovations-trade-pull.js | 218 +++
3 files changed, 1664 insertions(+), 20 deletions(-)
diff --git a/tk11041-innovations-reconcile/rescrape/PORTAL-PULL-RUNBOOK.md b/tk11041-innovations-reconcile/rescrape/PORTAL-PULL-RUNBOOK.md
index f4dfb8b..98849b9 100644
--- a/tk11041-innovations-reconcile/rescrape/PORTAL-PULL-RUNBOOK.md
+++ b/tk11041-innovations-reconcile/rescrape/PORTAL-PULL-RUNBOOK.md
@@ -22,26 +22,51 @@ trade-portal precedent. **Do not hand-edit the env files.**
| Account | **58315**, and every DW sample request states **"Net Less 20%"** |
## Consequence: this needs a real browser, not curl
-reCAPTCHA rules out a plain fetch login. Run it through the **`browserbase`** skill (cloud Chromium)
-with **`2captcha`** for the solve — both are already credentialed. Login is a **one-time session**;
-cache cookies and reuse them so we solve one captcha, not 39.
-
-**Estimated cost:** ~**$0.003** per captcha solve + one Browserbase session (a few cents). Call it
-**well under $0.10** for the whole pull if the session is cached. Actual will be logged to the cost
-ledger. Everything up to this point in the ticket has been **$0**.
-
-## The pull, in order
-1. `secrets` skill → confirm `INNOVATIONS_USERNAME` / `INNOVATIONS_PASSWORD` resolve (last-4 digest only).
-2. Browserbase session → `https://www.innovationsusa.com/login`, 2captcha solve, authenticate, **persist cookies**.
-3. For each of the **39 live-pattern** `mfr_sku` in `data/innovations-identity-map.json`
- (`site_state=="live"` — i.e. everything except the 12 WHL), fetch its `product_url` **authenticated**
- and extract the net price + unit. Throttle ~0.35s as the public sweep did.
-4. **Assert before trusting:** a price must be present and numeric, and the unit must be captured.
- A page that returns the logged-out shell (no price) is a **session failure, not a $0 price** — fail
- loud rather than recording zero. This is the rule the $0-orderable lineage exists to enforce.
-5. Reconcile the discount: registry says **10%**, every sample request says **Net Less 20%**. Do **not**
- compute retail until that is settled — a 10-point cost-basis error propagates through `cost/0.65/0.85`.
-6. Stage results, then the **gated** add-yard recovery for the 39. Nothing goes to Shopify unprompted.
+reCAPTCHA rules out a plain fetch login. The pull runs through the **`browserbase`** skill (cloud
+Chromium). **Correction to the 2026-09-11 recon:** a separate 2captcha call is *not* needed —
+Browserbase solves captchas natively via `browserSettings: { solveCaptchas: true }`, which is what
+the script uses. Login is a **one-time session**; the 39 live items resolve to only **7 pattern
+pages**, so one session covers the whole pull.
+
+**Estimated cost:** one Browserbase session, a few cents. Actual to be logged to the cost ledger.
+Everything in this ticket so far has been **$0**.
+
+## The script — written and self-tested 2026-09-11, waiting only on the paste
+`~/.claude/skills/browserbase/innovations-trade-pull.js` (copy committed here as
+`innovations-trade-pull.js`), alongside `romo-trade-pull.js` / `koroseal-trade-portal.js` where the
+deps and `.env` already live.
+
+```
+node innovations-trade-pull.js --selftest # $0, no network — proves the extractor goes RED on a
+ # real logged-out page. Run this first, always.
+node innovations-trade-pull.js --probe # login + auth proof + ONE pattern page
+node innovations-trade-pull.js # full pull, 7 live pattern pages
+```
+
+**Verified today, before any credential exists:**
+- `--selftest` → **7/7 PASS**, including the two that matter: the real captured logged-out
+ `/item/costine` page classifies `SESSION_FAILURE` and yields **no price**, and a `$0.00` token is
+ rejected rather than recorded. Fixture: `fixtures/logged-out-costine.html`.
+- `--probe` with no credentials → **exits 2, fails loud, opens no session, spends nothing.**
+
+**The safety contract, in the code rather than in prose:**
+1. Login is **positively proven** (an account marker present *and* "Sign In" absent) before any
+ page is fetched. An error-free login is not a proven session.
+2. Auth is re-asserted on **every** page — a portal can drop a session mid-run and keep serving 200s.
+3. Three states, never two: `MEASURED` / `NOT_MEASURED` (authed, no price) / `SESSION_FAILURE`
+ (auth unproven → **aborts the run** rather than record false absences). A page with no price is
+ never a `$0` price — the `$0`-orderable lineage is exactly why.
+4. `retail_computed: false` is written into the output with the reason, so the discount conflict
+ cannot be skipped silently downstream.
+5. No DB write, no Shopify write. Output is staged JSON in `data/portal-pull-<ts>.json`.
+6. robots-compliant: `/item/<slug>/` is `Allow`; `/item/*/*` is `Disallow` (and 500s), so only the
+ 7 pattern pages are fetched — never per-colorway URLs.
+
+## Still blocking the pull
+1. **The credential paste** (`INNOVATIONS_USERNAME` / `INNOVATIONS_PASSWORD`) — Steve only.
+2. **The discount** — registry says **10%**, every sample request says **Net Less 20%**. The script
+ refuses to compute retail until this is settled; a 10-point cost-basis error propagates through
+ `cost/0.65/0.85` to customers.
## The 12 Whistler items are NOT in this pull
They're discontinued and 404 on the vendor site; no logged-in page exists to price. Their answer comes
diff --git a/tk11041-innovations-reconcile/rescrape/fixtures/logged-out-costine.html b/tk11041-innovations-reconcile/rescrape/fixtures/logged-out-costine.html
new file mode 100644
index 0000000..08899b8
--- /dev/null
+++ b/tk11041-innovations-reconcile/rescrape/fixtures/logged-out-costine.html
@@ -0,0 +1,1401 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<meta name="author" content="Innovations USA"/>
+<meta name="copyright" content="2026 Innovations USA"/>
+<meta name="google-site-verification" content="fwG59bSL46ILopf4a-dxcCFolREpK5hG3jx0M07dujU" />
+<meta name="facebook-domain-verification" content="mep3j3g0n6lflop29olu2miwkc02sl" />
+<meta name="csrf-token" content="OUtlvikrTZc3lF5NAoS0EK9BLV06oFQhUu8JOilq">
+<meta name="robots" content="max-image-preview:large">
+
+<!-- DNS Prefetch for external domains -->
+<link rel="dns-prefetch" href="https://connect.facebook.net">
+<link rel="dns-prefetch" href="https://www.googletagmanager.com">
+<link rel="dns-prefetch" href="https://www.google-analytics.com">
+<link rel="dns-prefetch" href="https://maxcdn.bootstrapcdn.com">
+<link rel="dns-prefetch" href="https://use.typekit.net">
+
+<!-- Preconnect to critical domains -->
+<link rel="preconnect" href="https://connect.facebook.net" crossorigin>
+
+
+<title>Costine | Innovations in Wallcovering</title>
+<meta name="description" content="A contemporary update to a timeless design, Costine offers durable wall protection in a high-performance vinyl wallcovering suitable for th...">
+<meta name="keywords" content="Vinyl
+Dense Polyester Cotton Drill Wallcovering, ASTM E84 - Class A, Dense Polyester Cotton Drill, Made in US, Innovations in Wallcoverings">
+<meta property="og:description" content="A contemporary update to a timeless design, Costine offers durable wall protection in a high-performance vinyl wallcovering suitable for th...">
+<meta property="og:title" content="Costine">
+<meta property="og:type" content="product">
+<meta property="og:locale" content="en-US">
+<meta property="og:url" content="https://www.innovationsusa.com/item/costine">
+
+<meta name="twitter:title" content="Costine">
+<meta name="twitter:site" content="@InnovationsUSA">
+<script type="application/ld+json">{"@context":"https://schema.org","@type":"Product","name":"Costine","description":"A contemporary update to a timeless design, Costine offers durable wall protection in a high-performance vinyl wallcovering suitable for the most heavily trafficked areas. The deeply embossed vertical stripes are designed to absorb impact in areas where it is needed most. The dimensional stripes are enhanced by a color palette in hues like silver and pearl with a hint of shine. This versatile product is ideal for a wide range of applications from residential to commercial, the possibilities are endless."}</script>
+
+<!-- Favicon -->
+<link rel="apple-touch-icon" sizes="76x76" href="/images/icons/apple-touch-icon.png">
+<link rel="icon" type="image/png" sizes="32x32" href="/images/icons/favicon-32x32.png">
+<link rel="icon" type="image/png" sizes="16x16" href="/images/icons/favicon-16x16.png">
+<link rel="manifest" href="/images/icons/site.webmanifest">
+<link rel="mask-icon" href="/images/icons/safari-pinned-tab.svg" color="#5bbad5">
+<meta name="msapplication-TileColor" content="#da532c">
+<meta name="theme-color" content="#ffffff">
+<!-- Meta Pixel Code - Load after page is interactive -->
+<script>
+(function() {
+ function initFacebookPixel() {
+ !function(f,b,e,v,n,t,s)
+ {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};
+ if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
+ n.queue=[];t=b.createElement(e);t.async=!0;
+ t.src=v;s=b.getElementsByTagName(e)[0];
+ s.parentNode.insertBefore(t,s)}(window, document,'script',
+ 'https://connect.facebook.net/en_US/fbevents.js');
+ fbq('init', '771032708813581');
+ fbq('track', 'PageView');
+ }
+
+ // Load after page is interactive
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', function() {
+ setTimeout(initFacebookPixel, 500);
+ });
+ } else {
+ setTimeout(initFacebookPixel, 500);
+ }
+})();
+</script>
+<noscript><img height="1" width="1" style="display:none"
+src="https://www.facebook.com/tr?id=771032708813581&ev=PageView&noscript=1"
+/></noscript>
+<!-- End Meta Pixel Code -->
+<!-- Google Analytics -->
+<script>
+ window.dataLayer = window.dataLayer || [];
+ function gtag(){dataLayer.push(arguments);}
+ function getCookie(cookieName) {
+ const cookies = document.cookie.split(';').map(cookie => cookie.trim());
+ for (let i = 0; i < cookies.length; i++) {
+ const parts = cookies[i].split('=');
+ const name = parts[0];
+ const value = parts[1];
+ if (name === cookieName) {
+ return decodeURIComponent(value);
+ }
+ }
+ return null;
+ }
+ if(getCookie('gdpr')){
+ gtag('consent', 'default', {
+ 'ad_storage': 'granted',
+ 'ad_user_data': 'granted',
+ 'ad_personalization': 'granted',
+ 'analytics_storage': 'granted'
+ });
+ } else {
+ gtag('consent', 'default', {
+ 'ad_storage': 'denied',
+ 'ad_user_data': 'denied',
+ 'ad_personalization': 'denied',
+ 'analytics_storage': 'denied'
+ });
+ }
+ gtag('js', new Date());
+ gtag('config', 'G-CVVYLRG5BJ');
+</script>
+<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVVYLRG5BJ"></script>
+
+<!-- Styles -->
+<link rel="canonical" href="https://www.innovationsusa.com/item/costine" />
+<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
+<link rel="stylesheet" href="https://use.typekit.net/lmn1uve.css">
+<link rel="stylesheet" type="text/css" href="https://www.innovationsusa.com/css/app.css?v=2.55"/>
+<!-- Scripts -->
+<script type="text/javascript">
+ document.cookie='size='+Math.max(screen.width)+';';
+</script>
+
+<!-- This swiper used for the slider/carousel -->
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
+<style>
+ #dye-lots-content {
+ max-height: 0;
+ overflow: hidden;
+ transition: max-height 0.5s ease-out;
+ }
+ #dye-lots-content.expanded {
+ max-height: 500px;
+ }
+ #dye-lots-content th{
+ padding: 0px 14px
+ }
+ #dye-lots-content td{
+ border: none;
+ padding: 0px 14px;
+ color: #000;
+ font-size: 16px;
+ }
+
+ .swiper {
+ width: 100%;
+ height: 100%;
+ }
+
+ .swiper-slide {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: hidden;
+ }
+
+ .swiper-slide img {
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+ .swiper-button-next {
+ right: 0;
+ justify-content: right;
+ }
+ .swiper-button-prev {
+ left: 0 !important;
+ justify-content: left !important;
+ }
+ .swiper-button-next, .swiper-button-prev {
+ color: #ffffff;
+ }
+ .swiper-button-next:hover, .swiper-button-prev:hover {
+ color: #000000;
+ }
+ .swiper-button-next:after, .swiper-button-prev:after {
+ font-size: 25px !important;
+ font-weight: bold !important;
+ }
+ .yardage-button {
+ flex-grow: 1;
+ text-decoration: none;
+ font-weight: 400;
+ max-width: 300px;
+ min-width: 200px;
+ }
+ .yardage-button:hover {
+ font-weight: 400;
+ text-decoration: none;
+ }
+ .order-button, #order-sku-button {
+ flex-grow: 1;
+ max-width:300px;
+ min-width:200px;
+ }
+ #order-sku-button > button {
+ background-color: transparent !important;
+ color: white;
+ border: none;
+ padding: 0;
+ align-content: center;
+ text-align: center;
+ }
+ #sustainabilityCertModal .modal-dialog {
+ background-color: transparent;
+ padding: 0;
+ max-width: 600px;
+ margin: 1.75rem auto;
+ }
+ #sustainabilityCertModal .modal-content {
+ border: none;
+ border-radius: 0;
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
+ }
+ #sustainabilityCertModal .sustainability-cert-body {
+ display: flex;
+ align-items: center;
+ text-align: left;
+ }
+ #sustainabilityCertModal .sustainability-cert-icon {
+ width: 56px;
+ height: 56px;
+ flex-shrink: 0;
+ margin-right: 16px;
+ }
+ #sustainabilityCertModal .sustainability-cert-text {
+ flex: 1;
+ }
+ #sustainabilityCertModal .sustainability-cert-title {
+ color: #000;
+ font-size: 16px;
+ font-weight: 700;
+ line-height: 1.35;
+ margin-bottom: 8px;
+ }
+ #sustainabilityCertModal .sustainability-cert-copy {
+ color: #000;
+ font-size: 16px;
+ line-height: 1.5;
+ margin-bottom: 0;
+ }
+ #sustainabilityCertModal .sustainability-cert-copy a {
+ color: #000;
+ text-decoration: underline;
+ }
+</style>
+</head>
+<body >
+
+<div class="navbar navbar-expand-lg navbar-light justify-content-center px-5">
+ <div class="row px-0 col-md-12 col-xl-12 col-sm-12 flex-nowrap">
+ <div class="col-md-3 px-0 col-xl-3 col-sm-12 d-flex justify-content-center">
+ </div>
+ <div class="col-md-6 px-0 col-xl-6 col-sm-12 d-flex justify-content-center">
+ <a class="navbar-brand col-xl-6 col-lg-6 col-sm-12 mx-0 my-2" href="/" >
+ <img class="brand-img" src="/images/innovations-grey-logo-old.svg">
+ </a>
+ </div>
+ <div class="right-nav col-md-3 px-0 col-xl-3 col-sm-12 d-flex justify-content-end align-items-center" style="position: relative;">
+ <ul class=" navbar-nav d-flex align-items-center">
+ <li class="nav-item search">
+ <div id="navsearch-btn" class="search-label"></div>
+ </li>
+ <li class="desktop-cart nav-item mx-3">
+ <a href="/login" class="nav-link shoppingbag py-0 d-flex align-items-center">
+ <img src="https://www.innovationsusa.com/images/icons/shoppingbag1.svg" alt="Shopping Bag Icon">
+ </a>
+ </li>
+
+ <li class="nav-item">
+ <a class="nav-link py-0 login-label" href="/login">SIGN IN</a>
+ </li>
+
+ </ul>
+ <div id="cart-notification-root"></div>
+ </div>
+ </div>
+</div>
+<nav class="navbar navbar-expand-lg navbar-light px-0 ">
+ <label class="hamburger_toggle m-0 ml-4" for="menu">
+ <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="#FA4616" stroke-width="1" stroke-linecap="butt" stroke-linejoin="arcs"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
+ </label>
+ <input type="checkbox" id="menu" name="menu" class="m-menu__checkbox">
+ <label class="m-menu__overlay" for="menu"></label>
+ <div class="nav-dropdowns col-sm-12 fade hide border-top" id="nav-dropdowns">
+ <div class="mx-auto products-menu collapse">
+ <div class="row mx-auto products-menu-container align-items-start">
+ <!-- Spacer to align with nav items -->
+ <div class="col-md-1 offset-products-left"></div>
+
+ <!-- Left Column: EXPLORE BY (aligned with PRODUCTS) -->
+ <div class="p-0 col-md-3 explore-by-column">
+ <ul class="menu-1 explore-by-section">
+ <li class="p-0 title text-orange">EXPLORE BY</li>
+ <li><a href="/product-categories/explore-by-texture-and-finish">Texture & Finish</a></li>
+ <li><a href="/product-categories/explore-by-wallcovering-type">Wallcovering Type</a></li>
+ <li><a href="/product-categories/explore-by-color">Color</a></li>
+ <li><a href="/product/all-wallcovering?material=contract+rated">Contract Rated</a></li>
+ <li><a href="/product/environmental">Eco-Friendly</a></li>
+ </ul>
+ </div>
+
+ <!-- Middle Column: DESIGN RESOURCES (aligned with DISCOVER) -->
+ <div class="p-0 col-md-3 design-resources-column">
+ <ul class="menu-1 design-resources-section">
+ <li class="p-0 title text-orange">DESIGN RESOURCES</li>
+ <li><a href="/custom-studio">Custom Studio</a></li>
+ <li><a href="/yardage-calculator">Yardage Calculator</a></li>
+ <li><a href="/cart/sample">Sample Order</a></li>
+ </ul>
+ </div>
+
+ <!-- Right Column: Featured Image (aligned with RESOURCES) -->
+ <div class="p-0 col-md-4 products-image-column">
+ <img class="products-featured-img" src="/images/menu/menu1.jpg" alt="Featured Product">
+ </div>
+
+ <div class="col-md-1"></div>
+ </div>
+
+ <!-- Bottom CTAs -->
+ <div class="row mx-auto products-bottom-ctas">
+ <!-- Spacer to align with nav items -->
+ <div class="col-md-1"></div>
+
+ <div class="p-0 col-md-3 cta-wrapper">
+ <div class="cta-link">
+ <a href="/product/all-wallcovering">VIEW ALL WALLCOVERINGS<img class="ml-2 arrow-up-right" src="/images/icons/arrow-cta-02.svg"></a>
+ </div>
+ </div>
+ <div class="p-0 col-md-3 cta-wrapper">
+ <div class="cta-link">
+ <a href="/product/faux-leather">VIEW ALL FAUX LEATHER<img class="ml-2 arrow-up-right" src="/images/icons/arrow-cta-02.svg"></a>
+ </div>
+ </div>
+ <div class="p-0 col-md-4 cta-wrapper">
+ <div class="cta-link">
+ <a href="/product/collection/spring-2026">DISCOVER THE NEW COLLECTION<img class="ml-2 arrow-up-right" src="/images/icons/arrow-cta-02.svg"></a>
+ </div>
+ </div>
+
+ <div class="col-md-1"></div>
+ </div>
+ </div>
+ <div class="col-sm-12 mx-auto discover-menu collapse">
+ <div class="row col-md-10 mx-auto" style="padding: 0px 0.5rem;">
+ <div class="col-md-4 d-flex flex-row">
+ <ul class="menu-1 d-flex flex-column justify-content-around">
+ <li><a class="title-link" href="/projects" >Projects</a></li>
+ <li><a class="title-link" href="/mentions" >Press Mentions</a></li>
+ <li><a class="title-link" href="/catalogs" >Catalogs</a></li>
+ </ul>
+ </div>
+ <div class="col-md-4 px-3">
+ <img class="wallcovering ml-0 w-100" src="/images/menu/menu-spring-2026.jpg">
+ </div>
+ <div class="col-md-4 px-3">
+ <img class="wallcovering ml-0 w-100" src="/images/menu/menu-fall-2025.jpg">
+ </div>
+ <div class="row justify-content-center">
+ </div>
+ </div>
+ <div class="row col-md-10 mx-auto bottom-link" style="padding: 0px 0.5rem;">
+ <div class="col-md-4">
+ </div>
+ <div class="col-md-4 px-3">
+ <ul class="discover-extlink d-flex flex-row ">
+ <li><a class="wallcovering" href="/catalogs/facade-spring-2026" >SPRING 2026 CATALOG<img class="ml-4 arrow-up-right" src="/images/icons/arrow-cta-02.svg"></a></li>
+ </ul>
+ </div>
+ <div class="col-md-4 px-3">
+ <ul class="discover-extlink d-flex flex-row ">
+ <li><a class="wallcovering" href="/catalogs/nightfall-fall-2025" >FALL 2025 CATALOG<img class="ml-4 arrow-up-right" src="/images/icons/arrow-cta-02.svg"></a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <div class="col-sm-12 mx-auto resources-menu collapse">
+ <div class="row col-md-10 mx-auto" style="padding: 0px 0.5rem;">
+ <div class="col-md-5 d-flex flex-row">
+ <ul class="menu-1 d-flex flex-column justify-content-around">
+ <li><a class="title-link" href="/client-success" >Contact Us</a></li>
+ <li><a class="title-link" href="/find-a-rep" >Find a Rep</a></li>
+ <li><a class="title-link" href="/presentation-request" >Request a Presentation</a></li>
+ <li><a class="title-link" href="/let-us-shop-for-you" >Concierge Services</a></li>
+ <li><a class="title-link" href="/faq" >FAQs</a></li>
+ <li><a class="title-link" href="/showrooms" >Showrooms</a></li>
+ <li><a class="title-link" href="/hanging-instructions-index" >Hanging Instructions</a></li>
+ <li><a class="title-link" href="/spec-sheets-index" >Spec Sheets</a></li>
+ </ul>
+ </div>
+ <div class="col-md-7">
+ <img class="wallcovering ml-0 w-100" src="/images/menu/menu3.jpg">
+ </div>
+ <div class="row justify-content-center">
+ </div>
+ </div>
+ </div>
+ <div class="col-sm-12 mx-auto aboutus-menu collapse">
+ <div class="row col-md-10 mx-auto" style="padding: 0px 0.5rem;">
+ <div class="col-md-4 d-flex flex-row">
+ <ul class="menu-1 d-flex flex-column justify-content-around">
+ <li><a class="title-link" href="/our-story" >Our Story</a></li>
+ <li><a class="title-link" href="/sustainability" >Sustainability</a></li>
+ <li><a class="title-link" href="/careers" >Careers</a></li>
+ </ul>
+ </div>
+ <div class="col-md-8">
+ <img class="wallcovering ml-0 w-100" src="/images/menu/menu4.jpg">
+ </div>
+ <div class="row justify-content-center">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="bg">
+ <a class="mobile-logo" href="/">
+ <img class="w-50 mobile-logo-img p-0 my-2" src="/images/innovations-grey-logo-old.svg">
+ </a>
+ </div>
+ <!-- -- -- MOBILE NAV -- -- -->
+ <div class="right-nav mobile">
+ <ul class="navbar-nav">
+ <li class="nav-item search">
+ <div id="navsearch-btn-mobile" class="search-label"></div>
+ </li>
+ <li class="nav-item cart">
+ <a href="/cart/sample" class="nav-link shoppingbag pb-0">
+ <img src="https://www.innovationsusa.com/images/icons/shoppingbag1.svg" alt="Shopping Bag Icon">
+ <span id='mobile-cart-count' class=""></span>
+ </a>
+ </li>
+ </ul>
+ </div>
+
+ <div class="navbar-collapse mx-auto px-0" id="navbarToggler1">
+ <div class="mx-auto">
+ <ul class="desktop navbar-nav col-10 m-auto px-0 desktop-navmenu1" id="desktop-navmenu">
+ <li class="nav-item dropdown">
+ <a class="nav-link products" href="#">PRODUCTS<span class="underline"></span></a>
+ </li>
+ <li class="nav-item dropdown">
+ <a class="nav-link discover" href="#">DISCOVER<span class="underline"></span></a>
+ </li>
+ <li class="nav-item dropdown">
+ <a class="nav-link resourceslink" href="#">RESOURCES<span class="underline"></span></a>
+ </li>
+ <li class="nav-item dropdown">
+ <a class="nav-link contactus" href="#">ABOUT US<span class="underline"></span></a>
+ </li>
+ </ul>
+ <ul class="desktop navbar-nav col-10 m-auto px-0 desktop-navmenu2" id="desktop-navmenu2">
+ <li class="nav-item">
+ <a class="nav-link" href="#">PRODUCTS<span class="underline"></span></a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#">DISCOVER<span class="underline"></span></a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#">RESOURCES<span class="underline"></span></a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link" href="#">ABOUT US<span class="underline"></span></a>
+ </li>
+ </ul>
+ <ul class="mobile navbar-nav">
+ <li class="nav-item">
+ <label class="nav-link dropdown-toggle label__chevron" for="level-1" role="button">PRODUCTS</label>
+ <input type="checkbox" id="level-1" name="level-1" class="m-menu__checkbox">
+ <div class="navbar-collapse mx-auto px-0" id="navbarToggler1">
+ <div class="m-menu__header">
+ <label class="m-menu__toggle" for="level-1">
+ <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="#FA4616" stroke-width="1" stroke-linecap="butt" stroke-linejoin="arcs">
+ <path d="M10 9l-6 6 6 6"></path>
+ </svg>
+ </label>
+ <span>PRODUCTS</span>
+ </div>
+ <ul id="navitemDropdown11" class="drop-down-ul">
+ <li class="first">
+ <input type="hidden" id="arrow-label1-value" value="EXPLORE BY" />
+ <div id="arrow-label1">
+ </div>
+ <ul id="navitemDropdown10" class=" collapse">
+ <li class="mb-4"><a class="dropdown-item" href="/product-categories/explore-by-texture-and-finish">Texture & Finish</a></li>
+ <li class="mb-4"><a class="dropdown-item" href="/product-categories/explore-by-wallcovering-type">Wallcovering Type</a></li>
+ <li class="mb-4"><a class="dropdown-item" href="/product-categories/explore-by-color">Color</a></li>
+ <li class="mb-4"><a class="dropdown-item" href="/product/all-wallcovering?material=contract+rated">Contract Rated</a></li>
+ <li class="mb-4"><a class="dropdown-item" href="/product/environmental">Eco-Friendly</a></li>
+ </ul>
+ </li>
+ <li class="first">
+ <input type="hidden" id="arrow-label2-value" value="DESIGN RESOURCES" />
+ <div id="arrow-label2">
+ </div>
+ <ul id="navitemDropdown20" class=" collapse">
+ <li class="mb-4"><a class="dropdown-item" href="/custom-studio">Custom Studio</a></li>
+ <li class="mb-4"><a class="dropdown-item" href="/yardage-calculator">Yardage Calculator</a></li>
+ <li class="mb-4"><a class="dropdown-item" href="/cart/sample">Sample Order</a></li>
+ </ul>
+ </li>
+ <li class="first"><a class="dropdown-item ext-link" href="/product/all-wallcovering"><span class="oragne-border-line">VIEW ALL WALLCOVERINGS<img class="arrow-up-right ml-3" src="/images/icons/arrow-cta-02.svg"></span></a></li>
+ <li class="first"><a class="dropdown-item ext-link" href="/product/faux-leather"><span class="oragne-border-line">VIEW ALL FAUX LEATHER<img class="arrow-up-right ml-3" src="/images/icons/arrow-cta-02.svg"></span></a></li>
+ <li class="first"><a class="dropdown-item ext-link" href="/product/collection/spring-2026"><span class="oragne-border-line">DISCOVER THE NEW COLLECTION<img class="arrow-up-right ml-3" src="/images/icons/arrow-cta-02.svg"></span></a></li>
+ </ul>
+ </div>
+ </li>
+ <li class="nav-item">
+ <label class="nav-link dropdown-toggle label__chevron" for="level-2" role="button">DISCOVER</label>
+ <input type="checkbox" id="level-2" name="level-2" class="m-menu__checkbox">
+ <div class="navbar-collapse mx-auto px-0" id="navbarToggler2">
+ <div class="m-menu__header">
+ <label class="m-menu__toggle" for="level-2">
+ <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="#FA4616" stroke-width="1" stroke-linecap="butt" stroke-linejoin="arcs">
+ <path d="M10 9l-6 6 6 6"></path>
+ </svg>
+ </label>
+ <span>DISCOVER</span>
+ </div>
+ <ul id="navitemDropdown22" class="drop-down-ul">
+ <li><a class="dropdown-item" href="/projects">Projects</a></li>
+ <li><a class="dropdown-item" href="/mentions">Press Mentions</a></li>
+ <li><a class="dropdown-item" href="/catalogs">Catalogs</a></li>
+ </ul>
+ </div>
+ </li>
+ <li class="nav-item">
+ <label class="nav-link dropdown-toggle label__chevron" for="level-3" role="button">RESOURCES</label>
+ <input type="checkbox" id="level-3" name="level-3" class="m-menu__checkbox">
+ <div class="navbar-collapse mx-auto px-0" id="navbarToggler3">
+ <div class="m-menu__header">
+ <label class="m-menu__toggle" for="level-3">
+ <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="#FA4616" stroke-width="1" stroke-linecap="butt" stroke-linejoin="arcs">
+ <path d="M10 9l-6 6 6 6"></path>
+ </svg>
+ </label>
+ <span>RESOURCES</span>
+ </div>
+ <ul id="navitemDropdown33" class="drop-down-ul">
+ <li><a class="dropdown-item" href="/client-success">Contact Us</a></li>
+ <li><a class="dropdown-item" href="/find-a-rep">Find a Rep</a></li>
+ <li><a class="dropdown-item" href="/presentation-request">Request a Presentation</a></li>
+ <li><a class="dropdown-item" href="/let-us-shop-for-you">Concierge Services</a></li>
+ <li><a class="dropdown-item" href="/faq">FAQs</a></li>
+ <li><a class="dropdown-item" href="/showrooms">Showrooms</a></li>
+ <li><a class="dropdown-item" href="/hanging-instructions-index">Hanging Instructions</a></li>
+ <li><a class="dropdown-item" href="/spec-sheets-index">Spec Sheets</a></li>
+ </ul>
+ </div>
+ </li>
+ <li class="nav-item">
+ <label class="nav-link dropdown-toggle label__chevron" for="level-4" role="button">ABOUT US</label>
+ <input type="checkbox" id="level-4" name="level-4" class="m-menu__checkbox">
+ <div class="navbar-collapse mx-auto px-0" id="navbarToggler4">
+ <div class="m-menu__header">
+ <label class="m-menu__toggle" for="level-4">
+ <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="#FA4616" stroke-width="1" stroke-linecap="butt" stroke-linejoin="arcs">
+ <path d="M10 9l-6 6 6 6"></path>
+ </svg>
+ </label>
+ <span>ABOUT US</span>
+ </div>
+ <ul id="navitemDropdown33" class="drop-down-ul">
+ <li><a class="dropdown-item" href="/our-story">Our Story</a></li>
+ <li><a class="dropdown-item" href="/sustainability">Sustainability</a></li>
+ <li><a class="dropdown-item" href="/careers">Careers</a></li>
+ </ul>
+ </div>
+ </li>
+ <li class="nav-item dropdown">
+ <a class="nav-link login" href="https://www.innovationsusa.com/login">SIGN IN</a>
+
+ </li>
+ </ul>
+ </div>
+ </div>
+</nav>
+<div id="search-box" class="collapsed">
+ <div id="search-input-container" class="w-full position-relative">
+ <input id="search-input" class="w-full" >
+ <img id="search-close-icon" src="https://www.innovationsusa.com/images/icons/x.svg" alt="xicon">
+ </div>
+</div><main style="min-height:70vh; flex:none;">
+ <div id="itemcontainer" class="container-fluid">
+ <div class="row d-flex">
+ <div class="itmSubmenuContainer col-12 col-lg-5">
+ <div id="detailSpecDiv">
+ <div class="imgContainer">
+ <img src="https://www.innovationsusa.com/storage/product-list/March2023/GAzgUWwFqll3Se6BLCYU.jpg?v=2.55"
+ alt="Costine radiant Vinyl wallcovering"
+ loading="eager"
+ decoding="async">
+ </div>
+ <div class="desktop" style="display: block">
+ <div class="share" style="margin:16px 0 20px;">
+ <a href="mailto:name@my-email.com?subject=InnovationsUSA&body=The%20Innovations%20Design%20Studio%20collaborates%20with%20artisans%20around%20the%20world%20to%20develop%20unique%20wallcoverings%2C%20textiles%2C%20and%20faux%20leathers%0D%0Ahttps%3A%2F%2Fwww.innovationsusa.com%2Fitem%2Fcostine" style=":hover: text-decoration: none">
+ <img src="/images/icons/email_icon.svg"
+ alt="email-icon"
+ width="24"
+ height="24"
+ loading="lazy"
+ decoding="async">
+ </a>
+ <div id='download-image-2' data-downimage="https://www.innovationsusa.com/storage/product-list/March2023/GAzgUWwFqll3Se6BLCYU.jpg?v=2.55" class="d-inline-block" style="float: inline-end;"></div>
+ </div>
+
+ <div class="swiper product-gallery">
+ <div class="swiper-wrapper">
+ <div class="swiper-slide gallery-item" data-bs-toggle="modal" data-bs-target="#productGalleryModal" data-slide-index="0">
+ <img src="/storage/product-detail/March2023/d2jbYyvlMtIoiHjQAnUM-small.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ <div class="swiper-slide gallery-item" data-bs-toggle="modal" data-bs-target="#productGalleryModal" data-slide-index="1">
+ <img src="/storage/product-detail/March2023/AMkQl1hd71Ibm7c5NrtS-small.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ <div class="swiper-slide gallery-item" data-bs-toggle="modal" data-bs-target="#productGalleryModal" data-slide-index="2">
+ <img src="/storage/product-detail/March2023/Jd0jcIzJaopT6I9XTTVZ-small.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ <div class="swiper-slide gallery-item" data-bs-toggle="modal" data-bs-target="#productGalleryModal" data-slide-index="3">
+ <img src="/storage/product-detail/March2023/0Hk0AbjsPY2FtxBeX9c0-small.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ <div class="swiper-slide gallery-item" data-bs-toggle="modal" data-bs-target="#productGalleryModal" data-slide-index="4">
+ <img src="/storage/product-detail/March2024/QqOjCeJso0QA2uAUA3kr-small.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ <div class="swiper-slide gallery-item" data-bs-toggle="modal" data-bs-target="#productGalleryModal" data-slide-index="5">
+ <img src="/storage/product-detail/March2024/vOhf9fz2V8dLCAjrn51E-small.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ </div>
+ <div class="swiper-button-next"></div>
+ <div class="swiper-button-prev"></div>
+ </div>
+ </div>
+ </div><!-- detailSpecDiv -->
+ <div class="col-12 desktop p-0">
+ <div class="skuOptionContainer col-12 p-0 py-2">
+ <ui class="skuOption">
+ <li><div class="icons d-flex flex-wrap">
+ <div class="icon">
+ <a class="icon-container" href = "/specs/wallcovering/phthalate-free">
+ <img class="svg" src = "../../images/icons/2022/Phthalate_Free.svg" alt="Phthalate Free Icon"/>
+ </a>
+ <span style="margin-left: 2px">
+ Phthalate Free
+ </span>
+ </div>
+ <div class="icon" id="sku-spec-icon">
+ <a class="icon-container" href = "/specs/wallcovering/seamless">
+ <img class="svg" src = "../../images/icons/2022/Seamless.svg" alt="Seamless Icon"/>
+ </a>
+ <span class="d-flex align-items-start justify-content-center gap-1 ">
+ Seamless
+ <img src="https://www.innovationsusa.com/images/icons/Infobox_icon.svg" width="13px" height="13px" style="marging-left: 2px !important; margin-top: 5px !important;" alt=""/>
+ </span>
+ <span class="tooltiptext1" style="color: #fff !important">Invisible seam</span>
+ </div>
+ <div class="icon">
+ <a class="icon-container" href = "/specs/wallcovering/vinyl">
+ <img class="svg" src = "../../images/icons/2022/Vinyl.svg" alt="Vinyl Icon"/>
+ </a>
+ <span>
+ Vinyl
+ </span>
+ </div>
+ <div class="icon">
+ <a class="icon-container" href = "/specs/wallcovering/high-traffic">
+ <img class="svg" src = "../../images/icons/2022/High_Traffic.svg" alt="High Traffic Icon"/>
+ </a>
+ <span>
+ High Traffic
+ </span>
+ </div>
+ <div class="icon">
+ <a class="icon-container" href = "/specs/wallcovering/eco-friendly">
+ <img class="svg" src = "../../images/icons/2022/Eco-Friendly.svg" alt="Eco-friendly Wallcovering" />
+ </a>
+ <span>
+ Eco Friendly
+ </span>
+ </div>
+ <div class="icon">
+ <a class="icon-container" href = "/specs/wallcovering/tech-typeii">
+ <img class="svg" src = "../../images/icons/2022/Type-2.svg" alt="type ii" />
+ </a>
+ <span>
+ Type II
+ </span>
+ </div></div></li>
+ </ui>
+ </div>
+ <div class="alert alert-danger" id="order-error-message" style="display: none"></div>
+ <div class="skuStatDiv pb-4 w-full d-flex" style="gap: 12px">
+ <button type="button" class="order-button btn-orange" data-toggle="modal" data-target="#guestModal">ORDER A SAMPLE</button>
+ <a href="/yardage-calculator/Costine?width=52" class="yardage-button btn-white" type="button">YARDAGE CALCULATOR</a>
+ </div>
+ </div>
+ </div><!-- itmSubmenuContainer --- it's left side container -->
+ <div class="col-12 col-lg-7"> <!-- it's right side container -->
+ <div class="discriptionContainer">
+ <div class="col-12 d-flex p-0">
+ <div class="d-flex align-items-end mb-2">
+ <h1 class="product-title text-uppercase m-0"><a>Costine</a></h1>
+ </div>
+ </div>
+ <div class="content">A contemporary update to a timeless design, Costine offers durable wall protection in a high-performance vinyl wallcovering suitable for the most heavily trafficked areas. The deeply embossed vertical stripes are designed to absorb impact in areas where it is needed most. The dimensional stripes are enhanced by a color palette in hues like silver and pearl with a hint of shine. This versatile product is ideal for a wide range of applications from residential to commercial, the possibilities are endless.</div>
+ </div>
+ <div class="product-accordion-container">
+ <div class="accordion">
+ <div class="accordion-container">
+ <h4 class="label">Specifications</h4>
+ <div class="content">
+ <ul class="skuSpec m-0">
+ <li>
+ <span class="specTitle">Composition:</span>
+ <span class="specVal">Vinyl</span>
+ </li><li class="backing-spec">
+ <span class="specTitle">Backing:</span>
+ <span class="specVal">Dense Polyester Cotton Drill</span>
+ </li>
+ <li>
+ <span class="specTitle">Total Weight:</span>
+ <span class="specVal">34 oz/lineal yd
+ <span class="metric">(798 gsm)</span>
+ </span>
+ </li>
+ <li>
+ <span class="specTitle">Width:</span> <span class="specVal" >
+ <span id="itemwidth">52"</span>
+ <span class="metric">(132 cm)</span>
+ </span>
+ </li>
+ <li>
+ <span class="specTitle">Repeat:</span>
+ <span class="specVal">Non-Match</span></li>
+ <li>
+ <span class="specTitle">Full Roll:</span>
+ <span class="specVal">25 YDs</span>
+ </li><li>
+ <span class="specTitle">Fire Rating:</span>
+ <span class="specVal">ASTM E84 - Class A</span>
+ </li><li>
+ <span class="specTitle">Seaming:</span>
+ <span class="specVal">Seamless</span>
+ </li><li><span class="specTitle">Environmental Impact and Sustainability:</span> <span class="specVal"><a href="/product/all-wallcovering?environmental=ca-01350-compliant" style="color:#000; text-decoration: underline;">CA 01350 Compliant</a>, <a href="/product/all-wallcovering?environmental=phthalate-free-material" style="color:#000; text-decoration: underline;">Phthalate Free Material</a>, <a href="/product/all-wallcovering?environmental=ultra-low-voc" style="color:#000; text-decoration: underline;">Ultra-Low VOC</a></span></li><li>
+ <span class="specTitle type">Type:</span>
+ <span class="specVal"> Type II</span>
+ </li></ul>
+ </div>
+ </div>
+ <hr>
+ <div class="accordion-container">
+ <h4 class="label">Product Downloads</h4>
+ <div class="content">
+
+ <a href="https://www.innovationsusa.com/product-spec-sheet/costine" target="_blank" style="text-decoration: underline; color:#000">Spec Sheet</a>
+ <span> and </span>
+ <a href="https://www.innovationsusa.com/storage/+docs/hanging_instructions/costine.pdf?v=2.55" target="_blank" style="text-decoration: underline; color:#000">Hanging Instructions</a>
+ </div>
+ </div>
+ <hr>
+ <div class="accordion-container">
+ <h5 class="label">Seen In</h5>
+ <div class="content">
+ <div class="seenin hide">
+
+ <ul class="row p-0">
+ <li class="col-8 col-sm-6 col-md-3">
+ <div class="inner">
+ <a class="fabricName" href="/catalogs/spring-2023-catalog">
+ <img data-pin-no-hover="true" src="/storage/seenin/March2023/4OoxUNvXGh3VFH0svYRC.jpg" alt="Spring 2023 Catalog" width="100%">
+ <p class="seenTitle">Spring 2023 Catalog</p>
+ </a>
+ </div><!-- inner -->
+ </li>
+ <li class="col-8 col-sm-6 col-md-3">
+ <div class="inner">
+ <a class="fabricName" href="/videos/spring-2023">
+ <img data-pin-no-hover="true" src="/storage/seenin/March2023/eRVhq2ww633TEhCl4bWY.jpg" alt="Spring 2023 Video" width="100%">
+ <p class="seenTitle">Spring 2023 Video</p>
+ </a>
+ </div><!-- inner -->
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <hr>
+ </div>
+ </div>
+ <div class="skuThumbDiv col-12 px-0 pt-4">
+ <div class="itm thumbnailContainer ">
+ <div class="desktop">
+ <ul class="skuUL row">
+
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <a class="skuA fl" href="/item/costine/cso-001" data-featherlight="#fl0">
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-001.jpg?v=2.55"
+ data-pin-no-hover="true"
+ class="img-fluid"
+ alt="thumbnail"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-001</span><span class="skuName">RADIANT</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ </li>
+
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <a class="skuA fl" href="/item/costine/cso-002" data-featherlight="#fl0">
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-002.jpg?v=2.55"
+ data-pin-no-hover="true"
+ class="img-fluid"
+ alt="thumbnail"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-002</span><span class="skuName">PEARL</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ </li>
+
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <a class="skuA fl" href="/item/costine/cso-003" data-featherlight="#fl0">
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-003.jpg?v=2.55"
+ data-pin-no-hover="true"
+ class="img-fluid"
+ alt="thumbnail"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-003</span><span class="skuName">FILIGREE</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ </li>
+
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <a class="skuA fl" href="/item/costine/cso-004" data-featherlight="#fl0">
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-004.jpg?v=2.55"
+ data-pin-no-hover="true"
+ class="img-fluid"
+ alt="thumbnail"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-004</span><span class="skuName">POLISH</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ </li>
+
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <a class="skuA fl" href="/item/costine/cso-005" data-featherlight="#fl0">
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-005.jpg?v=2.55"
+ data-pin-no-hover="true"
+ class="img-fluid"
+ alt="thumbnail"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-005</span><span class="skuName">NAVY</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ </li>
+ </ul>
+
+ </div>
+
+ <div class="mobile">
+ <div class="swiper mobile-similar-products">
+ <div class="swiper-wrapper">
+ <div class="swiper-slide item ">
+ <a class="skuA fl" href="/item/costine/cso-001" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-001.jpg?v=2.55.jpg"
+ class="img-fluid"
+ alt="Wallcovering SKU cso-001"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt">
+ <span class="itemNum">CSO-001</span>
+ <span class="skuName">
+ radiant
+ </span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ <div class="swiper-slide item ">
+ <a class="skuA fl" href="/item/costine/cso-002" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-002.jpg?v=2.55.jpg"
+ class="img-fluid"
+ alt="Wallcovering SKU cso-002"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt">
+ <span class="itemNum">CSO-002</span>
+ <span class="skuName">
+ pearl
+ </span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ <div class="swiper-slide item ">
+ <a class="skuA fl" href="/item/costine/cso-003" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-003.jpg?v=2.55.jpg"
+ class="img-fluid"
+ alt="Wallcovering SKU cso-003"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt">
+ <span class="itemNum">CSO-003</span>
+ <span class="skuName">
+ filigree
+ </span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ <div class="swiper-slide item ">
+ <a class="skuA fl" href="/item/costine/cso-004" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-004.jpg?v=2.55.jpg"
+ class="img-fluid"
+ alt="Wallcovering SKU cso-004"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt">
+ <span class="itemNum">CSO-004</span>
+ <span class="skuName">
+ polish
+ </span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ <div class="swiper-slide item ">
+ <a class="skuA fl" href="/item/costine/cso-005" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-005.jpg?v=2.55.jpg"
+ class="img-fluid"
+ alt="Wallcovering SKU cso-005"
+ loading="lazy"
+ decoding="async">
+ <p class="skuBottomTxt">
+ <span class="itemNum">CSO-005</span>
+ <span class="skuName">
+ navy
+ </span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="swiper-button-next text-white"></div>
+ <div class="swiper-button-prev text-white"></div>
+ </div>
+ </div><!-- itm thumbnailContainer -->
+ </div><!-- skuThumDiv col-sm-8 -->
+ </div>
+ </div><!-- row -->
+</div><!-- skuDiv container-fluid --->
+
+<div class="modal fade" id="productGalleryModal" tabindex="-1" aria-labelledby="item-sku-gallery-modal" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+ <?xml version="1.0" encoding="UTF-8"?>
+<svg width="20px" height="21px" viewBox="0 0 20 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <title>Line 2</title>
+ <g id="Style-Guide" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="square">
+ <g id="Innovations_StyleGuide" transform="translate(-301.000000, -807.000000)" stroke="#7A7D81" stroke-width="2">
+ <path d="M319.421583,809.03005 L302.578402,825.969713 M302.574025,809 L319.274842,826" id="Line-2"></path>
+ </g>
+ </g>
+</svg>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="swiper modal-swiper">
+ <div class="swiper-wrapper">
+ <div class="swiper-slide">
+ <div class="d-flex flex-column">
+ <div style="overflow:hidden">
+ <div class="swiper-zoom-container">
+ <img src="/storage/product-detail/March2023/d2jbYyvlMtIoiHjQAnUM.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ </div>
+ <div class="d-flex align-items-center justify-content-between footer mt-2">
+ <h5 class="description text-black">Costine<br/>COS-005 </h5>
+ <h6 class="download-image-gallery btn-orange text-nowrap text-uppercase" data-downimage="/storage/product-detail/March2023/d2jbYyvlMtIoiHjQAnUM.jpg"></h6>
+ </div>
+ </div>
+ </div>
+ <div class="swiper-slide">
+ <div class="d-flex flex-column">
+ <div style="overflow:hidden">
+ <div class="swiper-zoom-container">
+ <img src="/storage/product-detail/March2023/AMkQl1hd71Ibm7c5NrtS.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ </div>
+ <div class="d-flex align-items-center justify-content-between footer mt-2">
+ <h5 class="description text-black">Costine<br/>CSO-002 Pearl</h5>
+ <h6 class="download-image-gallery btn-orange text-nowrap text-uppercase" data-downimage="/storage/product-detail/March2023/AMkQl1hd71Ibm7c5NrtS.jpg"></h6>
+ </div>
+ </div>
+ </div>
+ <div class="swiper-slide">
+ <div class="d-flex flex-column">
+ <div style="overflow:hidden">
+ <div class="swiper-zoom-container">
+ <img src="/storage/product-detail/March2023/Jd0jcIzJaopT6I9XTTVZ.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ </div>
+ <div class="d-flex align-items-center justify-content-between footer mt-2">
+ <h5 class="description text-black">Costine</h5>
+ <h6 class="download-image-gallery btn-orange text-nowrap text-uppercase" data-downimage="/storage/product-detail/March2023/Jd0jcIzJaopT6I9XTTVZ.jpg"></h6>
+ </div>
+ </div>
+ </div>
+ <div class="swiper-slide">
+ <div class="d-flex flex-column">
+ <div style="overflow:hidden">
+ <div class="swiper-zoom-container">
+ <img src="/storage/product-detail/March2023/0Hk0AbjsPY2FtxBeX9c0.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ </div>
+ <div class="d-flex align-items-center justify-content-between footer mt-2">
+ <h5 class="description text-black">Costine</h5>
+ <h6 class="download-image-gallery btn-orange text-nowrap text-uppercase" data-downimage="/storage/product-detail/March2023/0Hk0AbjsPY2FtxBeX9c0.jpg"></h6>
+ </div>
+ </div>
+ </div>
+ <div class="swiper-slide">
+ <div class="d-flex flex-column">
+ <div style="overflow:hidden">
+ <div class="swiper-zoom-container">
+ <img src="/storage/product-detail/March2024/QqOjCeJso0QA2uAUA3kr.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ </div>
+ <div class="d-flex align-items-center justify-content-between footer mt-2">
+ <h5 class="description text-black">Costine<br/>CSO-003 Filigree<br/><a href="https://www.instagram.com/duettdesignatl/" class="text-orange">Duett Design</a></h5>
+ <h6 class="download-image-gallery btn-orange text-nowrap text-uppercase" data-downimage="/storage/product-detail/March2024/QqOjCeJso0QA2uAUA3kr.jpg"></h6>
+ </div>
+ </div>
+ </div>
+ <div class="swiper-slide">
+ <div class="d-flex flex-column">
+ <div style="overflow:hidden">
+ <div class="swiper-zoom-container">
+ <img src="/storage/product-detail/March2024/vOhf9fz2V8dLCAjrn51E.jpg"
+ alt="Costine"
+ loading="lazy"
+ decoding="async">
+ </div>
+ </div>
+ <div class="d-flex align-items-center justify-content-between footer mt-2">
+ <h5 class="description text-black">Costine<br/>CSO-003 Filigree<br/><a href="https://www.instagram.com/duettdesignatl/" class="text-orange">Duett Design</a></h5>
+ <h6 class="download-image-gallery btn-orange text-nowrap text-uppercase" data-downimage="/storage/product-detail/March2024/vOhf9fz2V8dLCAjrn51E.jpg"></h6>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="modal-swiper-button swiper-button-next"></div>
+ <div class="modal-swiper-button swiper-button-prev"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="modal fade" id="guestModal" tabindex="-1" role="dialog" aria-labelledby="guestModalLabel" aria-hidden="true">
+ <div class="modal-dialog" role="document">
+ <div id="pdp-guest-modal"></div>
+ </div>
+</div>
+
+
+<div class="modal fade" id="itemSampleModal" tabindex="-1" role="dialog" aria-labelledby="sampleModalLabel" aria-hidden="false">
+ <div class="modal-dialog" role="document">
+ <form method="post" action="/item-sample-order">
+ <div class="modal-content">
+ <h5 class="modal-title" id="exampleModalLabel">Select SKUs to Sample</h5>
+ <div class="text-center" style="display:none;" id="item_spinner">
+ <div class="spinner-border" role="status">
+ <span class="sr-only">Loading...</span>
+ </div>
+ </div>
+ <input type="hidden" name="_token" value="OUtlvikrTZc3lF5NAoS0EK9BLV06oFQhUu8JOilq" autocomplete="off"> <div class="modal-body row d-flex flex-row flex-wrap my-5">
+ <ul class="skuUL row">
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <div class="skuA fl" data-featherlight="#fl0">
+ <input type="checkbox" class="form-check position-absolute" name="CSO-001" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-001.jpg?v=2.55" data-pin-no-hover="true" class="img-fluid" alt="thumbnail">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-001</span><span class="skuName">RADIANT</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </div>
+ </div>
+ </li>
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <div class="skuA fl" data-featherlight="#fl0">
+ <input type="checkbox" class="form-check position-absolute" name="CSO-002" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-002.jpg?v=2.55" data-pin-no-hover="true" class="img-fluid" alt="thumbnail">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-002</span><span class="skuName">PEARL</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </div>
+ </div>
+ </li>
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <div class="skuA fl" data-featherlight="#fl0">
+ <input type="checkbox" class="form-check position-absolute" name="CSO-003" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-003.jpg?v=2.55" data-pin-no-hover="true" class="img-fluid" alt="thumbnail">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-003</span><span class="skuName">FILIGREE</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </div>
+ </div>
+ </li>
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <div class="skuA fl" data-featherlight="#fl0">
+ <input type="checkbox" class="form-check position-absolute" name="CSO-004" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-004.jpg?v=2.55" data-pin-no-hover="true" class="img-fluid" alt="thumbnail">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-004</span><span class="skuName">POLISH</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </div>
+ </div>
+ </li>
+ <li data-sku="" class="col-sm-2 ">
+ <div class="inner">
+ <div class="skuA fl" data-featherlight="#fl0">
+ <input type="checkbox" class="form-check position-absolute" name="CSO-005" >
+ <img src="https://www.innovationsusa.com/storage/sku/350x350/CSO-005.jpg?v=2.55" data-pin-no-hover="true" class="img-fluid" alt="thumbnail">
+ <p class="skuBottomTxt"><span class="itemNum">CSO-005</span><span class="skuName">NAVY</span> <span class="trigger"></span></p>
+ <span class="red-dot"></span>
+ </div>
+ </div>
+ </li>
+ </ul>
+ </div>
+ <div class="modal-footer">
+ <button type="submit" id="order_btn" class="btn btn-primary red-button my-3">ORDER A SAMPLE</button>
+ </div>
+ </div>
+ </form>
+ </div>
+</div>
+</main>
+<footer class="page-footer">
+ <div class="container-fluid d-flex flex-column justify-content-center" style="gap:12px">
+ <div class="w-full d-flex justify-content-center">
+ <a href="/" class="col-6 col-md-3 d-flex justify-content-center">
+ <img class="footer-logo" src="/images/innovations-grey-logo-old.svg"
+ style="min-width:240px; width:90%; height:auto;">
+ </a>
+ </div>
+ <div class="w-full d-flex flex-column flex-md-row justify-content-between align-items-end">
+ <ul class="col-12 col-md-4 d-flex justify-content-around align-items-center order-1 order-md-2">
+ <li class="link"><a href="https://www.linkedin.com/company/2143853" target="_blank"
+ title="Innovationsusa Linked In"><img class="footer-social-icon"
+ src="/images/icons/footer-linkedin.svg" /></a>
+ </li>
+ <li class="fb"><a href="https://www.facebook.com/innovationsusa" target="_blank"
+ title="Innovationsusa Facebook"><img class="footer-social-icon"
+ src="/images/icons/footer-facebook.svg" /></a>
+ </li>
+ <li class="pin"><a href="https://pinterest.com/innovationsusa/boards/" target="_blank"
+ title="Innovationsusa Pinterest"><img class="footer-social-icon"
+ src="/images/icons/footer-pinterest.svg" /></a>
+ </li>
+ <li class="inst"><a href="https://www.instagram.com/innovationsusa" target="_blank"
+ title="Innovationsusa Instagram"><img class="footer-social-icon"
+ src="/images/icons/footer-instagram.svg" /></a>
+ </li>
+ </ul>
+ <ul class="col-12 col-md-4 d-flex flex-column order-3 order-md-1">
+ <li class="list-inline-item text-center text-md-left"><a href="/terms-conditions">TERMS & CONDITIONS</a></li>
+ <li class="list-inline-item text-center text-md-left"><a href="/privacy-policy">PRIVACY POLICY</a></li>
+ <li class="list-inline-item text-center text-md-left"><a href="/legal">LEGAL</a></li>
+ <li class="list-inline-item text-center text-md-right d-block d-md-none">© 2026 INNOVATIONS
+ USA</li>
+ </ul>
+ <ul class="col-12 col-md-4 d-flex flex-column order-2 order-md-3">
+ <li class="list-inline-item text-center text-md-right"><a href="#!">800.227.8053</a></li>
+ <li class="list-inline-item text-center text-md-right"><a href="mailto:info@innovationsusa.com"
+ style="overflow-wrap:break-word;">INFO@INNOVATIONSUSA.COM</a></li>
+ <li class="list-inline-item text-center text-md-right d-none d-md-block">© 2026 INNOVATIONS USA
+ </li>
+ </ul>
+ </div>
+ </div>
+ <div id="gdpr" class="">
+ <p>Innovationsusa.com uses cookies to recognize your browsing preferences and to analyze traffic. View our <a
+ class='terms' href="/terms-conditions">privacy page</a> to learn more.</p>
+ <div id="accept-btn"></div>
+ </div>
+</footer>
+<!-- Footer Scripts -->
+<script
+ src="https://code.jquery.com/jquery-3.5.1.min.js"
+ integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
+ crossorigin="anonymous"></script>
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
+<script src="https://www.innovationsusa.com/vendor/carousel/owl.carousel.min.js"></script>
+<script type="text/javascript" src="https://www.innovationsusa.com/js/MyCarousel-0.1.js"></script>
+<script type="text/javascript" src="https://www.innovationsusa.com/js/app.js?v=2.55"></script>
+<script type="text/javascript">
+$(document).ready(function() {
+ $('img').each(function(){
+ var dataSrc = $(this).data('src');
+ if (dataSrc) {
+ $(this).attr('src', dataSrc);
+ }
+ });
+})
+</script>
+<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
+
+<script type="text/javascript">
+ // Wait for jQuery to load
+ (function() {
+ function waitForJQuery() {
+ if (typeof jQuery !== 'undefined') {
+ jQuery(document).ready(function($) {
+ var _token = $("meta[name=csrf-token]").attr("content");
+ const itemNumber = null;
+ if(!itemNumber) {
+ return false
+ }
+ });
+ } else {
+ // jQuery not loaded yet, wait for it
+ setTimeout(waitForJQuery, 100);
+ }
+ }
+ waitForJQuery();
+ })();
+</script>
+
+
+<script>
+ // Wait for jQuery to load
+ (function() {
+ function waitForJQuery() {
+ if (typeof jQuery !== 'undefined') {
+ jQuery(document).ready(function($) {
+ const accordion = document.getElementsByClassName('accordion-container');
+ for (let i = 0; i < accordion.length; i++) {
+ accordion[i].addEventListener('click', function () {
+ this.classList.toggle('active');
+ if(this.querySelector('.content').querySelector('.login-btn')) return;
+ const content = this.querySelector('.content');
+ if (this.classList.contains('active')) {
+ content.style.height = content.scrollHeight + "px"
+ } else {
+ content.style.height = '0';
+ }
+
+ for (let j = 0; j < accordion.length; j++) {
+ if (this !== accordion[j] && accordion[j].classList.contains('active')) {
+ accordion[j].classList.remove('active');
+ accordion[j].querySelector('.content').style.height = '0';
+ }
+ }
+ });
+ }
+ });
+ } else {
+ setTimeout(waitForJQuery, 100);
+ }
+ }
+ waitForJQuery();
+ })();
+</script>
+
+<script>
+document.addEventListener('DOMContentLoaded', function() {
+ const toggleButton = document.querySelector('.toggle-button');
+ const collapsibleElement = document.getElementById('collapse-filter-pdp');
+
+ // Check if toggleButton exists
+ if (toggleButton) {
+ toggleButton.addEventListener('click', function() {
+ if (collapsibleElement.style.display === 'none') {
+ collapsibleElement.style.display = 'flex';
+ this.setAttribute('aria-expanded', 'true');
+ } else {
+ collapsibleElement.style.display = 'none';
+ this.setAttribute('aria-expanded', 'false');
+ }
+ });
+ }
+});
+</script>
+<script>
+ document.addEventListener('DOMContentLoaded', function(){
+ // Swiper JS
+ let gallerySwiper = new Swiper(".product-gallery", {
+ slidesPerView: 5,
+ spaceBetween: 10,
+ navigation: {
+ nextEl: ".swiper-button-next",
+ prevEl: ".swiper-button-prev",
+ },
+ });
+ let modalSwiper = new Swiper(".modal-swiper", {
+ zoom: true,
+ slidesPerView: 1,
+ spaceBetween: 10,
+ navigation: {
+ nextEl: ".swiper-button-next",
+ prevEl: ".swiper-button-prev",
+ },
+ pagination: {
+ el: ".swiper-pagination",
+ clickable: true,
+ },
+ });
+ let mobileSimilarProdSwiper = new Swiper(".mobile-similar-products", {
+ slidesPerView: 5,
+ spaceBetween: 10,
+ navigation: {
+ nextEl: ".swiper-button-next",
+ prevEl: ".swiper-button-prev",
+ },
+ })
+
+ let productGalleryModal = new bootstrap.Modal(document.getElementById('productGalleryModal'));
+ let galleryItems = document.querySelectorAll('.gallery-item');
+ galleryItems.forEach(function(item) {
+ item.addEventListener('click', function(event) {
+ event.preventDefault();
+
+ let initialSlideIndex = parseInt(this.dataset.slideIndex);
+ modalSwiper.slideTo(initialSlideIndex, 0);
+
+ productGalleryModal.show();
+ });
+ });
+});
+</script>
+<style>
+ html {
+ overflow-y: scroll; /* reserve the gutter — no layout shift */
+ scrollbar-width: thin; /* Firefox */
+ scrollbar-color: transparent transparent; /* hidden until hover */
+ }
+ html.scrollbar-hover { scrollbar-color: #999 #ececec; }
+
+ html::-webkit-scrollbar { width: 8px; }
+ html::-webkit-scrollbar-track { background: transparent; border-radius: 10px; }
+ html::-webkit-scrollbar-thumb { background: transparent; border-radius: 10px; }
+ html.scrollbar-hover::-webkit-scrollbar-track { background: #ececec; }
+ html.scrollbar-hover::-webkit-scrollbar-thumb { background: #999; }
+</style>
+<script>
+ (function () {
+ var root = document.documentElement;
+ var show = function () { root.classList.add('scrollbar-hover'); };
+ var hide = function () { root.classList.remove('scrollbar-hover'); };
+ root.addEventListener('mouseenter', show);
+ root.addEventListener('mouseleave', hide);
+ document.addEventListener('mousemove', show, { passive: true });
+ window.addEventListener('blur', hide);
+ })();
+</script>
+</body>
+</html>
diff --git a/tk11041-innovations-reconcile/rescrape/innovations-trade-pull.js b/tk11041-innovations-reconcile/rescrape/innovations-trade-pull.js
new file mode 100644
index 0000000..a5745a3
--- /dev/null
+++ b/tk11041-innovations-reconcile/rescrape/innovations-trade-pull.js
@@ -0,0 +1,218 @@
+// Innovations USA trade-portal price pull — TK-11041.
+// Cracked/staged 2026-09-11. Runs ONLY when INNOVATIONS_* credentials exist.
+//
+// WHY: Hektor Martinez (Innovations) answered our 2026-09-02 price-list request with
+// "Pricing is available through our website using your login information. Account # 58315."
+// Public pages carry ZERO price tokens (verified across all 371 pattern pages), so the
+// logged-in portal is the only path to net price for the 39 live-pattern PR-Innovations items.
+//
+// HARD RULES BAKED IN (these are the point of the script, not decoration):
+// 1. A page with no price is NEVER a $0 price. It is either NOT_MEASURED (auth proven on
+// that page) or SESSION_FAILURE (auth not proven) — and SESSION_FAILURE aborts the run.
+// 2. Login must be POSITIVELY proven before any pattern page is fetched. Absence of an
+// error is not proof of a session.
+// 3. This script does NOT compute retail. The cost basis is disputed (vendor_registry says
+// 10%, every DW sample request says "Net Less 20%"); a 10-point error propagates through
+// cost/0.65/0.85 straight to customers. Settle TK-11041's discount question first.
+// 4. No DB write. No Shopify write. Output is a staged JSON file for human review.
+// 5. robots.txt: /item/<slug>/ is Allow, /item/*/* is Disallow (and 500s). Pattern pages only.
+//
+// USAGE:
+// node innovations-trade-pull.js --selftest # $0, no network, no session. Proves the
+// # extractor REFUSES a logged-out page. Run first.
+// node innovations-trade-pull.js --probe # login + auth proof + ONE pattern page (~1 session)
+// node innovations-trade-pull.js # full pull, all 7 live pattern pages
+const fs = require('fs');
+const path = require('path');
+
+const TICKET = 'TK-11041';
+const REPO = process.env.INN_REPO ||
+ path.join(process.env.HOME, 'Projects/dw-unbuyable-recovery-pilot/tk11041-innovations-reconcile/rescrape');
+const IDENTITY_MAP = path.join(REPO, 'data/innovations-identity-map.json');
+const OUT_DIR = path.join(REPO, 'data');
+const FIXTURE_LOGGED_OUT = path.join(REPO, 'fixtures/logged-out-costine.html');
+
+const LOGIN_URL_DEFAULT = 'https://www.innovationsusa.com/login';
+const THROTTLE_MS = 350; // matches the public sweep's courtesy rate
+
+// ---------------------------------------------------------------- extraction
+// Authentication is asserted on EVERY page, not just at login: a portal can drop a session
+// mid-run and keep serving 200s. "SIGN IN" present with no account marker == logged out.
+const AUTH_POSITIVE = /sign\s*out|log\s*out|my\s*account|58315/i;
+const AUTH_NEGATIVE = /sign\s*in|log\s*in/i;
+
+function authState(text) {
+ const pos = AUTH_POSITIVE.test(text);
+ const neg = AUTH_NEGATIVE.test(text);
+ if (pos && !neg) return 'AUTHENTICATED';
+ if (pos && neg) return 'AMBIGUOUS'; // treated as failure — never trusted
+ return 'LOGGED_OUT';
+}
+
+// Returns {value, unit, raw} or null. NEVER returns 0 and never invents a unit.
+function extractPrice(text) {
+ const m = text.match(/\$\s?([0-9][0-9,]*(?:\.[0-9]{1,2})?)\s*(?:\/|per\s+)?\s*(yard|yd|lineal\s*yard|roll|sq\s*ft|each)?/i);
+ if (!m) return null;
+ const value = parseFloat(m[1].replace(/,/g, ''));
+ if (!Number.isFinite(value) || value <= 0) return null; // a $0 token is a defect, not a price
+ return { value, unit: m[2] ? m[2].toLowerCase().replace(/\s+/g, ' ') : null, raw: m[0].trim() };
+}
+
+// One page -> one verdict. This is the whole safety contract in one function, so the
+// self-test can exercise it with zero network.
+function classifyPage(text) {
+ const auth = authState(text);
+ if (auth !== 'AUTHENTICATED') return { status: 'SESSION_FAILURE', auth, price: null };
+ const price = extractPrice(text);
+ if (!price) return { status: 'NOT_MEASURED', auth, price: null };
+ return { status: 'MEASURED', auth, price };
+}
+
+// ---------------------------------------------------------------- self-test
+// A positive-only test on a detector proves nothing. This injects the real logged-out page
+// and demands the extractor go red. If this passes on a logged-out shell, the pull is unsafe.
+function selftest() {
+ let failures = 0;
+ const check = (name, cond) => {
+ console.log(` ${cond ? 'PASS' : 'FAIL'} ${name}`);
+ if (!cond) failures++;
+ };
+ console.log(`[selftest] ${TICKET} innovations-trade-pull — negative tests`);
+
+ if (fs.existsSync(FIXTURE_LOGGED_OUT)) {
+ const html = fs.readFileSync(FIXTURE_LOGGED_OUT, 'utf8');
+ const v = classifyPage(html);
+ check('real logged-out /item/costine => SESSION_FAILURE', v.status === 'SESSION_FAILURE');
+ check('real logged-out page yields NO price', v.price === null);
+ } else {
+ check(`fixture present at ${FIXTURE_LOGGED_OUT}`, false);
+ }
+
+ check('bare "Sign In" shell => SESSION_FAILURE',
+ classifyPage('<a>Sign In</a> Costine').status === 'SESSION_FAILURE');
+ check('authed page with NO price => NOT_MEASURED (never $0)',
+ classifyPage('Sign Out | My Account — Costine CSO-001').status === 'NOT_MEASURED');
+ check('a $0.00 token is rejected, not recorded as a price',
+ classifyPage('Sign Out Account 58315 — Price $0.00').status === 'NOT_MEASURED');
+ check('authed page WITH price => MEASURED + numeric',
+ (() => { const v = classifyPage('Sign Out Account 58315 — $84.50 per yard');
+ return v.status === 'MEASURED' && v.price.value === 84.5 && /yard/.test(v.price.unit); })());
+ check('BOTH sign-in and sign-out present => AMBIGUOUS, not trusted',
+ classifyPage('Sign In Sign Out $99.00').status === 'SESSION_FAILURE');
+
+ console.log(failures === 0 ? '[selftest] ALL PASS' : `[selftest] ${failures} FAILURE(S)`);
+ process.exit(failures === 0 ? 0 : 1);
+}
+
+// ---------------------------------------------------------------- credentials
+function creds() {
+ require('dotenv').config({ path: path.join(__dirname, '.env') });
+ const user = process.env.INNOVATIONS_USERNAME;
+ const pass = process.env.INNOVATIONS_PASSWORD;
+ const url = process.env.INNOVATIONS_LOGIN_URL || LOGIN_URL_DEFAULT;
+ const missing = [!user && 'INNOVATIONS_USERNAME', !pass && 'INNOVATIONS_PASSWORD'].filter(Boolean);
+ if (missing.length) {
+ console.error(`[!] ${TICKET}: missing ${missing.join(', ')}.`);
+ console.error(' These are registered in secrets-manager/routes.json and route here automatically.');
+ console.error(' Steve pastes them once, the `secrets` skill fans them out. Do NOT hand-edit .env.');
+ console.error(' Refusing to run: a credential-less run can only produce false absences.');
+ process.exit(2);
+ }
+ return { user, pass, url };
+}
+
+// ---------------------------------------------------------------- main
+(async () => {
+ const args = process.argv.slice(2);
+ if (args.includes('--selftest')) return selftest();
+ const probe = args.includes('--probe');
+
+ const { user, pass, url } = creds();
+ const map = JSON.parse(fs.readFileSync(IDENTITY_MAP, 'utf8'));
+ const live = map.items.filter(i => i.site_state === 'live');
+ const pages = [...new Map(live.map(i => [i.product_url, i.innovations_pattern])).entries()];
+ const targets = probe ? pages.slice(0, 1) : pages;
+ console.log(`[*] ${TICKET}: ${live.length} live items across ${pages.length} pattern pages` +
+ `${probe ? ' — PROBE: fetching 1' : ''}`);
+ console.log('[*] The 12 discontinued WHL/Whistler items are deliberately OUT of this pull (they 404).');
+
+ const Browserbase = require('@browserbasehq/sdk').default;
+ const { chromium } = require('playwright-core');
+ const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY });
+ const session = await bb.sessions.create({
+ projectId: process.env.BROWSERBASE_PROJECT_ID,
+ browserSettings: { solveCaptchas: true }, // login page carries reCAPTCHA
+ });
+ console.log(`[*] browserbase session ${session.id}`);
+ const browser = await chromium.connectOverCDP(session.connectUrl);
+ const ctx = browser.contexts()[0];
+ const page = ctx.pages()[0] || await ctx.newPage();
+ page.setDefaultTimeout(45000);
+
+ const results = [];
+ let aborted = null;
+ try {
+ // --- login
+ await page.goto(url, { waitUntil: 'domcontentloaded' });
+ await page.waitForTimeout(3000);
+ const pw = await page.$('input[type=password]');
+ if (pw) {
+ const userSel = await page.$('input[type=email], input[name=email], input[name=username]');
+ if (!userSel) throw new Error('login page has a password field but no resolvable username field');
+ await userSel.fill(user);
+ await pw.fill(pass);
+ await page.waitForTimeout(400);
+ await page.click('button[type=submit], input[type=submit], button:has-text("Sign In")')
+ .catch(async () => { await pw.focus(); await page.keyboard.press('Enter'); });
+ await page.waitForTimeout(9000); // captcha solve + redirect
+ }
+
+ // --- AUTH PROOF. Nothing is fetched until the session is positively proven.
+ const homeText = await page.evaluate(() => document.body.innerText);
+ const proof = authState(homeText);
+ if (proof !== 'AUTHENTICATED') {
+ throw new Error(`login NOT proven (auth=${proof}). Refusing to fetch pages — an unproven ` +
+ 'session produces false absences that look exactly like "vendor has no price".');
+ }
+ console.log('[+] session AUTHENTICATED (positively proven, not merely error-free)');
+
+ // --- pull
+ for (const [url_, pattern] of targets) {
+ await page.goto(url_, { waitUntil: 'domcontentloaded' });
+ await page.waitForTimeout(THROTTLE_MS + 1200);
+ const text = await page.evaluate(() => document.body.innerText);
+ const v = classifyPage(text);
+ console.log(` ${v.status.padEnd(15)} ${pattern.padEnd(12)} ${v.price ? '$' + v.price.value + (v.price.unit ? '/' + v.price.unit : '') : ''}`);
+ results.push({ pattern, url: url_, ...v, chars: text.length });
+ if (v.status === 'SESSION_FAILURE') {
+ aborted = `session dropped at ${pattern} — aborting rather than recording ${targets.length - results.length} false absences`;
+ break;
+ }
+ }
+ } catch (e) {
+ aborted = e.message;
+ console.error(`[!] ${e.message}`);
+ } finally {
+ await browser.close().catch(() => {});
+ }
+
+ const ts = new Date().toISOString().replace(/[:.]/g, '').slice(0, 15) + 'Z';
+ const out = {
+ ticket: TICKET, ts, mode: probe ? 'probe' : 'full',
+ session_id: session.id,
+ pages_attempted: targets.length, pages_returned: results.length,
+ measured: results.filter(r => r.status === 'MEASURED').length,
+ not_measured: results.filter(r => r.status === 'NOT_MEASURED').length,
+ aborted,
+ retail_computed: false,
+ retail_blocked_reason:
+ 'Discount basis unsettled: vendor_registry.innovations=10.00 vs "Net Less 20%" on every DW ' +
+ 'sample request for acct 58315. Retail must not be computed until TK-11041 settles it.',
+ results,
+ };
+ const outPath = path.join(OUT_DIR, `portal-pull-${ts}.json`);
+ fs.writeFileSync(outPath, JSON.stringify(out, null, 2));
+ console.log(`\n[*] staged -> ${outPath}`);
+ console.log(`[*] measured ${out.measured}/${targets.length} pages · NO db write · NO shopify write · NO retail computed`);
+ if (aborted) { console.error(`[!] RUN INCOMPLETE: ${aborted}`); process.exit(3); }
+})();
← 6ca521c TK-11041: portal-pull runbook + second draft restore point (
·
back to Dw Unbuyable Recovery Pilot
·
TK-11041: portal pull must capture WHICH price it read, not 00cbb25 →