[object Object]

← back to Designer Wallcoverings

color tabs: fix dead collection handles (blue-wallpaper, grey-silver) + interpolated even-row PDP palette

3046c493246b5cfcb6986fb6ce4b71ddfc1057dc · 2026-07-08 15:01:02 -0700 · Steve

- color-palette.liquid: every swatch links by measured hex to its color-family
  collection (no more name-dependent dead links); +20 interpolated colors between
  each pattern color, centered in even rows. blue->blue-wallpaper, gray->grey-silver.
- color-dots.liquid + collection-list.liquid: fix dead blue-wallpaper-collection /
  grey-wallcovering handles.
- Pushed live to theme #144076931123 (verified rendering).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 3046c493246b5cfcb6986fb6ce4b71ddfc1057dc
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jul 8 15:01:02 2026 -0700

    color tabs: fix dead collection handles (blue-wallpaper, grey-silver) + interpolated even-row PDP palette
    
    - color-palette.liquid: every swatch links by measured hex to its color-family
      collection (no more name-dependent dead links); +20 interpolated colors between
      each pattern color, centered in even rows. blue->blue-wallpaper, gray->grey-silver.
    - color-dots.liquid + collection-list.liquid: fix dead blue-wallpaper-collection /
      grey-wallcovering handles.
    - Pushed live to theme #144076931123 (verified rendering).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 .../theme-LIVE-591/sections/collection-list.liquid |   4 +-
 shopify/theme-LIVE-591/snippets/color-dots.liquid  |   4 +-
 .../theme-LIVE-591/snippets/color-palette.liquid   | 204 +++++++++++++++------
 3 files changed, 152 insertions(+), 60 deletions(-)

diff --git a/shopify/theme-LIVE-591/sections/collection-list.liquid b/shopify/theme-LIVE-591/sections/collection-list.liquid
index 10fe83e8..2605c3b5 100644
--- a/shopify/theme-LIVE-591/sections/collection-list.liquid
+++ b/shopify/theme-LIVE-591/sections/collection-list.liquid
@@ -24,7 +24,7 @@
     <div style="max-width:1200px;margin:0 auto;padding:0 16px;">
       <p style="font-family:-apple-system,system-ui,sans-serif;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.08em;color:#999;margin:0 0 10px;text-align:center;">Shop by Color</p>
       <div style="display:flex;flex-wrap:nowrap;overflow-x:auto;justify-content:center;gap:16px;scrollbar-width:none;-ms-overflow-style:none;padding:2px 0;">
-        <a href="/collections/blue-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#3B5998;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Blue</span></a>
+        <a href="/collections/blue-wallpaper" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#3B5998;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Blue</span></a>
         <a href="/collections/green-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#4A7C59;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Green</span></a>
         <a href="/collections/gold-wallpaper" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#C4995C;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Gold</span></a>
         <a href="/collections/red-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#9B2335;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Red</span></a>
@@ -34,7 +34,7 @@
         <a href="/collections/yellow-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#DAA520;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Yellow</span></a>
         <a href="/collections/black" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#1a1a1a;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Black</span></a>
         <a href="/collections/white-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#F5F5F0;margin:0 auto 4px;border:2px solid #ddd;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">White</span></a>
-        <a href="/collections/grey-wallcovering" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#808080;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Gray</span></a>
+        <a href="/collections/grey-silver" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#808080;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Gray</span></a>
         <a href="/collections/brown-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#6B4226;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Brown</span></a>
         <a href="/collections/beige-cream-wallpaper-collection" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:#C8B99A;margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Beige</span></a>
         <a href="/collections/grey-silver" style="text-decoration:none;text-align:center;flex-shrink:0;"><div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#C0C0C0,#E8E8E8);margin:0 auto 4px;border:2px solid #eee;box-shadow:0 1px 4px rgba(0,0,0,0.08);"></div><span style="font-family:-apple-system,system-ui,sans-serif;font-size:10px;color:#666;">Silver</span></a>
diff --git a/shopify/theme-LIVE-591/snippets/color-dots.liquid b/shopify/theme-LIVE-591/snippets/color-dots.liquid
index 3b97e2c2..17becd29 100644
--- a/shopify/theme-LIVE-591/snippets/color-dots.liquid
+++ b/shopify/theme-LIVE-591/snippets/color-dots.liquid
@@ -40,7 +40,7 @@
 
     var C = {
       'red':'red-wallpaper-collection','crimson':'red-wallpaper-collection','burgundy':'red-wallpaper-collection','wine':'red-wallpaper-collection','maroon':'red-wallpaper-collection',
-      'blue':'blue-wallpaper-collection','navy':'blue-wallpaper-collection','cobalt':'blue-wallpaper-collection','indigo':'blue-wallpaper-collection','sky blue':'blue-wallpaper-collection','steel blue':'blue-wallpaper-collection','royal blue':'blue-wallpaper-collection',
+      'blue':'blue-wallpaper','navy':'blue-wallpaper','cobalt':'blue-wallpaper','indigo':'blue-wallpaper','sky blue':'blue-wallpaper','steel blue':'blue-wallpaper','royal blue':'blue-wallpaper',
       'green':'green-wallpaper-collection','sage':'green-wallpaper-collection','olive':'green-wallpaper-collection','forest green':'green-wallpaper-collection','emerald':'green-wallpaper-collection','mint':'green-wallpaper-collection','moss':'green-wallpaper-collection',
       'gold':'gold-wallpaper','golden':'gold-wallpaper','amber':'gold-wallpaper',
       'yellow':'yellow-wallpaper-collection','mustard':'yellow-wallpaper-collection',
@@ -49,7 +49,7 @@
       'purple':'purple','violet':'purple','plum':'purple','lavender':'purple','lilac':'purple','mauve':'purple',
       'black':'black','charcoal':'black','ebony':'black','onyx':'black',
       'white':'white-wallpaper-collection','ivory':'white-wallpaper-collection','cream':'white-wallpaper-collection','pearl':'white-wallpaper-collection','off-white':'white-wallpaper-collection',
-      'gray':'grey-wallcovering','grey':'grey-wallcovering','silver':'grey-silver','slate':'grey-wallcovering',
+      'gray':'grey-silver','grey':'grey-silver','silver':'grey-silver','slate':'grey-silver',
       'brown':'brown-wallpaper-collection','chocolate':'brown-wallpaper-collection','espresso':'brown-wallpaper-collection','walnut':'brown-wallpaper-collection','mocha':'brown-wallpaper-collection','sienna':'brown-wallpaper-collection',
       'beige':'beige-cream-wallpaper-collection','tan':'beige-cream-wallpaper-collection','taupe':'beige-cream-wallpaper-collection','sand':'beige-cream-wallpaper-collection','khaki':'beige-cream-wallpaper-collection','camel':'beige-cream-wallpaper-collection','oatmeal':'beige-cream-wallpaper-collection','linen':'beige-cream-wallpaper-collection',
       'coral':'coral','peach':'coral',
diff --git a/shopify/theme-LIVE-591/snippets/color-palette.liquid b/shopify/theme-LIVE-591/snippets/color-palette.liquid
index 37f81db8..33057aac 100644
--- a/shopify/theme-LIVE-591/snippets/color-palette.liquid
+++ b/shopify/theme-LIVE-591/snippets/color-palette.liquid
@@ -1,15 +1,15 @@
 {% comment %}
-  color-palette — "Colors In This Pattern" big-swatch-card breakdown.
-  Shows ALL colors in the pattern with a % coverage under each card.
+  color-palette — "Colors In This Pattern" swatch spectrum.
+  Shows the pattern's real colors AND ~20 interpolated colors between each pair,
+  laid out as uniform swatches centered in even rows. Every swatch (real OR
+  interpolated) links to its color-FAMILY collection, derived from the measured
+  hex — so there is never a dead/unlinked swatch. (Steve 2026-07-08)
 
   Data tiers (mirrors color-dots.liquid, kept in sync):
-    Tier 1  custom.color_dots_json / custom.color_details  (Gemini-enriched JSON: [{hex,name,pct}])
+    Tier 1  custom.color_dots_json / custom.color_details  (enriched JSON: [{hex,name,pct}])
     Tier 2  custom.primary_color_hex + dwc.ai_generated_colors (name list → hex map)
     Tier 3  custom.color_hex (single)
     Tier 4  Canvas pixel extraction from the product image (always yields real % — reliable fallback)
-
-  Replaces the small "color-dots" strip. Percentages come from the metafield
-  `pct`/`percentage` field when present, else are computed live from the image.
 {% endcomment %}
 
 {% comment %} Read the authoritative enriched field FIRST (color_details); legacy
@@ -35,6 +35,7 @@
   {% if color_name != blank %}data-color-name="{{ color_name }}"{% endif %}
   {% if color_hex != blank %}data-color-hex="{{ color_hex }}"{% endif %}
   {% if product.featured_image %}data-product-image="{{ product.featured_image | img_url: '400x400' }}"{% endif %}
+  data-product-style="{{ product.metafields.custom.style.value | default: product.type | escape }}"
 >
   <p class="dw-color-palette__title">Colors In This Pattern</p>
   <div class="dw-color-palette__cards" data-dw-color-palette-cards aria-live="polite"></div>
@@ -43,21 +44,27 @@
 <style>
   .dw-color-palette{padding:16px 0 10px;text-align:center;min-height:10px;}
   .dw-color-palette__title{font-family:Lora,serif;font-size:15px;font-weight:500;color:#3D4246;margin:0 0 12px;letter-spacing:-0.01em;}
-  /* swatches shrunk to ~1/3 (84px -> 28px), chrome scaled down to match (Steve 2026-07-08) */
-  .dw-color-palette__cards{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;max-width:640px;margin:0 auto;}
-  .dw-color-palette__card{display:flex;flex-direction:column;align-items:center;gap:3px;text-decoration:none;width:auto;min-width:28px;max-width:66px;}
-  a.dw-color-palette__card{cursor:pointer;}
-  .dw-color-palette__swatch{width:28px;height:28px;border-radius:4px;border:1px solid #e5e2dc;box-shadow:0 1px 3px rgba(0,0,0,.06);transition:transform .15s ease,border-color .15s ease,box-shadow .15s ease;position:relative;overflow:hidden;}
-  .dw-color-palette__card:hover .dw-color-palette__swatch{transform:translateY(-1px);border-color:#3D4246;box-shadow:0 3px 8px rgba(0,0,0,.14);}
-  .dw-color-palette__name{font-family:Lora,serif;font-size:10px;color:#3D4246;line-height:1.2;max-width:64px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-transform:capitalize;}
-  .dw-color-palette__pct{font-size:10px;font-weight:600;color:#8a8577;letter-spacing:.02em;}
-  .dw-color-palette__bar{display:flex;height:4px;border-radius:3px;overflow:hidden;max-width:640px;margin:12px auto 0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.04);}
+  /* Centered EVEN ROWS of uniform swatches: flex-wrap + justify-content:center
+     centers every row, including a partial last row. (Steve 2026-07-08) */
+  .dw-color-palette__cards{display:flex;flex-wrap:wrap;justify-content:center;align-content:center;gap:2px;max-width:660px;margin:0 auto;}
+  .dw-swatch{display:block;width:18px;height:18px;border-radius:3px;text-decoration:none;box-sizing:border-box;border:1px solid rgba(0,0,0,.06);transition:transform .12s ease,box-shadow .12s ease,z-index .12s;position:relative;}
+  a.dw-swatch{cursor:pointer;}
+  .dw-swatch:hover{transform:scale(1.55);box-shadow:0 3px 10px rgba(0,0,0,.22);z-index:3;border-color:rgba(0,0,0,.25);}
+  /* the pattern's REAL colors get a ring + a touch more size so they stand out
+     from the interpolated in-between steps, while rows stay even. */
+  .dw-swatch--base{width:22px;height:22px;border-radius:4px;border:1px solid #fff;box-shadow:0 0 0 1.5px #3D4246,0 1px 3px rgba(0,0,0,.14);}
+  .dw-swatch--base:hover{transform:scale(1.4);}
+  .dw-color-palette__bar{display:flex;height:4px;border-radius:3px;overflow:hidden;max-width:660px;margin:14px auto 0;box-shadow:inset 0 0 0 1px rgba(0,0,0,.04);}
   .dw-color-palette__bar span{display:block;height:100%;}
+  .dw-color-palette__legend{display:flex;flex-wrap:wrap;justify-content:center;gap:6px 14px;max-width:660px;margin:12px auto 0;}
+  .dw-color-palette__legend a,.dw-color-palette__legend span{display:inline-flex;align-items:center;gap:5px;font-family:Lora,serif;font-size:11px;color:#3D4246;text-decoration:none;text-transform:capitalize;}
+  .dw-color-palette__legend i{width:11px;height:11px;border-radius:2px;box-shadow:0 0 0 1px rgba(0,0,0,.12);}
+  .dw-color-palette__legend a:hover{color:#000;text-decoration:underline;}
   .dw-color-palette:empty{display:none;}
   @media (max-width:600px){
-    .dw-color-palette__cards{gap:6px;}
-    .dw-color-palette__card{max-width:56px;}
-    .dw-color-palette__swatch{width:22px;height:22px;}
+    .dw-color-palette__cards{gap:2px;max-width:100%;}
+    .dw-swatch{width:15px;height:15px;}
+    .dw-swatch--base{width:19px;height:19px;}
   }
 </style>
 
@@ -73,7 +80,7 @@
     /* name -> hex fallback map (kept in sync with color-dots.liquid) */
     var N = {
       'red':'#DC2626','crimson':'#DC143C','burgundy':'#800020','wine':'#722F37','maroon':'#800000',
-      'blue':'#2563EB','navy':'#1B2A4A','cobalt':'#0047AB','indigo':'#3F51B5','sky blue':'#87CEEB','steel blue':'#4682B4','royal blue':'#4169E1','blue frost':'#BcorD','deep indigo':'#1B2A4A','dark navy':'#1B2A4A','midnight':'#191970',
+      'blue':'#2563EB','navy':'#1B2A4A','cobalt':'#0047AB','indigo':'#3F51B5','sky blue':'#87CEEB','steel blue':'#4682B4','royal blue':'#4169E1','blue frost':'#C4D3E0','deep indigo':'#1B2A4A','dark navy':'#1B2A4A','midnight':'#191970',
       'green':'#16A34A','sage':'#87AE73','olive':'#808000','forest green':'#228B22','emerald':'#50C878','mint':'#98FF98','moss':'#8A9A5B','sea glass':'#C6D8CE',
       'gold':'#D4AF37','golden':'#FFD700','amber':'#FFBF00',
       'yellow':'#EAB308','mustard':'#FFDB58',
@@ -89,66 +96,151 @@
       'teal':'#0D9488','aqua':'#00FFFF','turquoise':'#40E0D0','cyan':'#06B6D4',
       'metallic':'#AAA9AD','copper':'#B87333','bronze':'#CD7F32'
     };
-    /* fix bad placeholder above */
-    N['blue frost']='#C4D3E0';
 
-    function esc(s){return (s||'').toString().replace(/[<>&"]/g,function(c){return {'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c];});}
     function pctOf(c){ var p = (c.pct!=null?c.pct:(c.percentage!=null?c.percentage:null)); if(p==null) return null; p=parseFloat(p); return isNaN(p)?null:Math.round(p); }
 
-    /* Build a card. Receives the WHOLE color object (fixes the color-dots `c` bug). */
-    function makeCard(c){
-      var hex = c.hex || N[(c.name||'').toLowerCase()] || '#ccc';
-      var name = c.name || '';
-      var pct = pctOf(c);
-      /* Link each color to ALL published ("pushed") SKUs of that color via the storefront
-         search — Shopify search only indexes published products, so "if pushed" is inherent.
-         No name -> not linkable, render a plain swatch. (Steve 2026-07-08) */
-      var card;
-      if(name){
-        card = document.createElement('a');
-        card.href = '/search?q=' + encodeURIComponent(name) + '&type=product';
-        card.title = 'View all ' + name + ' wallcoverings' + (pct!=null? ' — '+pct+'% here':'') + ' ('+hex+')';
+    /* ── HEX → color-family COLLECTION (handles verified live 2026-07-08) ──────
+       Derive the family from the REAL measured hex and link to that family's
+       collection. blue-wallpaper & grey-silver corrected from the old dead
+       handles (blue-wallpaper-collection / grey-wallcovering, which 404'd). */
+    var FAM_COLL = {
+      red:'red-wallpaper-collection', orange:'orange', yellow:'yellow-wallpaper-collection',
+      gold:'gold-wallpaper', green:'green-wallpaper-collection', teal:'turquoise',
+      blue:'blue-wallpaper', purple:'purple', pink:'pink-wallcovering-2',
+      brown:'brown-wallpaper-collection', beige:'beige-cream-wallpaper-collection',
+      black:'black', white:'white-wallpaper-collection', gray:'grey-silver'
+    };
+    function hexToRgb(h){
+      h=(h||'').replace('#','');
+      if(h.length===3) h=h.split('').map(function(x){return x+x;}).join('');
+      if(h.length<6) return null;
+      var r=parseInt(h.slice(0,2),16),g=parseInt(h.slice(2,4),16),b=parseInt(h.slice(4,6),16);
+      return (isNaN(r)||isNaN(g)||isNaN(b))?null:[r,g,b];
+    }
+    function familyFromHex(hex){
+      var rgb=hexToRgb(hex); if(!rgb) return null;
+      var r=rgb[0]/255,g=rgb[1]/255,b=rgb[2]/255;
+      var mx=Math.max(r,g,b),mn=Math.min(r,g,b),d=mx-mn;
+      var l=(mx+mn)/2, s=d===0?0:d/(1-Math.abs(2*l-1));
+      var hdeg=0;
+      if(d!==0){
+        if(mx===r) hdeg=60*(((g-b)/d)%6);
+        else if(mx===g) hdeg=60*(((b-r)/d)+2);
+        else hdeg=60*(((r-g)/d)+4);
+      }
+      if(hdeg<0) hdeg+=360;
+      if(s<0.18){
+        if(l>0.86) return 'white';
+        if(l<0.18) return 'black';
+        if((hdeg>=20 && hdeg<=70) && l>0.30) return 'beige';
+        return 'gray';
+      }
+      if(l>0.80 && (hdeg>=20 && hdeg<70)) return 'beige';
+      if(l<0.40 && s<0.75 && ((hdeg>=10 && hdeg<70) || hdeg>=345)) return 'brown';
+      if(l<0.16) return 'black';
+      if(hdeg<15||hdeg>=345) return 'red';
+      if(hdeg<40){ return (s<0.45 && l>0.55) ? 'beige' : 'orange'; }
+      if(hdeg<55){ return (s<0.45) ? 'beige' : (hdeg<50 ? 'gold' : 'yellow'); }
+      if(hdeg<65) return (l<0.45) ? 'gold' : 'yellow';
+      if(hdeg<170) return 'green';
+      if(hdeg<200) return 'teal';
+      if(hdeg<255) return 'blue';
+      if(hdeg<290) return 'purple';
+      return 'pink';
+    }
+    var PRODUCT_STYLE = (root.dataset.productStyle||'').trim();
+    function familyHref(hex){
+      var fam=familyFromHex(hex); if(!fam) return null;
+      var handle=FAM_COLL[fam]; if(!handle) return null;
+      var url='/collections/'+handle+'?sort_by=created-descending';
+      if(PRODUCT_STYLE){ url+='&filter.p.m.custom.style='+encodeURIComponent(PRODUCT_STYLE); }
+      return url;
+    }
+
+    /* ── color math: normalize + interpolate ── */
+    function normHex(hex){
+      var rgb=hexToRgb(hex); if(!rgb) return null;
+      return '#'+rgb.map(function(x){return x.toString(16).padStart(2,'0');}).join('');
+    }
+    function mix(a,b,t){
+      var ca=hexToRgb(a),cb=hexToRgb(b); if(!ca||!cb) return a;
+      var r=Math.round(ca[0]+(cb[0]-ca[0])*t),g=Math.round(ca[1]+(cb[1]-ca[1])*t),bl=Math.round(ca[2]+(cb[2]-ca[2])*t);
+      return '#'+[r,g,bl].map(function(x){return x.toString(16).padStart(2,'0');}).join('');
+    }
+    var STEPS = 20; /* interpolated colors served BETWEEN each pair (Steve 2026-07-08) */
+
+    /* Build one swatch. Every swatch links to its hex-derived family collection. */
+    function makeSwatch(hex, opts){
+      opts=opts||{};
+      var href=familyHref(hex);
+      var el=document.createElement(href?'a':'span');
+      el.className='dw-swatch'+(opts.base?' dw-swatch--base':'');
+      el.style.background=hex;
+      if(href) el.href=href;
+      var fam=familyFromHex(hex);
+      if(opts.base){
+        var lbl=(opts.name?opts.name:(fam||''));
+        el.title='Shop '+(fam||'this')+' wallcoverings'+(lbl&&lbl!==fam?' — '+lbl:'')+' ('+hex+(opts.pct!=null?', '+opts.pct+'% here':'')+')';
       } else {
-        card = document.createElement('div');
-        card.title = (pct!=null? pct+'% ':'') + '('+hex+')';
+        el.title='Shop '+(fam||'this')+' wallcoverings ('+hex+')';
       }
-      card.className = 'dw-color-palette__card';
-      var sw = document.createElement('div');
-      sw.className = 'dw-color-palette__swatch';
-      sw.style.background = hex;
-      card.appendChild(sw);
-      if(name){ var nm=document.createElement('span'); nm.className='dw-color-palette__name'; nm.textContent=name; card.appendChild(nm); }
-      if(pct!=null){ var pc=document.createElement('span'); pc.className='dw-color-palette__pct'; pc.textContent=pct+'%'; card.appendChild(pc); }
-      return card;
+      return el;
     }
 
     function render(colors){
       if(!colors || !colors.length) return false;
-      /* de-dupe by hex, sort by pct desc when available */
+      /* de-dupe by hex/name, keep order; resolve each to a real hex */
       var seen={}, list=[];
       colors.forEach(function(c){
         if(!c) return;
-        var key=(c.hex|| c.name ||'').toString().toLowerCase();
-        if(!key || seen[key]) return; seen[key]=1; list.push(c);
+        var hex=normHex(c.hex) || normHex(N[(c.name||'').toLowerCase()]);
+        if(!hex) return;
+        if(seen[hex]) return; seen[hex]=1;
+        list.push({hex:hex, name:c.name||'', pct:pctOf(c)});
       });
       if(!list.length) return false;
-      var hasPct = list.some(function(c){return pctOf(c)!=null;});
-      if(hasPct) list.sort(function(a,b){return (pctOf(b)||0)-(pctOf(a)||0);});
+      var hasPct = list.some(function(c){return c.pct!=null;});
+      if(hasPct) list.sort(function(a,b){return (b.pct||0)-(a.pct||0);});
       list = list.slice(0,8);
-      list.forEach(function(c){ cards.appendChild(makeCard(c)); });
+
+      /* Build the spectrum: base color, then STEPS interpolated to the next base. */
+      var frag=document.createDocumentFragment();
+      for(var i=0;i<list.length;i++){
+        frag.appendChild(makeSwatch(list[i].hex,{base:true,name:list[i].name,pct:list[i].pct}));
+        if(i<list.length-1){
+          for(var k=1;k<=STEPS;k++){
+            var t=k/(STEPS+1);
+            frag.appendChild(makeSwatch(mix(list[i].hex,list[i+1].hex,t),{base:false}));
+          }
+        }
+      }
+      cards.appendChild(frag);
+
+      /* named legend for the real colors (so names/% stay available, rows stay even) */
+      var named=list.filter(function(c){return c.name;});
+      if(named.length){
+        var leg=document.createElement('div'); leg.className='dw-color-palette__legend';
+        named.forEach(function(c){
+          var href=familyHref(c.hex);
+          var it=document.createElement(href?'a':'span');
+          if(href) it.href=href;
+          it.innerHTML='<i style="background:'+c.hex+'"></i>'+c.name+(c.pct!=null?' <b style="font-weight:600;color:#8a8577">'+c.pct+'%</b>':'');
+          leg.appendChild(it);
+        });
+        root.appendChild(leg);
+      }
+
       /* proportion bar when we have percentages */
       if(hasPct){
         var bar=document.createElement('div'); bar.className='dw-color-palette__bar';
-        var tot=list.reduce(function(s,c){return s+(pctOf(c)||0);},0)||1;
-        list.forEach(function(c){ var s=document.createElement('span'); s.style.background=c.hex||N[(c.name||'').toLowerCase()]||'#ccc'; s.style.flex=(pctOf(c)||0)/tot; bar.appendChild(s); });
+        var tot=list.reduce(function(s,c){return s+(c.pct||0);},0)||1;
+        list.forEach(function(c){ var sp=document.createElement('span'); sp.style.background=c.hex; sp.style.flex=(c.pct||0)/tot; bar.appendChild(sp); });
         root.appendChild(bar);
       }
       return true;
     }
 
-    /* Metafield fallbacks — used ONLY if canvas extraction yields nothing.
-       (A single color_hex alone is a worse answer than a multi-color canvas read
-       for the "all colors with %" goal, so these are demoted below canvas.) */
+    /* Metafield fallbacks — used ONLY if canvas extraction yields nothing. */
     function renderMeta(){
       var ph=root.dataset.primaryHex, aiRaw=root.dataset.aiColors, sh=root.dataset.colorHex, list2=[];
       if(ph) list2.push({hex:ph, name:root.dataset.colorName||'Primary'});

← fa453341 auto-save: 2026-07-08T14:36:14 (3 files) — DW-Programming/Im  ·  back to Designer Wallcoverings  ·  auto-save: 2026-07-08T15:06:23 (8 files) — DW-Programming/Im 79f6183d →