[object Object]

← back to Trending Dw

trending-dw: bestseller-intelligence dashboard (Amazon facets + new-grid + sort/density/infinite-scroll), seeded from 2026-07-02 trend research

a0b04376ec61c7c4495fd003d1aba0070d399f13 · 2026-07-02 11:23:13 -0700 · Steve

Files touched

Diff

commit a0b04376ec61c7c4495fd003d1aba0070d399f13
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Jul 2 11:23:13 2026 -0700

    trending-dw: bestseller-intelligence dashboard (Amazon facets + new-grid + sort/density/infinite-scroll), seeded from 2026-07-02 trend research
---
 .deploy.conf          |   4 +
 .gitignore            |   8 +
 README.md             |  32 ++++
 data/bestsellers.json | 421 ++++++++++++++++++++++++++++++++++++++++++++++++++
 package.json          |  11 ++
 public/index.html     | 177 +++++++++++++++++++++
 scripts/seed.js       |  73 +++++++++
 server.js             |  74 +++++++++
 8 files changed, 800 insertions(+)

diff --git a/.deploy.conf b/.deploy.conf
new file mode 100644
index 0000000..e3ceb5b
--- /dev/null
+++ b/.deploy.conf
@@ -0,0 +1,4 @@
+PROJECT_NAME=trending-dw
+DEPLOY_PATH=/root/Projects/trending-dw
+HEALTH_URL=https://trending.designerwallcoverings.com/
+PORT=9951
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1924158
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+node_modules/
+.env*
+tmp/
+*.log
+.DS_Store
+dist/
+build/
+.next/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..628e70e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+# trending-dw — Trending Bestseller Intelligence
+
+`trending.designerwallcoverings.com` — an Amazon-style dashboard of what's selling across
+Google data points and print-on-demand marketplaces (Spoonflower, Etsy, Society6, Creative
+Market, William Morris et al): **which company, which item, which marketplace, and its
+bestseller signal**.
+
+## Run
+```
+npm start          # http://127.0.0.1:9948  (basic-auth admin:DW2024!)
+npm run seed       # rebuild data/bestsellers.json from research
+```
+
+## Layout
+- **Left panel (Amazon-style facets):** Marketplace · Company · Style · Color · Price, with live counts + click-to-filter.
+- **Top bar:** result count · Sort (Bestseller signal / Newest / Title / Company / Marketplace) · Density slider.
+- **Grid:** "new"-style cards (swatch tile from dominant color, NEW ribbon, signal rank), infinite-scroll.
+- All three DW hard-rule grid controls present: **sort + density + infinite scroll**.
+
+## Data
+`data/bestsellers.json` is generated by `scripts/seed.js` from the 2026-07-02 design-trend-scout
+Exa research. To keep it live, re-run design-trend-scout on a schedule and regenerate the seed
+(the refresh feed is the intended next wiring — see below).
+
+## Gated switches (Steve flips)
+- **Public go-live:** set `BASIC_AUTH=''` to remove the auth gate (default is gated — it publishes competitor intelligence).
+- **DNS:** `trending` CNAME/A on Cloudflare → Kamatera `45.61.58.125`.
+- **Deploy:** `/deploy` to Kamatera (pm2 `trending-dw`).
+- **Live Google/POD feed:** wire `scripts/seed.js` to the design-trend-scout Exa pipeline for scheduled refresh (metered — show cost).
+
+## Notes
+- **No copyrighted marketplace images** are stored/served — cards render color-swatch tiles. This is intentional (copyright + it's a public DW subdomain).
diff --git a/data/bestsellers.json b/data/bestsellers.json
new file mode 100644
index 0000000..f96e22f
--- /dev/null
+++ b/data/bestsellers.json
@@ -0,0 +1,421 @@
+{
+  "generatedAt": "2026-07-02",
+  "source": "design-trend-scout (Exa research)",
+  "count": 28,
+  "items": [
+    {
+      "id": "TR-001",
+      "dominantHex": "#2f5d3a",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Strawberry Thief",
+      "company": "William Morris & Co.",
+      "marketplace": "Google / Retail",
+      "style": "Heritage Floral",
+      "color": "Forest Green",
+      "priceBand": "$$$",
+      "signal": "Most-installed heritage wallpaper",
+      "signalRank": 98,
+      "url": "https://williammorriswallpaper.co/blogs/guides/wallpaper-trends-2026"
+    },
+    {
+      "id": "TR-002",
+      "dominantHex": "#9bab8b",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Willow Bough",
+      "company": "William Morris & Co.",
+      "marketplace": "Google / Retail",
+      "style": "Heritage Floral",
+      "color": "Sage",
+      "priceBand": "$$$",
+      "signal": "Ahead of forecast",
+      "signalRank": 92,
+      "url": "https://williammorriswallpaper.co/blogs/guides/wallpaper-trends-2026"
+    },
+    {
+      "id": "TR-003",
+      "dominantHex": "#9bab8b",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Trellis",
+      "company": "Morris & Co. (Sanderson)",
+      "marketplace": "Google / Retail",
+      "style": "Heritage Trellis",
+      "color": "Sage",
+      "priceBand": "$$$",
+      "signal": "Ahead of forecast",
+      "signalRank": 88,
+      "url": "https://williammorriswallpaper.co/blogs/guides/wallpaper-trends-2026"
+    },
+    {
+      "id": "TR-004",
+      "dominantHex": "#6e2b2b",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Layered Heritage Damask",
+      "company": "House of Hackney",
+      "marketplace": "Google / Retail",
+      "style": "Damask",
+      "color": "Oxblood",
+      "priceBand": "$$$$",
+      "signal": "Maximalist trend leader",
+      "signalRank": 84
+    },
+    {
+      "id": "TR-005",
+      "dominantHex": "#e7c3c0",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Seamless Crane Chinoiserie (removable)",
+      "company": "WallHalla",
+      "marketplace": "Etsy",
+      "style": "Chinoiserie",
+      "color": "Blush",
+      "priceBand": "$$",
+      "signal": "High review count",
+      "signalRank": 80,
+      "url": "https://www.etsy.com/shop/WallHalla"
+    },
+    {
+      "id": "TR-006",
+      "dominantHex": "#2f5d3a",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Chinoiserie Garden Mural",
+      "company": "Independent maker",
+      "marketplace": "Spoonflower",
+      "style": "Chinoiserie Mural",
+      "color": "Forest Green",
+      "priceBand": "$$$",
+      "signal": "2026-trends collection",
+      "signalRank": 78,
+      "url": "https://www.spoonflower.com/en/shop/2026-trends"
+    },
+    {
+      "id": "TR-007",
+      "dominantHex": "#e7c3c0",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Rose-Hued Cheetah Print",
+      "company": "House of Hackney",
+      "marketplace": "Google / Designer forecast",
+      "style": "Animal-Skin Print",
+      "color": "Blush",
+      "priceBand": "$$$$",
+      "signal": "Designer trend pick 2026",
+      "signalRank": 90
+    },
+    {
+      "id": "TR-008",
+      "dominantHex": "#2f5d3a",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Verdant Green Tiger Print",
+      "company": "House of Hackney",
+      "marketplace": "Google / Designer forecast",
+      "style": "Animal-Skin Print",
+      "color": "Forest Green",
+      "priceBand": "$$$$",
+      "signal": "Designer trend pick 2026",
+      "signalRank": 89
+    },
+    {
+      "id": "TR-009",
+      "dominantHex": "#76322f",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Masai Red Zebra (removable)",
+      "company": "WallHalla",
+      "marketplace": "Etsy",
+      "style": "Animal-Skin Print",
+      "color": "Claret",
+      "priceBand": "$$",
+      "signal": "Shop bestseller",
+      "signalRank": 76,
+      "url": "https://www.etsy.com/shop/WallHalla"
+    },
+    {
+      "id": "TR-010",
+      "dominantHex": "#c99a3a",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Leopard Jungle Peel & Stick",
+      "company": "WallHalla",
+      "marketplace": "Etsy",
+      "style": "Animal-Skin Print",
+      "color": "Mustard",
+      "priceBand": "$$",
+      "signal": "High review count",
+      "signalRank": 74,
+      "url": "https://www.etsy.com/shop/WallHalla"
+    },
+    {
+      "id": "TR-011",
+      "dominantHex": "#b6c33a",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Art-Deco Metallic Fan Geometric",
+      "company": "Trend forecast (Deco revival)",
+      "marketplace": "Google / Patternbank",
+      "style": "Art-Deco Geometric",
+      "color": "Chartreuse",
+      "priceBand": "$$$",
+      "signal": "Chartreuse color-of-year adjacent",
+      "signalRank": 82
+    },
+    {
+      "id": "TR-012",
+      "dominantHex": "#2b6c6b",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Seamless Geometric (peel & stick)",
+      "company": "Fancy Walls",
+      "marketplace": "Google / Retail",
+      "style": "Geometric",
+      "color": "Teal",
+      "priceBand": "$$",
+      "signal": "Top-5 P&S design 2026",
+      "signalRank": 79,
+      "url": "https://fancywalls.eu/blog/top-wallpaper-designs/"
+    },
+    {
+      "id": "TR-013",
+      "dominantHex": "#9a9488",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Grasscloth-Effect Textured Plain",
+      "company": "Wallpaperdirect editors",
+      "marketplace": "Google / Retail",
+      "style": "Texture-Effect",
+      "color": "Greige",
+      "priceBand": "$$",
+      "signal": "Key emerging trend",
+      "signalRank": 81,
+      "url": "https://blog.wallpaperdirect.com/wallpaper-trends-forecast-2025-2/"
+    },
+    {
+      "id": "TR-014",
+      "dominantHex": "#efece3",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Linen-Weave Embroidery Illusion",
+      "company": "Sanderson / Morris & Co.",
+      "marketplace": "Google / Retail",
+      "style": "Texture-Effect",
+      "color": "Cloud White",
+      "priceBand": "$$$",
+      "signal": "Tactility trend",
+      "signalRank": 77
+    },
+    {
+      "id": "TR-015",
+      "dominantHex": "#c07a4e",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Ditsy Floral Micro-Print",
+      "company": "Independent maker",
+      "marketplace": "Spoonflower",
+      "style": "Ditsy Micro-Print",
+      "color": "Terracotta",
+      "priceBand": "$",
+      "signal": "Small-room favorite",
+      "signalRank": 70,
+      "url": "https://www.spoonflower.com/en/shop/top-sellers"
+    },
+    {
+      "id": "TR-016",
+      "dominantHex": "#28324f",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Tiny Geometric Micro-Print",
+      "company": "Independent maker",
+      "marketplace": "Spoonflower",
+      "style": "Ditsy Micro-Print",
+      "color": "Indigo",
+      "priceBand": "$",
+      "signal": "Micro-print rising",
+      "signalRank": 68
+    },
+    {
+      "id": "TR-017",
+      "dominantHex": "#2f5d3a",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Fern Botanical Removable",
+      "company": "MUSE Wall Studio",
+      "marketplace": "Etsy",
+      "style": "Botanical",
+      "color": "Forest Green",
+      "priceBand": "$$$",
+      "signal": "Luxury P&S bestseller",
+      "signalRank": 83,
+      "url": "https://www.etsy.com/uk/shop/musewallstudio"
+    },
+    {
+      "id": "TR-018",
+      "dominantHex": "#9a9488",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Gray Botanical Ink Leaf",
+      "company": "MUSE Wall Studio",
+      "marketplace": "Etsy",
+      "style": "Botanical",
+      "color": "Greige",
+      "priceBand": "$$",
+      "signal": "Shop bestseller",
+      "signalRank": 73,
+      "url": "https://www.etsy.com/uk/shop/musewallstudio"
+    },
+    {
+      "id": "TR-019",
+      "dominantHex": "#e7c3c0",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Mineral Science Botanical",
+      "company": "MUSE Wall Studio",
+      "marketplace": "Etsy",
+      "style": "Botanical",
+      "color": "Blush",
+      "priceBand": "$$",
+      "signal": "Featured bestseller",
+      "signalRank": 69,
+      "url": "https://www.etsy.com/uk/shop/musewallstudio"
+    },
+    {
+      "id": "TR-020",
+      "dominantHex": "#2b6c6b",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Painterly Botanical Panorama",
+      "company": "Wallpaperdirect editors",
+      "marketplace": "Google / Retail",
+      "style": "Scenic Mural",
+      "color": "Teal",
+      "priceBand": "$$$$",
+      "signal": "Premium timeless seller",
+      "signalRank": 80,
+      "url": "https://blog.wallpaperdirect.com/wallpaper-trends-forecast-2025-2/"
+    },
+    {
+      "id": "TR-021",
+      "dominantHex": "#9bab8b",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Watercolor Tropical Palm (removable)",
+      "company": "WallHalla",
+      "marketplace": "Etsy",
+      "style": "Tropical",
+      "color": "Sage",
+      "priceBand": "$$",
+      "signal": "High review count",
+      "signalRank": 66,
+      "url": "https://www.etsy.com/shop/WallHalla"
+    },
+    {
+      "id": "TR-022",
+      "dominantHex": "#c07a4e",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Selina Boho Peel & Stick",
+      "company": "Wallblush",
+      "marketplace": "Google / Retail",
+      "style": "Boho",
+      "color": "Terracotta",
+      "priceBand": "$$",
+      "signal": "New 2026 release",
+      "signalRank": 72,
+      "url": "https://wallblush.com/products/selina"
+    },
+    {
+      "id": "TR-023",
+      "dominantHex": "#9a9488",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Herringbone Brushstroke Neutral",
+      "company": "MUSE Wall Studio",
+      "marketplace": "Etsy",
+      "style": "Geometric",
+      "color": "Greige",
+      "priceBand": "$$",
+      "signal": "Scandi bestseller",
+      "signalRank": 67,
+      "url": "https://www.etsy.com/uk/shop/musewallstudio"
+    },
+    {
+      "id": "TR-024",
+      "dominantHex": "#26364d",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Blue Chevron Watercolor",
+      "company": "MUSE Wall Studio",
+      "marketplace": "Etsy",
+      "style": "Geometric",
+      "color": "Navy",
+      "priceBand": "$$",
+      "signal": "Neutral P&S seller",
+      "signalRank": 64,
+      "url": "https://www.etsy.com/uk/shop/musewallstudio"
+    },
+    {
+      "id": "TR-025",
+      "dominantHex": "#232323",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Classic Black & White Floral",
+      "company": "Fancy Walls",
+      "marketplace": "Google / Retail",
+      "style": "Heritage Floral",
+      "color": "Black",
+      "priceBand": "$$",
+      "signal": "Top-5 P&S design 2026",
+      "signalRank": 75,
+      "url": "https://fancywalls.eu/blog/top-wallpaper-designs/"
+    },
+    {
+      "id": "TR-026",
+      "dominantHex": "#e7c3c0",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Must-Have Florals",
+      "company": "Fancy Walls",
+      "marketplace": "Google / Retail",
+      "style": "Heritage Floral",
+      "color": "Blush",
+      "priceBand": "$$",
+      "signal": "#1 P&S design 2026",
+      "signalRank": 85,
+      "url": "https://fancywalls.eu/blog/top-wallpaper-designs/"
+    },
+    {
+      "id": "TR-027",
+      "dominantHex": "#c07a4e",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "2026 Color-Trend Collection (Earthy Vibrancy)",
+      "company": "Spoonflower community",
+      "marketplace": "Spoonflower",
+      "style": "Color Trend",
+      "color": "Terracotta",
+      "priceBand": "$$",
+      "signal": "Curated 2026 color trends",
+      "signalRank": 71,
+      "url": "https://www.spoonflower.com/en/shop/2026-color-trends"
+    },
+    {
+      "id": "TR-028",
+      "dominantHex": "#efece3",
+      "spottedAt": "2026-07-02",
+      "isNew": true,
+      "title": "Cloud Dancer Warm-White Program",
+      "company": "Spoonflower community",
+      "marketplace": "Spoonflower",
+      "style": "Calm Neutral",
+      "color": "Cloud White",
+      "priceBand": "$",
+      "signal": "Pantone 2026 aligned",
+      "signalRank": 65,
+      "url": "https://www.spoonflower.com/en/shop/2026-trends"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..e43629a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "trending-dw",
+  "version": "0.1.0",
+  "private": true,
+  "description": "trending.designerwallcoverings.com — bestseller intelligence across Google + POD marketplaces",
+  "main": "server.js",
+  "scripts": {
+    "start": "node server.js",
+    "seed": "node scripts/seed.js"
+  }
+}
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..760478b
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,177 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8"/>
+<meta name="viewport" content="width=device-width, initial-scale=1"/>
+<title>Trending — Designer Wallcoverings</title>
+<style>
+  :root{ --cols: 4; --ink:#1c1a17; --paper:#faf8f3; --line:#e4ded2; --accent:#2f5d3a; --muted:#8a8272; --chip:#f0ebe0; }
+  *{ box-sizing:border-box; }
+  body{ margin:0; font-family:"Helvetica Neue",Arial,sans-serif; color:var(--ink); background:var(--paper); -webkit-font-smoothing:antialiased; }
+  a{ color:inherit; }
+  header.top{ display:flex; align-items:baseline; gap:18px; padding:18px 26px 14px; border-bottom:1px solid var(--line); position:sticky; top:0; background:var(--paper); z-index:20; }
+  header.top .wm{ font-weight:800; letter-spacing:.14em; text-transform:uppercase; font-size:15px; }
+  header.top .wm small{ display:block; font-weight:400; letter-spacing:.22em; font-size:9px; color:var(--muted); margin-top:3px; }
+  header.top .tag{ font-size:12px; color:var(--muted); font-style:italic; }
+  .layout{ display:grid; grid-template-columns: 258px 1fr; align-items:start; }
+  /* LEFT AMAZON-STYLE PANEL */
+  aside{ position:sticky; top:64px; align-self:start; height:calc(100vh - 64px); overflow:auto; padding:16px 14px 40px; border-right:1px solid var(--line); }
+  aside .search{ width:100%; padding:9px 11px; border:1px solid var(--line); border-radius:7px; font-size:13px; margin-bottom:14px; background:#fff; }
+  .facet{ margin-bottom:16px; }
+  .facet h4{ margin:0 0 7px; font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
+  .facet a{ display:flex; justify-content:space-between; gap:8px; padding:4px 6px; font-size:12.5px; text-decoration:none; border-radius:5px; cursor:pointer; }
+  .facet a:hover{ background:#fff; }
+  .facet a.active{ background:var(--accent); color:#fff; font-weight:600; }
+  .facet a .c{ color:var(--muted); font-variant-numeric:tabular-nums; }
+  .facet a.active .c{ color:#e8f0ea; }
+  .reset{ font-size:11px; color:var(--accent); cursor:pointer; text-decoration:underline; }
+  /* MAIN */
+  main{ padding:16px 26px 60px; }
+  .bar{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-bottom:16px; }
+  .bar .count{ font-size:13px; color:var(--muted); }
+  .bar .count b{ color:var(--ink); }
+  .bar label{ font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin-right:6px; }
+  .bar select{ padding:7px 9px; border:1px solid var(--line); border-radius:7px; font-size:13px; background:#fff; }
+  .bar .dens{ display:flex; align-items:center; gap:8px; margin-left:auto; }
+  .bar input[type=range]{ width:130px; accent-color:var(--accent); }
+  .grid{ display:grid; grid-template-columns:repeat(var(--cols),1fr); gap:16px; }
+  .card{ border:1px solid var(--line); border-radius:12px; overflow:hidden; background:#fff; display:flex; flex-direction:column; transition:box-shadow .15s, transform .15s; }
+  .card:hover{ box-shadow:0 8px 24px rgba(0,0,0,.09); transform:translateY(-2px); }
+  .swatch{ aspect-ratio:4/3; position:relative; }
+  .swatch .ribbon{ position:absolute; top:10px; left:-30px; transform:rotate(-45deg); background:#b6392f; color:#fff; font-size:10px; letter-spacing:.14em; padding:3px 34px; font-weight:700; }
+  .swatch .rank{ position:absolute; bottom:8px; right:9px; background:rgba(0,0,0,.55); color:#fff; font-size:10px; padding:2px 7px; border-radius:20px; letter-spacing:.05em; }
+  .body{ padding:11px 12px 13px; display:flex; flex-direction:column; gap:6px; flex:1; }
+  .title{ font-size:14px; font-weight:700; line-height:1.25; }
+  .company{ font-size:12px; color:var(--ink); }
+  .company b{ color:var(--accent); }
+  .chips{ display:flex; flex-wrap:wrap; gap:5px; margin-top:2px; }
+  .chip{ font-size:10px; padding:3px 7px; border-radius:20px; background:var(--chip); color:#5a5346; letter-spacing:.03em; }
+  .chip.mk{ background:#1c1a17; color:#fff; }
+  .signal{ font-size:11.5px; color:var(--muted); margin-top:auto; }
+  .signal .dot{ color:var(--accent); }
+  .src{ font-size:11px; color:var(--accent); text-decoration:none; margin-top:4px; }
+  .src:hover{ text-decoration:underline; }
+  #sentinel{ height:40px; }
+  .loading{ text-align:center; color:var(--muted); font-size:12px; padding:20px; }
+  @media(max-width:820px){ .layout{ grid-template-columns:1fr; } aside{ position:static; height:auto; border-right:none; border-bottom:1px solid var(--line); } }
+</style>
+</head>
+<body>
+<header class="top">
+  <div class="wm">Designer Wallcoverings<small>Trending Intelligence</small></div>
+  <div class="tag">Bestsellers across Google &amp; print-on-demand — who's selling what, right now</div>
+</header>
+<div class="layout">
+  <aside>
+    <input class="search" id="search" placeholder="Search item, company, style…" />
+    <div style="margin-bottom:12px"><span class="reset" id="reset">✕ Clear all filters</span></div>
+    <div id="facets"></div>
+  </aside>
+  <main>
+    <div class="bar">
+      <div class="count"><b id="cnt">0</b> bestseller data points</div>
+      <div>
+        <label>Sort</label>
+        <select id="sort">
+          <option value="signal">Bestseller signal</option>
+          <option value="newest">Newest</option>
+          <option value="titleAZ">Title A–Z</option>
+          <option value="company">Company</option>
+          <option value="marketplace">Marketplace</option>
+        </select>
+      </div>
+      <div class="dens"><label>Density</label><input type="range" id="dens" min="2" max="6" step="1" value="4"/></div>
+    </div>
+    <div class="grid" id="grid"></div>
+    <div id="sentinel"></div>
+    <div class="loading" id="loading" style="display:none">Loading…</div>
+  </main>
+</div>
+<script>
+const state = {
+  filters: JSON.parse(localStorage.getItem('tdw_filters')||'{}'),
+  q: '', sort: localStorage.getItem('tdw_sort')||'signal',
+  page: 1, size: 12, total: 0, loading: false, done: false
+};
+const DIMS = [['marketplace','Marketplace'],['company','Company'],['style','Style'],['color','Color'],['priceBand','Price']];
+
+function save(){ localStorage.setItem('tdw_filters', JSON.stringify(state.filters)); localStorage.setItem('tdw_sort', state.sort); }
+
+async function loadFacets(){
+  const f = await (await fetch('/api/facets')).json();
+  const el = document.getElementById('facets'); el.innerHTML='';
+  for (const [key,label] of DIMS){
+    const rows = (f[key]||[]);
+    if(!rows.length) continue;
+    const box = document.createElement('div'); box.className='facet';
+    box.innerHTML = '<h4>'+label+'</h4>';
+    for (const {value,count} of rows){
+      const a = document.createElement('a');
+      a.className = state.filters[key]===value ? 'active':'';
+      a.innerHTML = '<span>'+value+'</span><span class="c">'+count+'</span>';
+      a.onclick = ()=>{ if(state.filters[key]===value) delete state.filters[key]; else state.filters[key]=value; save(); loadFacets(); reload(); };
+      box.appendChild(a);
+    }
+    el.appendChild(box);
+  }
+}
+
+function qs(){
+  const p = new URLSearchParams();
+  for (const k in state.filters) p.set(k, state.filters[k]);
+  if (state.q) p.set('q', state.q);
+  p.set('sort', state.sort); p.set('page', state.page); p.set('size', state.size);
+  return p.toString();
+}
+
+function card(it){
+  const c = document.createElement('div'); c.className='card';
+  const grad = 'linear-gradient(135deg,'+it.dominantHex+' 0%,'+shade(it.dominantHex,-18)+' 100%)';
+  c.innerHTML =
+    '<div class="swatch" style="background:'+grad+'">'
+    + (it.isNew?'<div class="ribbon">NEW</div>':'')
+    + (it.signalRank?'<div class="rank">▲ '+it.signalRank+'</div>':'')
+    + '</div>'
+    + '<div class="body">'
+    + '<div class="title">'+esc(it.title)+'</div>'
+    + '<div class="company">by <b>'+esc(it.company)+'</b></div>'
+    + '<div class="chips"><span class="chip mk">'+esc(it.marketplace)+'</span><span class="chip">'+esc(it.style)+'</span><span class="chip">'+esc(it.color)+'</span><span class="chip">'+esc(it.priceBand)+'</span></div>'
+    + '<div class="signal"><span class="dot">●</span> '+esc(it.signal)+'</div>'
+    + (it.url?'<a class="src" href="'+it.url+'" target="_blank" rel="noopener noreferrer">View source ↗</a>':'')
+    + '</div>';
+  return c;
+}
+function esc(s){ return String(s).replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c])); }
+function shade(hex,p){ const n=parseInt(hex.slice(1),16); let r=(n>>16)+p, g=((n>>8)&255)+p, b=(n&255)+p; r=Math.max(0,Math.min(255,r));g=Math.max(0,Math.min(255,g));b=Math.max(0,Math.min(255,b)); return '#'+((1<<24)+(r<<16)+(g<<8)+b).toString(16).slice(1); }
+
+async function fetchPage(){
+  if(state.loading||state.done) return;
+  state.loading=true; document.getElementById('loading').style.display='block';
+  const d = await (await fetch('/api/items?'+qs())).json();
+  state.total = d.total; document.getElementById('cnt').textContent = d.total;
+  const grid = document.getElementById('grid');
+  d.items.forEach(it=> grid.appendChild(card(it)));
+  if (state.page*state.size >= d.total) state.done=true;
+  state.page++; state.loading=false; document.getElementById('loading').style.display='none';
+}
+function reload(){ state.page=1; state.done=false; document.getElementById('grid').innerHTML=''; fetchPage(); }
+
+// density
+const dens=document.getElementById('dens');
+dens.value = localStorage.getItem('tdw_cols')||4;
+document.documentElement.style.setProperty('--cols', dens.value);
+dens.oninput = ()=>{ document.documentElement.style.setProperty('--cols', dens.value); localStorage.setItem('tdw_cols', dens.value); };
+// sort
+const sortSel=document.getElementById('sort'); sortSel.value=state.sort;
+sortSel.onchange=()=>{ state.sort=sortSel.value; save(); reload(); };
+// search (debounced)
+let t; document.getElementById('search').oninput=(e)=>{ clearTimeout(t); t=setTimeout(()=>{ state.q=e.target.value.trim(); reload(); },250); };
+// reset
+document.getElementById('reset').onclick=()=>{ state.filters={}; state.q=''; document.getElementById('search').value=''; save(); loadFacets(); reload(); };
+// infinite scroll
+new IntersectionObserver((ents)=>{ if(ents[0].isIntersecting) fetchPage(); },{rootMargin:'400px'}).observe(document.getElementById('sentinel'));
+
+loadFacets(); reload();
+</script>
+</body>
+</html>
diff --git a/scripts/seed.js b/scripts/seed.js
new file mode 100644
index 0000000..06ee5fb
--- /dev/null
+++ b/scripts/seed.js
@@ -0,0 +1,73 @@
+#!/usr/bin/env node
+// Builds data/bestsellers.json from the 2026-07-02 design-trend-scout research.
+// Each record = one demonstrable bestseller/trend data point across Google + POD marketplaces.
+// NO copyrighted marketplace images are stored — cards render swatch tiles from dominantHex.
+const fs = require('fs');
+const path = require('path');
+
+// color families -> representative hex (for the swatch tile)
+const HEX = {
+  'Forest Green': '#2f5d3a', 'Oxblood': '#6e2b2b', 'Plum': '#5a3a55', 'Chartreuse': '#b6c33a',
+  'Cloud White': '#efece3', 'Blush': '#e7c3c0', 'Terracotta': '#c07a4e', 'Indigo': '#28324f',
+  'Greige': '#9a9488', 'Mustard': '#c99a3a', 'Teal': '#2b6c6b', 'Black': '#232323',
+  'Sage': '#9bab8b', 'Claret': '#76322f', 'Gold': '#b49555', 'Navy': '#26364d'
+};
+
+// one entry helper
+let _id = 0;
+const seen = [];
+function it(o){ seen.push({ id: 'TR-' + String(++_id).padStart(3,'0'), dominantHex: HEX[o.color] || '#888', spottedAt: '2026-07-02', isNew: o.isNew !== false, ...o }); }
+
+// ---- Heritage maximalist florals (the #1 trend) ----
+it({ title:'Strawberry Thief', company:'William Morris & Co.', marketplace:'Google / Retail', style:'Heritage Floral', color:'Forest Green', priceBand:'$$$', signal:'Most-installed heritage wallpaper', signalRank:98, url:'https://williammorriswallpaper.co/blogs/guides/wallpaper-trends-2026' });
+it({ title:'Willow Bough', company:'William Morris & Co.', marketplace:'Google / Retail', style:'Heritage Floral', color:'Sage', priceBand:'$$$', signal:'Ahead of forecast', signalRank:92, url:'https://williammorriswallpaper.co/blogs/guides/wallpaper-trends-2026' });
+it({ title:'Trellis', company:'Morris & Co. (Sanderson)', marketplace:'Google / Retail', style:'Heritage Trellis', color:'Sage', priceBand:'$$$', signal:'Ahead of forecast', signalRank:88, url:'https://williammorriswallpaper.co/blogs/guides/wallpaper-trends-2026' });
+it({ title:'Layered Heritage Damask', company:'House of Hackney', marketplace:'Google / Retail', style:'Damask', color:'Oxblood', priceBand:'$$$$', signal:'Maximalist trend leader', signalRank:84 });
+
+// ---- Chinoiserie (heritage #2) ----
+it({ title:'Seamless Crane Chinoiserie (removable)', company:'WallHalla', marketplace:'Etsy', style:'Chinoiserie', color:'Blush', priceBand:'$$', signal:'High review count', signalRank:80, url:'https://www.etsy.com/shop/WallHalla' });
+it({ title:'Chinoiserie Garden Mural', company:'Independent maker', marketplace:'Spoonflower', style:'Chinoiserie Mural', color:'Forest Green', priceBand:'$$$', signal:'2026-trends collection', signalRank:78, url:'https://www.spoonflower.com/en/shop/2026-trends' });
+
+// ---- Animal-skin print with a twist (the HIGH gap / hot lane) ----
+it({ title:'Rose-Hued Cheetah Print', company:'House of Hackney', marketplace:'Google / Designer forecast', style:'Animal-Skin Print', color:'Blush', priceBand:'$$$$', signal:'Designer trend pick 2026', signalRank:90 });
+it({ title:'Verdant Green Tiger Print', company:'House of Hackney', marketplace:'Google / Designer forecast', style:'Animal-Skin Print', color:'Forest Green', priceBand:'$$$$', signal:'Designer trend pick 2026', signalRank:89 });
+it({ title:'Masai Red Zebra (removable)', company:'WallHalla', marketplace:'Etsy', style:'Animal-Skin Print', color:'Claret', priceBand:'$$', signal:'Shop bestseller', signalRank:76, url:'https://www.etsy.com/shop/WallHalla' });
+it({ title:'Leopard Jungle Peel & Stick', company:'WallHalla', marketplace:'Etsy', style:'Animal-Skin Print', color:'Mustard', priceBand:'$$', signal:'High review count', signalRank:74, url:'https://www.etsy.com/shop/WallHalla' });
+
+// ---- Chartreuse + Art-Deco metallic geometric (HIGH gap) ----
+it({ title:'Art-Deco Metallic Fan Geometric', company:'Trend forecast (Deco revival)', marketplace:'Google / Patternbank', style:'Art-Deco Geometric', color:'Chartreuse', priceBand:'$$$', signal:'Chartreuse color-of-year adjacent', signalRank:82 });
+it({ title:'Seamless Geometric (peel & stick)', company:'Fancy Walls', marketplace:'Google / Retail', style:'Geometric', color:'Teal', priceBand:'$$', signal:'Top-5 P&S design 2026', signalRank:79, url:'https://fancywalls.eu/blog/top-wallpaper-designs/' });
+
+// ---- Tactile texture-effect (HIGH gap) ----
+it({ title:'Grasscloth-Effect Textured Plain', company:'Wallpaperdirect editors', marketplace:'Google / Retail', style:'Texture-Effect', color:'Greige', priceBand:'$$', signal:'Key emerging trend', signalRank:81, url:'https://blog.wallpaperdirect.com/wallpaper-trends-forecast-2025-2/' });
+it({ title:'Linen-Weave Embroidery Illusion', company:'Sanderson / Morris & Co.', marketplace:'Google / Retail', style:'Texture-Effect', color:'Cloud White', priceBand:'$$$', signal:'Tactility trend', signalRank:77 });
+
+// ---- Small-scale ditsy micro-prints ----
+it({ title:'Ditsy Floral Micro-Print', company:'Independent maker', marketplace:'Spoonflower', style:'Ditsy Micro-Print', color:'Terracotta', priceBand:'$', signal:'Small-room favorite', signalRank:70, url:'https://www.spoonflower.com/en/shop/top-sellers' });
+it({ title:'Tiny Geometric Micro-Print', company:'Independent maker', marketplace:'Spoonflower', style:'Ditsy Micro-Print', color:'Indigo', priceBand:'$', signal:'Micro-print rising', signalRank:68 });
+
+// ---- Botanical / fern / greenery (Etsy strong sellers) ----
+it({ title:'Fern Botanical Removable', company:'MUSE Wall Studio', marketplace:'Etsy', style:'Botanical', color:'Forest Green', priceBand:'$$$', signal:'Luxury P&S bestseller', signalRank:83, url:'https://www.etsy.com/uk/shop/musewallstudio' });
+it({ title:'Gray Botanical Ink Leaf', company:'MUSE Wall Studio', marketplace:'Etsy', style:'Botanical', color:'Greige', priceBand:'$$', signal:'Shop bestseller', signalRank:73, url:'https://www.etsy.com/uk/shop/musewallstudio' });
+it({ title:'Mineral Science Botanical', company:'MUSE Wall Studio', marketplace:'Etsy', style:'Botanical', color:'Blush', priceBand:'$$', signal:'Featured bestseller', signalRank:69, url:'https://www.etsy.com/uk/shop/musewallstudio' });
+
+// ---- Painterly murals / panoramas ----
+it({ title:'Painterly Botanical Panorama', company:'Wallpaperdirect editors', marketplace:'Google / Retail', style:'Scenic Mural', color:'Teal', priceBand:'$$$$', signal:'Premium timeless seller', signalRank:80, url:'https://blog.wallpaperdirect.com/wallpaper-trends-forecast-2025-2/' });
+it({ title:'Watercolor Tropical Palm (removable)', company:'WallHalla', marketplace:'Etsy', style:'Tropical', color:'Sage', priceBand:'$$', signal:'High review count', signalRank:66, url:'https://www.etsy.com/shop/WallHalla' });
+
+// ---- Boho / mid-century / coastal ----
+it({ title:'Selina Boho Peel & Stick', company:'Wallblush', marketplace:'Google / Retail', style:'Boho', color:'Terracotta', priceBand:'$$', signal:'New 2026 release', signalRank:72, url:'https://wallblush.com/products/selina' });
+it({ title:'Herringbone Brushstroke Neutral', company:'MUSE Wall Studio', marketplace:'Etsy', style:'Geometric', color:'Greige', priceBand:'$$', signal:'Scandi bestseller', signalRank:67, url:'https://www.etsy.com/uk/shop/musewallstudio' });
+it({ title:'Blue Chevron Watercolor', company:'MUSE Wall Studio', marketplace:'Etsy', style:'Geometric', color:'Navy', priceBand:'$$', signal:'Neutral P&S seller', signalRank:64, url:'https://www.etsy.com/uk/shop/musewallstudio' });
+
+// ---- Classic B&W + florals (Fancy Walls top-5) ----
+it({ title:'Classic Black & White Floral', company:'Fancy Walls', marketplace:'Google / Retail', style:'Heritage Floral', color:'Black', priceBand:'$$', signal:'Top-5 P&S design 2026', signalRank:75, url:'https://fancywalls.eu/blog/top-wallpaper-designs/' });
+it({ title:'Must-Have Florals', company:'Fancy Walls', marketplace:'Google / Retail', style:'Heritage Floral', color:'Blush', priceBand:'$$', signal:'#1 P&S design 2026', signalRank:85, url:'https://fancywalls.eu/blog/top-wallpaper-designs/' });
+
+// ---- Spoonflower marketplace category signals ----
+it({ title:'2026 Color-Trend Collection (Earthy Vibrancy)', company:'Spoonflower community', marketplace:'Spoonflower', style:'Color Trend', color:'Terracotta', priceBand:'$$', signal:'Curated 2026 color trends', signalRank:71, url:'https://www.spoonflower.com/en/shop/2026-color-trends' });
+it({ title:'Cloud Dancer Warm-White Program', company:'Spoonflower community', marketplace:'Spoonflower', style:'Calm Neutral', color:'Cloud White', priceBand:'$', signal:'Pantone 2026 aligned', signalRank:65, url:'https://www.spoonflower.com/en/shop/2026-trends' });
+
+const out = { generatedAt: '2026-07-02', source: 'design-trend-scout (Exa research)', count: seen.length, items: seen };
+fs.writeFileSync(path.join(__dirname, '..', 'data', 'bestsellers.json'), JSON.stringify(out, null, 2));
+console.log('wrote', seen.length, 'bestseller records');
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..bba5d4e
--- /dev/null
+++ b/server.js
@@ -0,0 +1,74 @@
+#!/usr/bin/env node
+// trending.designerwallcoverings.com — bestseller-intelligence dashboard.
+// Zero-dependency Node http server. Basic-auth gated (admin:DW2024!) by default.
+// Aggregates POD/Google bestseller data points from data/bestsellers.json.
+const http = require('http');
+const fs = require('fs');
+const path = require('path');
+
+const PORT = process.env.PORT || 9951;
+const PUBLIC = path.join(__dirname, 'public');
+const DATA = path.join(__dirname, 'data', 'bestsellers.json');
+const AUTH = process.env.BASIC_AUTH === undefined ? 'admin:DW2024!' : process.env.BASIC_AUTH;  // BASIC_AUTH='' disables (public go-live is gated)
+
+const MIME = { '.html':'text/html', '.js':'application/javascript', '.css':'text/css', '.json':'application/json', '.svg':'image/svg+xml', '.ico':'image/x-icon' };
+
+function loadItems(){ try { return JSON.parse(fs.readFileSync(DATA,'utf8')).items || []; } catch(e){ return []; } }
+
+function facets(items){
+  const dim = (key) => {
+    const m = {};
+    for (const it of items){ const v = it[key]; if(!v) continue; m[v] = (m[v]||0)+1; }
+    return Object.entries(m).sort((a,b)=>b[1]-a[1]).map(([value,count])=>({value,count}));
+  };
+  return { marketplace: dim('marketplace'), company: dim('company'), style: dim('style'), color: dim('color'), priceBand: dim('priceBand') };
+}
+
+function send(res, code, body, type){ res.writeHead(code, { 'Content-Type': type||'application/json', 'Cache-Control':'no-store' }); res.end(body); }
+
+const server = http.createServer((req,res)=>{
+  // basic auth gate
+  if (AUTH){
+    const hdr = req.headers.authorization || '';
+    const expect = 'Basic ' + Buffer.from(AUTH).toString('base64');
+    if (hdr !== expect){ res.writeHead(401, { 'WWW-Authenticate':'Basic realm="trending-dw"' }); return res.end('Auth required'); }
+  }
+  const u = new URL(req.url, 'http://x');
+
+  if (u.pathname === '/api/facets'){ return send(res, 200, JSON.stringify(facets(loadItems()))); }
+
+  if (u.pathname === '/api/items'){
+    let items = loadItems();
+    const q = (k)=> (u.searchParams.get(k)||'').toLowerCase();
+    for (const key of ['marketplace','company','style','color','priceBand']){
+      const val = u.searchParams.get(key);
+      if (val) items = items.filter(it => (it[key]||'') === val);
+    }
+    const search = q('q');
+    if (search) items = items.filter(it => (it.title+' '+it.company+' '+it.style+' '+it.marketplace).toLowerCase().includes(search));
+    const sort = u.searchParams.get('sort') || 'signal';
+    const cmp = {
+      signal: (a,b)=> (b.signalRank||0)-(a.signalRank||0),
+      titleAZ: (a,b)=> a.title.localeCompare(b.title),
+      company: (a,b)=> a.company.localeCompare(b.company),
+      marketplace: (a,b)=> a.marketplace.localeCompare(b.marketplace),
+      newest: (a,b)=> (b.spottedAt||'').localeCompare(a.spottedAt||'')
+    }[sort] || ((a,b)=>0);
+    items = items.slice().sort(cmp);
+    const page = parseInt(u.searchParams.get('page')||'1',10);
+    const size = parseInt(u.searchParams.get('size')||'12',10);
+    const total = items.length;
+    const paged = items.slice((page-1)*size, page*size);
+    return send(res, 200, JSON.stringify({ total, page, size, items: paged }));
+  }
+
+  // static
+  let p = u.pathname === '/' ? '/index.html' : u.pathname;
+  const fp = path.join(PUBLIC, path.normalize(p).replace(/^(\.\.[\/\\])+/,''));
+  fs.readFile(fp, (err,buf)=>{
+    if (err){ return send(res, 404, 'Not found', 'text/plain'); }
+    send(res, 200, buf, MIME[path.extname(fp)] || 'application/octet-stream');
+  });
+});
+
+server.listen(PORT, ()=> console.log('trending-dw on http://127.0.0.1:'+PORT+(AUTH?'  (basic-auth '+AUTH.split(':')[0]+')':'  (PUBLIC)')));

(oldest)  ·  back to Trending Dw  ·  widen data: +Society6/Redbubble/Creative Market/Patternbank 9098c9e →