{"product_id":"list-stacking-visualizer","title":"List Stacking Visualizer","description":"\u003cstyle\u003e\n  :root { --ink:#1b2432; --ink-soft:#4a5568; --ink-faint:#8494a7; --paper:#f7f8f6; --card:#fff; --line:#dde3e0; --hot:#c7401e; --chip-bg:#eef1ee; --shadow:0 1px 3px rgba(27,36,50,.08),0 8px 24px rgba(27,36,50,.06); --va:#5b7a99; --vb:#c98a1b; --vc:#2e7d4f; }\n  @media (prefers-color-scheme: dark) { :root { --ink:#e8ecf1; --ink-soft:#a8b4c2; --ink-faint:#6b7a8c; --paper:#141b26; --card:#1c2534; --line:#2c3848; --hot:#e85c36; --chip-bg:#263143; --shadow:0 1px 3px rgba(0,0,0,.4),0 8px 24px rgba(0,0,0,.3); --va:#7fa3c4; --vb:#e0a53f; --vc:#4caf7d; } }\n  #lsv-root { background: var(--paper); color: var(--ink); font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif; line-height: 1.5; }\n  #lsv-root .mono { font-family: ui-monospace, \"SF Mono\", \"Cascadia Mono\", Consolas, Menlo, monospace; font-variant-numeric: tabular-nums; }\n  #lsv-root .wrap { max-width: 1120px; margin: 0 auto; padding: 32px 20px 56px; }\n  #lsv-root header.top { display: flex; flex-direction: column; gap: 8px; padding-bottom: 24px; border-bottom: 2px solid var(--ink); margin-bottom: 24px; }\n  #lsv-root .eyebrow { font-family: ui-monospace, \"SF Mono\", \"Cascadia Mono\", Consolas, Menlo, monospace; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }\n  #lsv-root h1 { margin: 0; font-size: clamp(28px,4.5vw,42px); font-weight: 800; letter-spacing: -.02em; line-height: 1.06; }\n  #lsv-root .sub { margin: 4px 0 0; max-width: 66ch; color: var(--ink-soft); font-size: 15px; }\n  #lsv-root .toolbar { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 22px; }\n  #lsv-root .toolbar button { font: inherit; font-weight: 600; font-size: 13px; padding: 9px 16px; border-radius: 999px; border: 1px solid var(--line); background: var(--card); color: var(--ink-soft); cursor: pointer; }\n  #lsv-root .toolbar button.primary { background: var(--ink); color: var(--paper); border-color: var(--ink); }\n  #lsv-root .lists { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; margin-bottom: 28px; }\n  #lsv-root .listcard { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 16px; box-shadow: var(--shadow); display: flex; flex-direction: column; gap: 8px; }\n  #lsv-root .lc-head { display: flex; align-items: center; gap: 8px; }\n  #lsv-root .lc-dot { width: 11px; height: 11px; border-radius: 50%; flex-shrink: 0; }\n  #lsv-root input.lc-name { font: inherit; font-weight: 700; font-size: 14px; border: none; background: transparent; color: var(--ink); flex: 1; min-width: 0; padding: 2px 0; }\n  #lsv-root input.lc-name:focus { outline: none; border-bottom: 1px solid var(--ink-faint); }\n  #lsv-root .lc-remove { background: none; border: none; color: var(--ink-faint); cursor: pointer; font-size: 16px; padding: 0 4px; }\n  #lsv-root .listcard textarea { width: 100%; min-height: 130px; resize: vertical; font-family: ui-monospace, \"SF Mono\", \"Cascadia Mono\", Consolas, Menlo, monospace; font-size: 12px; border: 1px solid var(--line); border-radius: 8px; padding: 10px; background: var(--paper); color: var(--ink); }\n  #lsv-root .lc-count { font-size: 12px; color: var(--ink-faint); }\n  #lsv-root .lc-count b { color: var(--ink); }\n  #lsv-root .lc-file { font-size: 12px; }\n  #lsv-root .lc-file label { display: inline-block; cursor: pointer; color: var(--hot); font-weight: 600; }\n  #lsv-root .lc-file input { display: none; }\n  #lsv-root .addlist { display: flex; align-items: center; justify-content: center; min-height: 100px; border: 1.5px dashed var(--line); border-radius: 12px; background: transparent; color: var(--ink-faint); font-weight: 600; font-size: 14px; cursor: pointer; width: 100%; }\n  #lsv-root .results { display: grid; grid-template-columns: 340px 1fr; gap: 24px; align-items: start; }\n  #lsv-root .venn-panel { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 20px; box-shadow: var(--shadow); }\n  #lsv-root .venn-panel h2 { margin: 0 0 12px; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); }\n  #lsv-root .venn-svg-wrap { display: flex; justify-content: center; }\n  #lsv-root .venn-legend { display: flex; flex-direction: column; gap: 6px; margin-top: 14px; }\n  #lsv-root .venn-legend .row { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-soft); }\n  #lsv-root .venn-legend .sw { width: 12px; height: 12px; border-radius: 3px; flex-shrink: 0; }\n  #lsv-root .venn-legend b { color: var(--ink); margin-left: auto; }\n  #lsv-root .stack-summary { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 20px; box-shadow: var(--shadow); display: flex; flex-direction: column; gap: 14px; }\n  #lsv-root .ss-top { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }\n  #lsv-root .ss-num { font-family: ui-monospace, \"SF Mono\", \"Cascadia Mono\", Consolas, Menlo, monospace; font-size: 44px; font-weight: 700; color: var(--hot); line-height: 1; }\n  #lsv-root .ss-label { font-size: 14px; color: var(--ink-soft); max-width: 34ch; }\n  #lsv-root .ss-verdict { font-size: 14px; color: var(--ink-soft); border-left: 3px solid var(--hot); padding-left: 12px; }\n  #lsv-root .ss-verdict strong { color: var(--ink); }\n  #lsv-root .ss-btns button { font: inherit; font-weight: 600; font-size: 13px; border-radius: 8px; padding: 9px 14px; cursor: pointer; border: 1px solid var(--line); background: var(--ink); color: var(--paper); }\n  #lsv-root table.stack-table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 13px; }\n  #lsv-root table.stack-table thead th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint); border-bottom: 2px solid var(--line); padding: 8px 10px; }\n  #lsv-root table.stack-table tbody td { padding: 8px 10px; border-bottom: 1px solid var(--line); color: var(--ink-soft); }\n  #lsv-root table.stack-table .addr-cell { color: var(--ink); font-weight: 600; }\n  #lsv-root .list-chip { display: inline-block; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 999px; color: #fff; margin-right: 4px; margin-bottom: 2px; }\n  #lsv-root .table-wrap { max-height: 420px; overflow-y: auto; overflow-x: auto; border: 1px solid var(--line); border-radius: 10px; margin-top: 20px; }\n  #lsv-root .table-empty { padding: 40px 20px; text-align: center; color: var(--ink-faint); font-size: 14px; }\n  #lsv-root footer.brand { margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: baseline; justify-content: space-between; font-size: 13px; color: var(--ink-soft); }\n  #lsv-root footer.brand a { color: var(--hot); text-decoration: none; font-weight: 600; }\n  #lsv-root .disclaimer { margin-top: 10px; font-size: 12px; color: var(--ink-faint); max-width: 74ch; }\n  @media (max-width: 860px) { #lsv-root .results { grid-template-columns: 1fr; } }\n\u003c\/style\u003e\n\n\u003cdiv id=\"lsv-root\"\u003e\u003cdiv class=\"wrap\"\u003e\n  \u003cheader class=\"top\"\u003e\n    \u003cspan class=\"eyebrow\"\u003eFree tool for wholesalers \u0026amp; investors\u003c\/span\u003e\n    \u003ch1\u003eList Stacking Visualizer\u003c\/h1\u003e\n    \u003cp class=\"sub\"\u003ePaste or upload 2–3 lists and see exactly which owners overlap. Records that show up on more than one list are your highest-priority calls — this is what \"stacking\" means, made visible.\u003c\/p\u003e\n  \u003c\/header\u003e\n  \u003cdiv class=\"toolbar\"\u003e\n    \u003cbutton class=\"primary\" id=\"lsv-sampleBtn\" type=\"button\"\u003eLoad sample data\u003c\/button\u003e\n    \u003cbutton id=\"lsv-clearBtn\" type=\"button\"\u003eClear all\u003c\/button\u003e\n  \u003c\/div\u003e\n  \u003cdiv class=\"lists\" id=\"lsv-listsGrid\"\u003e\u003c\/div\u003e\n  \u003cdiv class=\"results\"\u003e\n    \u003cdiv class=\"venn-panel\"\u003e\n      \u003ch2\u003eOverlap map\u003c\/h2\u003e\n      \u003cdiv class=\"venn-svg-wrap\" id=\"lsv-vennSvgWrap\"\u003e\u003c\/div\u003e\n      \u003cdiv class=\"venn-legend\" id=\"lsv-vennLegend\"\u003e\u003c\/div\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"stack-summary\"\u003e\n      \u003cdiv class=\"ss-top\"\u003e\n        \u003cspan class=\"ss-num mono\" id=\"lsv-stackedCount\"\u003e0\u003c\/span\u003e\n        \u003cspan class=\"ss-label\"\u003erecords appear on \u003cb\u003e2 or more\u003c\/b\u003e lists — your stacked, highest-motivation names.\u003c\/span\u003e\n      \u003c\/div\u003e\n      \u003cp class=\"ss-verdict\" id=\"lsv-ssVerdict\"\u003e\u003cstrong\u003ePaste your lists above.\u003c\/strong\u003e Matching is by normalized property address.\u003c\/p\u003e\n      \u003cdiv class=\"ss-btns\"\u003e\u003cbutton id=\"lsv-downloadBtn\" type=\"button\"\u003eDownload stacked list (CSV)\u003c\/button\u003e\u003c\/div\u003e\n      \u003cdiv class=\"table-wrap\"\u003e\n        \u003ctable class=\"stack-table\" id=\"lsv-stackTable\"\u003e\n          \u003cthead\u003e\u003ctr\u003e\n\u003cth\u003eAddress\u003c\/th\u003e\n\u003cth\u003eFound on\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n          \u003ctbody id=\"lsv-stackTbody\"\u003e\u003c\/tbody\u003e\n        \u003c\/table\u003e\n        \u003cdiv class=\"table-empty\" id=\"lsv-tableEmpty\"\u003eNo overlapping records yet.\u003c\/div\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n  \u003cfooter class=\"brand\"\u003e\n    \u003cspan\u003eBuilt free for the investor community by \u003cb\u003eRealSupermarket.com\u003c\/b\u003e \u0026amp; \u003cb\u003eListCentral.US\u003c\/b\u003e\u003c\/span\u003e\n    \u003cspan\u003eWant lists? \u003ca href=\"https:\/\/realsupermarket.com\"\u003eSee our County Data →\u003c\/a\u003e\u003c\/span\u003e\n  \u003c\/footer\u003e\n  \u003cp class=\"disclaimer\"\u003eMatching uses normalized address text only — it does not verify parcel data or geocode. Always sanity-check high-value matches before mailing.\u003c\/p\u003e\n\u003c\/div\u003e\u003c\/div\u003e\n\n\u003cscript\u003e\n(function () {\n  var COLORS = ['va', 'vb', 'vc'];\n  var SAMPLE = [\n    { name: 'Absentee Owners', color: 'va', text: ['412 Maple St, Springfield','88 Pine Ave, Springfield','19 Birchwood Ln, Springfield','501 Cedar Ct, Springfield','77 Elmwood Dr, Springfield','203 Oak Ridge Rd, Springfield','14 Sunset Blvd, Springfield','660 River Rd, Springfield'].join('\\n') },\n    { name: 'Tax Delinquent', color: 'vb', text: ['412 Maple Street, Springfield','19 Birchwood Lane, Springfield','900 Willow Way, Springfield','22 Hilltop Ave, Springfield','77 Elmwood Drive, Springfield','305 Meadow Ct, Springfield'].join('\\n') },\n    { name: 'Pre-Foreclosure', color: 'vc', text: ['412 Maple St., Springfield','77 Elmwood Dr, Springfield','48 Grove St, Springfield','19 Birchwood Ln, Springfield'].join('\\n') }\n  ];\n  var grid = document.getElementById('lsv-listsGrid');\n  var lists = []; var nextId = 1;\n  var SUFFIX_MAP = { STREET:'ST', ST:'ST', AVENUE:'AVE', AVE:'AVE', BOULEVARD:'BLVD', BLVD:'BLVD', DRIVE:'DR', DR:'DR', LANE:'LN', LN:'LN', ROAD:'RD', RD:'RD', COURT:'CT', CT:'CT', CIRCLE:'CIR', CIR:'CIR', PLACE:'PL', PL:'PL', WAY:'WAY', PARKWAY:'PKWY', PKWY:'PKWY', TERRACE:'TER', TER:'TER', TRAIL:'TRL', TRL:'TRL', HIGHWAY:'HWY', HWY:'HWY', NORTH:'N', SOUTH:'S', EAST:'E', WEST:'W' };\n  function normalize(raw) {\n    var s = raw.toUpperCase().trim();\n    s = s.replace(\/[.,#]\/g, ' ');\n    s = s.replace(\/\\s+APT\\s+\\S+$\/,'').replace(\/\\s+UNIT\\s+\\S+$\/,'').replace(\/\\s+STE\\s+\\S+$\/,'');\n    s = s.replace(\/\\s+\/g, ' ').trim();\n    return s.split(' ').map(function (w) { return SUFFIX_MAP[w] || w; }).join(' ');\n  }\n  function parseInput(text) {\n    var lines = text.split('\\n').map(function (l) { return l.trim(); }).filter(Boolean);\n    if (!lines.length) return [];\n    if (lines[0].indexOf(',') !== -1) {\n      var HEADER_LABELS = ['address','property address','site address','mailing address','street address','owner','owner name','name','street','city','state','zip','postal code'];\n      var cells = lines[0].split(',').map(function (h) { return h.trim().toLowerCase().replace(\/\"\/g,''); });\n      var isHeaderRow = cells.some(function (c) { return HEADER_LABELS.indexOf(c) !== -1; });\n      var addrIdx = 0, start = 0;\n      if (isHeaderRow) { var found = cells.findIndex(function (c) { return c.indexOf('address') !== -1; }); addrIdx = found !== -1 ? found : 0; start = 1; }\n      var out = [];\n      for (var i = start; i \u003c lines.length; i++) { var cols = lines[i].split(','); if (cols[addrIdx]) out.push(cols[addrIdx].replace(\/\"\/g,'').trim()); }\n      return out.filter(Boolean);\n    }\n    return lines;\n  }\n  function colorFor(idx) { return COLORS[idx % COLORS.length]; }\n  function addList(name, color, text) {\n    var id = 'list' + (nextId++);\n    var card = document.createElement('div');\n    card.className = 'listcard'; card.dataset.id = id;\n    card.innerHTML = '\u003cdiv class=\"lc-head\"\u003e\u003cspan class=\"lc-dot\" style=\"background:var(--' + color + ')\"\u003e\u003c\/span\u003e\u003cinput class=\"lc-name\" type=\"text\" value=\"' + name.replace(\/\"\/g,'\u0026quot;') + '\" maxlength=\"40\"\u003e\u003cbutton class=\"lc-remove\" type=\"button\" title=\"Remove list\"\u003e✕\u003c\/button\u003e\u003c\/div\u003e' +\n      '\u003cdiv class=\"lc-file\"\u003e\u003clabel\u003eUpload CSV\/TXT \u003cinput type=\"file\" accept=\".csv,.txt\"\u003e\u003c\/label\u003e\u003c\/div\u003e' +\n      '\u003ctextarea placeholder=\"Paste addresses, one per line...\"\u003e' + (text || '') + '\u003c\/textarea\u003e' +\n      '\u003cdiv class=\"lc-count\"\u003e\u003cb class=\"lc-count-num\"\u003e0\u003c\/b\u003e records\u003c\/div\u003e';\n    grid.appendChild(card);\n    var obj = { id: id, color: color, el: card, ta: card.querySelector('textarea'), nameInput: card.querySelector('.lc-name') };\n    lists.push(obj);\n    card.querySelector('textarea').addEventListener('input', compute);\n    card.querySelector('.lc-name').addEventListener('input', compute);\n    card.querySelector('.lc-remove').addEventListener('click', function () { lists = lists.filter(function (l) { return l.id !== id; }); card.remove(); renderAddButton(); compute(); });\n    card.querySelector('.lc-file input').addEventListener('change', function (e) {\n      var file = e.target.files[0]; if (!file) return;\n      var reader = new FileReader();\n      reader.onload = function () { obj.ta.value = reader.result; compute(); };\n      reader.readAsText(file);\n    });\n    return obj;\n  }\n  var addBtn = null;\n  function renderAddButton() {\n    if (addBtn) addBtn.remove();\n    if (lists.length \u003e= 3) { addBtn = null; return; }\n    addBtn = document.createElement('button');\n    addBtn.type = 'button'; addBtn.className = 'addlist';\n    addBtn.textContent = '+ Add another list' + (lists.length === 0 ? ' (up to 3)' : '');\n    addBtn.addEventListener('click', function () { addList('List ' + String.fromCharCode(65 + lists.length), colorFor(lists.length), ''); renderAddButton(); compute(); });\n    grid.appendChild(addBtn);\n  }\n  function computeSets() {\n    return lists.map(function (l) {\n      var raw = parseInput(l.ta.value); var norm = {};\n      raw.forEach(function (r) { norm[normalize(r)] = r; });\n      l.countEl = l.el.querySelector('.lc-count-num'); l.countEl.textContent = Object.keys(norm).length;\n      return { list: l, norm: norm };\n    });\n  }\n  function compute() {\n    var sets = computeSets();\n    var active = sets.filter(function (s) { return Object.keys(s.norm).length \u003e 0; });\n    var membership = {};\n    sets.forEach(function (s, idx) { Object.keys(s.norm).forEach(function (key) { if (!membership[key]) membership[key] = { display: s.norm[key], lists: [] }; membership[key].lists.push(idx); }); });\n    var stacked = Object.keys(membership).filter(function (k) { return membership[k].lists.length \u003e= 2; });\n    document.getElementById('lsv-stackedCount').textContent = stacked.length;\n    renderVenn(sets, membership); renderVerdict(active.length, stacked.length, sets); renderTable(stacked, membership, sets);\n  }\n  function renderVerdict(activeCount, stackedCount, sets) {\n    var el = document.getElementById('lsv-ssVerdict');\n    if (activeCount \u003c 2) { el.innerHTML = '\u003cstrong\u003eAdd a second list.\u003c\/strong\u003e Stacking needs at least 2 lists to find overlap — paste addresses or load sample data above.'; return; }\n    var totalUnique = Object.keys(sets.reduce(function (acc, s) { Object.keys(s.norm).forEach(function (k) { acc[k] = 1; }); return acc; }, {})).length;\n    var pct = totalUnique \u003e 0 ? Math.round((stackedCount \/ totalUnique) * 100) : 0;\n    if (stackedCount === 0) { el.innerHTML = '\u003cstrong\u003eNo overlap found.\u003c\/strong\u003e These lists don’t share any addresses — try lists targeting a similar area, or check for formatting differences.'; }\n    else { el.innerHTML = '\u003cstrong\u003e' + stackedCount + ' stacked record' + (stackedCount === 1 ? '' : 's') + '\u003c\/strong\u003e (' + pct + '% of ' + totalUnique + ' unique addresses). These owners are flagged by more than one distress signal — call them first, mail them hardest.'; }\n  }\n  function renderTable(stacked, membership, sets) {\n    var tbody = document.getElementById('lsv-stackTbody'); var empty = document.getElementById('lsv-tableEmpty'); var table = document.getElementById('lsv-stackTable');\n    tbody.innerHTML = '';\n    if (!stacked.length) { table.style.display = 'none'; empty.style.display = 'block'; return; }\n    table.style.display = 'table'; empty.style.display = 'none';\n    stacked.sort(function (a, b) { return membership[b].lists.length - membership[a].lists.length; });\n    stacked.forEach(function (key) {\n      var m = membership[key]; var tr = document.createElement('tr');\n      var chips = m.lists.map(function (idx) { var l = sets[idx].list; return '\u003cspan class=\"list-chip\" style=\"background:var(--' + l.color + ')\"\u003e' + l.nameInput.value + '\u003c\/span\u003e'; }).join('');\n      tr.innerHTML = '\u003ctd class=\"addr-cell\"\u003e' + m.display.replace(\/\u003c\/g,'\u0026lt;') + '\u003c\/td\u003e\u003ctd\u003e' + chips + '\u003c\/td\u003e';\n      tbody.appendChild(tr);\n    });\n  }\n  function renderVenn(sets, membership) {\n    var wrap = document.getElementById('lsv-vennSvgWrap'); var legend = document.getElementById('lsv-vennLegend');\n    legend.innerHTML = sets.map(function (s) { return '\u003cdiv class=\"row\"\u003e\u003cspan class=\"sw\" style=\"background:var(--' + s.list.color + ')\"\u003e\u003c\/span\u003e' + s.list.nameInput.value + '\u003cb class=\"mono\"\u003e' + Object.keys(s.norm).length + '\u003c\/b\u003e\u003c\/div\u003e'; }).join('');\n    if (sets.length \u003c 2) { wrap.innerHTML = '\u003csvg width=\"280\" height=\"200\"\u003e\u003c\/svg\u003e'; return; }\n    function countRegion(idxIn, idxOut) {\n      var n = 0;\n      Object.keys(membership).forEach(function (k) {\n        var ls = membership[k].lists;\n        var hasAll = idxIn.every(function (i) { return ls.indexOf(i) !== -1; });\n        var hasNone = idxOut.every(function (i) { return ls.indexOf(i) === -1; });\n        if (hasAll \u0026\u0026 hasNone) n++;\n      });\n      return n;\n    }\n    var cssVar = function (name) { return getComputedStyle(document.documentElement).getPropertyValue('--' + name).trim(); };\n    if (sets.length === 2) {\n      var a = countRegion([0],[1]), b = countRegion([1],[0]), ab = countRegion([0,1],[]);\n      wrap.innerHTML = '\u003csvg width=\"320\" height=\"220\" viewBox=\"0 0 340 220\"\u003e\u003ccircle cx=\"130\" cy=\"110\" r=\"85\" fill=\"' + cssVar(sets[0].list.color) + '\" opacity=\"0.55\"\/\u003e\u003ccircle cx=\"210\" cy=\"110\" r=\"85\" fill=\"' + cssVar(sets[1].list.color) + '\" opacity=\"0.55\"\/\u003e\u003ctext x=\"90\" y=\"115\" text-anchor=\"middle\" font-size=\"22\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + a + '\u003c\/text\u003e\u003ctext x=\"250\" y=\"115\" text-anchor=\"middle\" font-size=\"22\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + b + '\u003c\/text\u003e\u003ctext x=\"170\" y=\"115\" text-anchor=\"middle\" font-size=\"24\" font-weight=\"800\" fill=\"var(--ink)\"\u003e' + ab + '\u003c\/text\u003e\u003c\/svg\u003e';\n    } else {\n      var A = countRegion([0],[1,2]), B = countRegion([1],[0,2]), C = countRegion([2],[0,1]);\n      var AB = countRegion([0,1],[2]), AC = countRegion([0,2],[1]), BC = countRegion([1,2],[0]);\n      var ABC = countRegion([0,1,2],[]);\n      wrap.innerHTML = '\u003csvg width=\"300\" height=\"260\" viewBox=\"0 0 320 260\"\u003e\u003ccircle cx=\"140\" cy=\"100\" r=\"78\" fill=\"' + cssVar(sets[0].list.color) + '\" opacity=\"0.5\"\/\u003e\u003ccircle cx=\"200\" cy=\"100\" r=\"78\" fill=\"' + cssVar(sets[1].list.color) + '\" opacity=\"0.5\"\/\u003e\u003ccircle cx=\"170\" cy=\"160\" r=\"78\" fill=\"' + cssVar(sets[2].list.color) + '\" opacity=\"0.5\"\/\u003e\u003ctext x=\"100\" y=\"80\" text-anchor=\"middle\" font-size=\"18\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + A + '\u003c\/text\u003e\u003ctext x=\"240\" y=\"80\" text-anchor=\"middle\" font-size=\"18\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + B + '\u003c\/text\u003e\u003ctext x=\"170\" y=\"215\" text-anchor=\"middle\" font-size=\"18\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + C + '\u003c\/text\u003e\u003ctext x=\"170\" y=\"95\" text-anchor=\"middle\" font-size=\"15\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + AB + '\u003c\/text\u003e\u003ctext x=\"125\" y=\"150\" text-anchor=\"middle\" font-size=\"15\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + AC + '\u003c\/text\u003e\u003ctext x=\"215\" y=\"150\" text-anchor=\"middle\" font-size=\"15\" font-weight=\"700\" fill=\"var(--ink)\"\u003e' + BC + '\u003c\/text\u003e\u003ctext x=\"170\" y=\"130\" text-anchor=\"middle\" font-size=\"20\" font-weight=\"800\" fill=\"var(--ink)\"\u003e' + ABC + '\u003c\/text\u003e\u003c\/svg\u003e';\n    }\n  }\n  document.getElementById('lsv-sampleBtn').addEventListener('click', function () {\n    lists.slice().forEach(function (l) { l.el.remove(); }); lists = [];\n    SAMPLE.forEach(function (s) { addList(s.name, s.color, s.text); });\n    renderAddButton(); compute();\n  });\n  document.getElementById('lsv-clearBtn').addEventListener('click', function () {\n    lists.slice().forEach(function (l) { l.el.remove(); }); lists = [];\n    addList('List A', 'va', ''); addList('List B', 'vb', '');\n    renderAddButton(); compute();\n  });\n  document.getElementById('lsv-downloadBtn').addEventListener('click', function () {\n    var sets = computeSets(); var membership = {};\n    sets.forEach(function (s, idx) { Object.keys(s.norm).forEach(function (key) { if (!membership[key]) membership[key] = { display: s.norm[key], lists: [] }; membership[key].lists.push(idx); }); });\n    var stacked = Object.keys(membership).filter(function (k) { return membership[k].lists.length \u003e= 2; });\n    if (!stacked.length) { alert('No stacked records to export yet.'); return; }\n    var rows = [['Address','Found On','List Count']];\n    stacked.forEach(function (key) { var m = membership[key]; var names = m.lists.map(function (idx) { return sets[idx].list.nameInput.value; }).join(' | '); rows.push([m.display, names, m.lists.length]); });\n    var csv = rows.map(function (r) { return r.map(function (c) { return '\"' + String(c).replace(\/\"\/g,'\"\"') + '\"'; }).join(','); }).join('\\n');\n    var blob = new Blob([csv], { type: 'text\/csv' }); var url = URL.createObjectURL(blob);\n    var a = document.createElement('a'); a.href = url; a.download = 'stacked-list.csv';\n    document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url);\n  });\n  addList('List A', 'va', ''); addList('List B', 'vb', ''); renderAddButton(); compute();\n})();\n\u003c\/script\u003e","brand":"ListCentral.US","offers":[{"title":"Default","offer_id":50174970790128,"sku":"TOOL-LIST-STACK","price":0.0,"currency_code":"USD","in_stock":false}],"url":"https:\/\/listcentral.us\/products\/list-stacking-visualizer","provider":"ListCentral.US","version":"1.0","type":"link"}