← back to Wallsandfabrics

public/index.html

428 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Walls &amp; Fabrics — matched-set storefront from Designer Wallcoverings</title>
<meta name="description" content="A purpose-built lens on the Designer Wallcoverings catalog. 3,600+ wallcoverings, fabrics, murals, and trims — searchable side-by-side, sortable by color wheel. Memo samples ship next business day.">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">

<!-- anti-flash theme — must run before paint -->
<script>
(function(){try{var t=localStorage.getItem('waf-theme');if(!t){t=window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light';}document.documentElement.setAttribute('data-theme',t);}catch(e){}})();
</script>

<!-- GA4 gtag (auto) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-429EVNMHVY"></script>
<script>
window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config','G-429EVNMHVY');
</script>
<!-- /GA4 gtag -->

<style>
:root{
  --bg:#F4EFE6; --fg:#0E1116; --muted:#5b5042; --line:#d8cfbf;
  --paper:#ffffff; --accent:#9A6E3A; --accent2:#46606D;
  --shadow:0 1px 0 rgba(0,0,0,.05),0 12px 28px -16px rgba(0,0,0,.18);
  --cols:5;
}
:root[data-theme="dark"]{
  --bg:#0E1116; --fg:#F0EBE0; --muted:#9aa1ae; --line:#2a3038;
  --paper:#171b22; --accent:#C99463; --accent2:#7BA3B3;
  --shadow:0 1px 0 rgba(0,0,0,.4),0 14px 30px -14px rgba(0,0,0,.6);
}
*{box-sizing:border-box}
html,body{margin:0;background:var(--bg);color:var(--fg);font-family:Georgia,'Times New Roman',serif}
body{font-size:16px;line-height:1.5}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
.wrap{max-width:1320px;margin:0 auto;padding:0 22px}
header.site{position:sticky;top:0;z-index:20;background:var(--bg);border-bottom:1px solid var(--line)}
header.site .row{display:flex;align-items:center;gap:18px;padding:14px 22px}
.brand{font-family:'Bodoni Moda','Playfair Display',Georgia,serif;font-weight:700;font-size:22px;letter-spacing:.02em}
.brand .amp{color:var(--accent);font-style:italic;padding:0 .12em}
nav.top{display:flex;gap:18px;margin-left:auto;align-items:center;font-size:14px}
nav.top a{color:var(--fg);opacity:.78}
nav.top a:hover{opacity:1}
.theme-btn{background:none;border:1px solid var(--line);color:var(--fg);width:38px;height:38px;border-radius:50%;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:16px}
.theme-btn:hover{border-color:var(--accent)}

.hero{padding:72px 22px 36px;border-bottom:1px solid var(--line)}
.hero h1{font-family:'Bodoni Moda','Playfair Display',Georgia,serif;font-size:clamp(38px,5.4vw,64px);line-height:1.05;margin:0 0 18px;letter-spacing:-.012em;max-width:18ch}
.hero h1 em{font-style:italic;color:var(--accent);font-weight:500}
.hero p.lede{font-size:18px;color:var(--muted);max-width:62ch;margin:0 0 8px;line-height:1.5}
.hero .meta{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.22em;margin-bottom:18px;font-family:-apple-system,'Helvetica Neue',sans-serif}

.editorial{padding:44px 0 56px;border-bottom:1px solid var(--line);background:linear-gradient(to bottom, transparent 0%, rgba(154,110,58,.04) 100%)}
.editorial .label{font-size:11px;color:var(--accent);text-transform:uppercase;letter-spacing:.26em;margin:0 0 14px;font-family:-apple-system,'Helvetica Neue',sans-serif;font-weight:600}
.editorial h2{font-family:'Bodoni Moda','Playfair Display',Georgia,serif;font-weight:400;font-size:clamp(22px,2.4vw,30px);line-height:1.25;margin:0 0 20px;max-width:38ch;color:var(--fg)}
.editorial .cols{display:grid;grid-template-columns:1fr 1fr;gap:36px;max-width:78ch}
@media (max-width:720px){.editorial .cols{grid-template-columns:1fr;gap:18px}}
.editorial p{font-size:15.5px;line-height:1.65;color:var(--fg);opacity:.86;margin:0 0 14px}
.editorial p:last-child{margin-bottom:0}
.editorial p em{color:var(--accent);font-style:italic}

.howto{padding:54px 0 60px;border-bottom:1px solid var(--line)}
.howto .label{font-size:11px;color:var(--accent);text-transform:uppercase;letter-spacing:.26em;margin:0 0 14px;font-family:-apple-system,'Helvetica Neue',sans-serif;font-weight:600}
.howto h2{font-family:'Bodoni Moda','Playfair Display',Georgia,serif;font-weight:400;font-size:clamp(22px,2.4vw,30px);line-height:1.25;margin:0 0 32px;max-width:34ch;color:var(--fg)}
.howto .steps{display:grid;grid-template-columns:repeat(3,1fr);gap:32px}
@media (max-width:820px){.howto .steps{grid-template-columns:1fr;gap:22px}}
.howto .step{display:flex;flex-direction:column;gap:10px;padding-top:22px;border-top:1px solid var(--line)}
.howto .num{font-family:'Bodoni Moda',Georgia,serif;font-size:13px;letter-spacing:.22em;color:var(--accent);font-style:italic}
.howto .step h3{font-family:-apple-system,'Helvetica Neue',sans-serif;font-weight:600;font-size:15px;margin:0;color:var(--fg);letter-spacing:.01em}
.howto .step p{font-size:14.5px;line-height:1.6;color:var(--fg);opacity:.78;margin:0}
.howto .footnote{margin:28px 0 0;font-size:13px;color:var(--muted);font-style:italic;max-width:62ch}

.surface-tabs{display:flex;flex-wrap:wrap;gap:8px;margin:24px 0 0}
.surface-tab{padding:10px 16px;border:1px solid var(--line);background:var(--paper);color:var(--fg);border-radius:999px;cursor:pointer;font:inherit;font-size:13px;letter-spacing:.05em;text-transform:uppercase}
.surface-tab[aria-pressed="true"]{background:var(--fg);color:var(--bg);border-color:var(--fg)}
.surface-tab .count{opacity:.6;margin-left:6px;font-variant-numeric:tabular-nums}

.toolbar{display:flex;flex-wrap:wrap;gap:14px;align-items:center;padding:18px 0;border-bottom:1px solid var(--line);margin-bottom:24px}
.toolbar .grow{flex:1;min-width:200px}
.toolbar input[type="search"]{width:100%;padding:11px 14px;font:inherit;border:1px solid var(--line);background:var(--paper);color:var(--fg);border-radius:8px}
.toolbar label{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.12em}
.toolbar select{padding:10px 12px;font:inherit;border:1px solid var(--line);background:var(--paper);color:var(--fg);border-radius:8px}
.toolbar input[type="range"]{accent-color:var(--accent);width:140px}
.toolbar .group{display:flex;align-items:center;gap:8px}

.grid{display:grid;grid-template-columns:repeat(var(--cols),1fr);gap:18px;padding:8px 0 60px}
@media (max-width:1100px){.grid{grid-template-columns:repeat(min(var(--cols),4),1fr)}}
@media (max-width:820px){.grid{grid-template-columns:repeat(min(var(--cols),3),1fr)}}
@media (max-width:560px){.grid{grid-template-columns:repeat(min(var(--cols),2),1fr)}}
.card{background:var(--paper);border:1px solid var(--line);border-radius:10px;overflow:hidden;display:flex;flex-direction:column;transition:transform .15s,box-shadow .15s}
.card:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
.card .img{aspect-ratio:1/1;background:#0001;display:block;background-size:cover;background-position:center}
.card .body{padding:11px 12px 12px}
.card .surface{font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--accent);font-weight:700}
.card .ttl{font-size:14px;line-height:1.35;margin:4px 0 6px;color:var(--fg);min-height:2.6em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.card .meta{font-size:12px;color:var(--muted);display:flex;justify-content:space-between;gap:8px}
.card a.smp{display:inline-block;margin-top:8px;font-size:12px;letter-spacing:.05em;text-transform:uppercase;color:var(--accent2);border-bottom:1px solid var(--accent2);padding-bottom:1px}

.pager{display:flex;justify-content:center;gap:10px;margin:30px 0 60px}
.pager button{padding:10px 18px;border:1px solid var(--line);background:var(--paper);color:var(--fg);border-radius:6px;cursor:pointer;font:inherit;font-size:14px}
.pager button:disabled{opacity:.4;cursor:not-allowed}
.pager .info{align-self:center;color:var(--muted);font-size:13px;font-variant-numeric:tabular-nums}

.empty{padding:80px 20px;text-align:center;color:var(--muted)}
.empty h2{color:var(--fg);font-family:'Bodoni Moda',Georgia,serif;font-weight:400;margin-bottom:8px}

footer.site{border-top:1px solid var(--line);padding:36px 0;font-size:13px;color:var(--muted);background:var(--paper)}
footer.site .grid-foot{display:grid;grid-template-columns:2fr 1fr 1fr;gap:30px}
@media (max-width:720px){footer.site .grid-foot{grid-template-columns:1fr}}
footer.site h4{font-size:11px;text-transform:uppercase;letter-spacing:.18em;color:var(--fg);margin:0 0 10px}
footer.site a{color:var(--accent2)}
.legal{margin-top:18px;font-size:12px;color:var(--muted)}
</style>
<!-- Meta Pixel — INERT until set-fb-pixel.sh is run (does NOT load fbevents.js or hit Meta until flipped) -->
<script>
(function(){
  var PIXEL_ID = '{{FACEBOOK_PIXEL_ID}}';
  // Inert until flipped — the brace check prevents BOTH the loader IIFE
  // AND the init call from running, so fbevents.js is never fetched.
  if (PIXEL_ID.indexOf('{{') !== -1) return;
  !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', PIXEL_ID);
  fbq('track', 'PageView');
})();
</script>
<!-- noscript fallback is added by set-fb-pixel.sh on flip (omitted here to avoid unflipped img phone-home) -->
<!-- End Meta Pixel -->
</head>
<body>
<!-- Theme toggle (theme1 / theme2) — query-param-gated preview surface
     (Steve 2026-05-29). ?theme=2 in URL flips to theme2 and persists in
     localStorage. Toggle UI hidden until theme2 mode active. Same key
     ('wallco-page-theme') as wallco.ai for cross-site continuity. -->
<script>
(function(){
  var qs = new URLSearchParams(location.search);
  var fromUrl = qs.get('theme');
  var saved = null; try { saved = localStorage.getItem('wallco-page-theme'); } catch(e){}
  var theme = null;
  if (fromUrl === '2' || fromUrl === 'theme2') theme = 'theme2';
  else if (fromUrl === '1' || fromUrl === 'theme1') theme = 'theme1';
  else if (saved === 'theme2' || saved === 'theme1') theme = saved;
  if (theme) {
    document.documentElement.setAttribute('data-page-theme', theme);
    if (fromUrl) { try { localStorage.setItem('wallco-page-theme', theme); } catch(e){} }
  }
})();
</script>
<style id="page-theme-css-fleet">
  [data-page-theme="theme2"] body{
    background:#fff !important; color:#0a0a0a !important;
  }
  [data-page-theme="theme2"] h1,
  [data-page-theme="theme2"] h2,
  [data-page-theme="theme2"] h3{ letter-spacing:-0.01em; font-weight:500; }
  [data-page-theme="theme2"] .card,
  [data-page-theme="theme2"] [class*="card"]{
    background:#fafafa !important; border:1px solid #e5e5e5 !important; box-shadow:none !important;
  }
  #page-theme-toggle{ display:none; }
  [data-page-theme] #page-theme-toggle{ display:inline-flex; }
  #page-theme-toggle{
    position:fixed; top:96px; right:14px; z-index:90;
    gap:0; align-items:center;
    background:rgba(255,255,255,.92); border:1px solid #d8d2c5;
    border-radius:999px; padding:3px; backdrop-filter:blur(6px);
    box-shadow:0 2px 10px rgba(0,0,0,.08);
    font:600 11px ui-sans-serif,system-ui; letter-spacing:.06em; text-transform:uppercase;
  }
  #page-theme-toggle button{
    border:0; background:transparent; color:#5a5048; cursor:pointer;
    padding:6px 14px; border-radius:999px; font:inherit; transition:all .15s;
  }
  #page-theme-toggle button[aria-pressed="true"]{ background:#1a1714; color:#faf7f2; }
  #page-theme-toggle button:hover:not([aria-pressed="true"]){ color:#1a1714; }
</style>
<div id="page-theme-toggle" role="group" aria-label="Page theme">
  <button type="button" data-theme="theme1" aria-pressed="false">Theme 1</button>
  <button type="button" data-theme="theme2" aria-pressed="false">Theme 2</button>
</div>
<script>
(function(){
  var cur = document.documentElement.getAttribute('data-page-theme') || 'theme1';
  var btns = document.querySelectorAll('#page-theme-toggle button');
  function sync(t){ btns.forEach(function(b){ b.setAttribute('aria-pressed', b.dataset.theme === t ? 'true' : 'false'); }); }
  sync(cur);
  btns.forEach(function(b){
    b.addEventListener('click', function(){
      var t = b.dataset.theme;
      document.documentElement.setAttribute('data-page-theme', t);
      try { localStorage.setItem('wallco-page-theme', t); } catch(e){}
      sync(t);
    });
  });
})();
</script>


<header class="site">
  <div class="wrap row">
    <div class="brand">Walls <span class="amp">&amp;</span> Fabrics</div>
    <nav class="top">
      <a href="#grid" data-surface="all">All</a>
      <a href="#grid" data-surface="wallcovering">Walls</a>
      <a href="#grid" data-surface="fabric">Fabrics</a>
      <a href="#grid" data-surface="mural">Murals</a>
      <a href="#grid" data-surface="trim">Trim</a>
      <button id="themeBtn" class="theme-btn" type="button" aria-label="Toggle dark / light">☼</button>
    </nav>
  </div>
</header>

<section class="hero wrap" id="hero">
  <div class="meta">A Designer Wallcoverings property · Est. 2026</div>
  <h1>When the wall <em>and</em> the fabric both have to land.</h1>
  <p class="lede">A purpose-built lens on the Designer Wallcoverings catalog &mdash; 3,600&#43; wallcoverings, fabrics, murals, and trims, searchable side-by-side and sortable by color wheel.</p>

  <div class="surface-tabs" id="surfaceTabs"></div>
</section>

<section class="editorial">
  <div class="wrap">
    <div class="label">About the Collection</div>
    <h2>Most catalogs make you switch contexts — wallpaper here, textiles over there. This one doesn&rsquo;t.</h2>
    <div class="cols">
      <p>Designers who work in <em>walls and fabrics</em> together know the problem. A botanical paper needs a drapery that won&rsquo;t fight it. A grasscloth needs the right woven texture in the cushion. Pulling them from separate catalogs, separate sites, separate spec sheets is the friction that eats an afternoon.</p>
      <p>This site is the narrower lens: every wallcovering, fabric, mural, and trim we carry, in one searchable grid. Sort by color wheel and scroll terracotta to teal across both surfaces at once. Tag a paper you like, hold its hue against the coordinating linen, and order the memo samples side-by-side &mdash; they ship the next business day from the same warehouse.</p>
    </div>
  </div>
</section>

<section class="howto">
  <div class="wrap">
    <div class="label">How matched-set browsing works</div>
    <h2>Three small moves that turn a 3,600-SKU catalog into a paired set in an afternoon.</h2>
    <div class="steps">
      <div class="step">
        <div class="num">01 — Filter</div>
        <h3>Pick a surface, then narrow.</h3>
        <p>Start with Walls or Fabrics, search a pattern name or color word (&ldquo;ochre botanical,&rdquo; &ldquo;putty linen&rdquo;), and let the grid prune to the working shortlist. Color-wheel sort puts adjacent hues next to each other so a near-match jumps the eye.</p>
      </div>
      <div class="step">
        <div class="num">02 — Pair</div>
        <h3>Hold a wall against a fabric in the same hue band.</h3>
        <p>Switch the surface filter to the other side without losing your color sort. The grid keeps you in the same chromatic range &mdash; terracotta walls next to terracotta wovens &mdash; so coordinating picks read together instead of fighting.</p>
      </div>
      <div class="step">
        <div class="num">03 — Memo</div>
        <h3>Order both samples in one pass.</h3>
        <p>Tap <em>Request memo</em> on each card. Memos for walls and fabrics ship the next business day from the same Sherman Oaks warehouse on a single packing slip &mdash; no hunting two vendor portals to reconcile arrival dates.</p>
      </div>
    </div>
    <p class="footnote">Trade pricing, quantity quotes, and CFA cuttings available on request &mdash; reach out to <a href="mailto:info@wallsandfabrics.com">info@wallsandfabrics.com</a> or call 888-373-4564.</p>
  </div>
</section>

<section class="wrap" id="grid">
  <div class="toolbar">
    <div class="grow"><input id="q" type="search" placeholder="Search by name, color, surface…" autocomplete="off"></div>
    <div class="group"><label for="sort">Sort</label>
      <select id="sort">
        <option value="newest">Newest</option>
        <option value="light-dark">Light → Dark</option>
        <option value="dark-light">Dark → Light</option>
        <option value="wheel">Color Wheel</option>
        <option value="color">Color</option>
        <option value="style">Style</option>
        <option value="sku">SKU A→Z</option>
        <option value="title">Title A→Z</option>
        <option value="price-asc">Price ↑</option>
        <option value="price-desc">Price ↓</option>
      </select>
    </div>
    <div class="group"><label for="cols">Density</label>
      <input id="cols" type="range" min="3" max="8" step="1" value="5">
    </div>
  </div>

  <div id="results" class="grid"></div>

  <div class="pager">
    <button id="prev" disabled>← Previous</button>
    <span class="info" id="info">—</span>
    <button id="next" disabled>Next →</button>
  </div>
</section>

<footer class="site">
  <div class="wrap grid-foot">
    <div>
      <h4>Walls &amp; Fabrics</h4>
      <p>A Designer Wallcoverings sister site. Trade orders, memo samples, and quantity quotes available — same catalog, narrower lens.</p>
      <p class="legal">© <span id="yr">2026</span> Designer Wallcoverings · 15442 Ventura Bl #102, Sherman Oaks CA 91403</p>
    </div>
    <div>
      <h4>Contact</h4>
      <p><a href="mailto:info@wallsandfabrics.com">info@wallsandfabrics.com</a></p>
      <p><a href="tel:+18883734564">888-373-4564</a></p>
    </div>
    <div>
      <h4>Browse</h4>
      <p><a href="#" data-surface="wallcovering">Wallcoverings</a></p>
      <p><a href="#" data-surface="fabric">Fabrics</a></p>
      <p><a href="#" data-surface="mural">Murals</a></p>
      <p><a href="#" data-surface="trim">Trim</a></p>
    </div>
  </div>
</footer>

<script>
(function(){
  // theme toggle
  var btn=document.getElementById('themeBtn');
  function setTheme(t){document.documentElement.setAttribute('data-theme',t);try{localStorage.setItem('waf-theme',t);}catch(e){}btn.textContent=(t==='dark')?'☾':'☼';}
  setTheme(document.documentElement.getAttribute('data-theme')||'light');
  btn.addEventListener('click',function(){setTheme(document.documentElement.getAttribute('data-theme')==='dark'?'light':'dark');});

  // density slider
  var sl=document.getElementById('cols');
  function applyCols(v){document.documentElement.style.setProperty('--cols',String(v));try{localStorage.setItem('waf-cols',String(v));}catch(e){}}
  var savedCols=Number(localStorage.getItem('waf-cols'))||5;
  sl.value=String(savedCols); applyCols(savedCols);
  sl.addEventListener('input',function(){applyCols(Number(sl.value));});

  // sort persistence
  var sortSel=document.getElementById('sort');
  var savedSort=localStorage.getItem('waf-sort')||'newest';
  sortSel.value=savedSort;
  sortSel.addEventListener('change',function(){try{localStorage.setItem('waf-sort',sortSel.value);}catch(e){}reload(1);});

  // search debounce
  var q=document.getElementById('q'); var qTimer=null;
  q.addEventListener('input',function(){clearTimeout(qTimer);qTimer=setTimeout(function(){reload(1);},250);});

  // surface tabs
  var SURFACE_LABELS={all:'All',wallcovering:'Walls',fabric:'Fabrics',mural:'Murals',trim:'Trim'};
  var state={surface:'all',page:1};
  var tabs=document.getElementById('surfaceTabs');
  function buildTabs(counts){
    var totalAll=Object.values(counts).reduce(function(a,b){return a+b;},0);
    var keys=['all','wallcovering','fabric','mural','trim'];
    tabs.innerHTML=keys.map(function(k){
      var n=k==='all'?totalAll:(counts[k]||0);
      var label=SURFACE_LABELS[k]||k;
      return '<button class="surface-tab" data-surface="'+k+'" aria-pressed="'+(state.surface===k?'true':'false')+'">'+label+'<span class="count">'+n.toLocaleString()+'</span></button>';
    }).join('');
    Array.from(tabs.querySelectorAll('.surface-tab')).forEach(function(b){
      b.addEventListener('click',function(){state.surface=b.dataset.surface;buildTabs(counts);reload(1);});
    });
  }
  // nav links + footer browse links also drive surface
  Array.from(document.querySelectorAll('a[data-surface]')).forEach(function(a){
    a.addEventListener('click',function(e){e.preventDefault();state.surface=a.dataset.surface;reload(1);document.getElementById('grid').scrollIntoView({behavior:'smooth',block:'start'});});
  });

  // pager
  var prev=document.getElementById('prev'),next=document.getElementById('next'),info=document.getElementById('info');
  prev.addEventListener('click',function(){if(state.page>1){reload(state.page-1);}});
  next.addEventListener('click',function(){reload(state.page+1);});

  function fmt$(p){if(!p||!p.max_price)return '';var n=Number(p.max_price);return isFinite(n)?'$'+n.toFixed(0):'';}
  function card(p){
    var img='<span class="img" style="background-image:url(\''+(p.image_url||'').replace(/'/g,'%27')+'\')"></span>';
    var url=p.product_url||'https://designerwallcoverings.com/products/'+encodeURIComponent(p.handle||p.sku||'');
    var surface=(p.__surface||'wallcovering');
    var label=SURFACE_LABELS[surface]||surface;
    var ttl=(p.title||'(untitled)').replace(/&/g,'&amp;').replace(/</g,'&lt;');
    // Standing rule — never render DW vendor names on customer surfaces.
    var brand='Designer Wallcoverings';
    return '<a href="'+url+'" target="_blank" rel="noopener noreferrer" class="card" data-sku="'+(p.sku||p.handle||'')+'">'
      +img
      +'<div class="body"><div class="surface">'+label+'</div><div class="ttl">'+ttl+'</div>'
      +'<div class="meta"><span>'+brand+'</span><span>'+fmt$(p)+'</span></div>'
      +'<span class="smp">Request memo →</span></div></a>';
  }

  function renderEmpty(){
    document.getElementById('results').innerHTML='<div class="empty"><h2>No matches</h2><p>Try widening your search or selecting a different surface.</p></div>';
    info.textContent='0 results';
    prev.disabled=true; next.disabled=true;
  }

  function reload(page){
    state.page=page||1;
    var params=new URLSearchParams({sort:sortSel.value,page:String(state.page),limit:'24'});
    if(q.value.trim()) params.set('q',q.value.trim());
    if(state.surface && state.surface!=='all') params.set('surface',state.surface);
    info.textContent='Loading…';
    fetch('/api/products?'+params.toString()).then(function(r){return r.json();}).then(function(j){
      buildTabs(j.surfaces||{});
      if(!j.items || !j.items.length){renderEmpty();return;}
      document.getElementById('results').innerHTML=j.items.map(card).join('');
      info.textContent=(j.total.toLocaleString())+' results · page '+j.page+' of '+j.pages;
      prev.disabled=j.page<=1;
      next.disabled=j.page>=j.pages;
    }).catch(function(e){info.textContent='Error loading.';console.error(e);});
  }

  document.getElementById('yr').textContent=new Date().getFullYear();
  reload(1);
})();
</script>



<!-- Big Red customer chat — lower-left, woman-avatar, vendor-redacted retail persona. -->
<script data-bigred-widget src="https://chat.designerwallcoverings.com/widget.js"
        data-host="https://chat.designerwallcoverings.com"
        data-mode="retail"
        defer onerror="this.remove()"></script>

<script src="/sku-redact.js" defer></script>
<!-- corner-nav disabled (UL-hamburger rebuild) -->
<script>window.DwHeaderConfig={siteName:"Walls & Fabrics",accent:"#9B7B4F",navLinks:[{name:'Home',url:'/'},{name:'Collections',url:'#shop'},{name:'About',url:'/about'},{name:'Care',url:'/care.html'},{name:'History',url:'/history.html'}],adminLinks:[{name:'Shopify admin',url:'https://admin.shopify.com',external:true},{name:'Edit hero',url:'#'},{name:'Analytics',url:'#'}]};</script>
<script src="/dw-header.js" defer></script>
<script src="/dw-theme-nav.js" defer></script>
</body>
</html>