<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<title>The Wiser Loonie</title>

<meta name="description" content="Real Canadian deals — Amazon.ca, Walmart, Costco, Canadian Tire, Best Buy, and more — checked directly against retailer prices, refreshed daily.">

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],500;12..96,700;12..96,800&family=Public+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@500;600;700&display=swap">

<style>

  :root{

    --bg: #FFFFFF; --surface: #FFFFFF; --surface-2: #F2F3F0; --border: #E3E6E0;

    --ink: #14213D; --ink-soft: #5B6478; --ink-faint: #8991A3;

    --accent: #FF4B3E; --gold: #FFC93C; --gold-ink: #4A3300;

    --fresh: #1F9D74; --fresh-ink: #FFFFFF;

    --shadow: 0 10px 24px -14px rgba(20,33,61,0.18);

    --font-display: "Bricolage Grotesque", "Arial Black", sans-serif;

    --font-body: "Public Sans", -apple-system, "Segoe UI", sans-serif;

    --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", monospace;

  }

  @media (prefers-color-scheme: dark){

    :root:not([data-theme="light"]){

      --bg: #10141F; --surface: #1A2032; --surface-2: #232A40; --border: #2E3650;

      --ink: #EEF1F8; --ink-soft: #A7AFC6; --ink-faint: #6E7590;

      --accent: #FF6B5C; --gold: #FFD666; --gold-ink: #3A2900;

      --fresh: #3EDCA1; --fresh-ink: #0B2318;

      --shadow: 0 14px 30px -16px rgba(0,0,0,0.55);

    }

  }

  :root[data-theme="dark"]{

    --bg: #10141F; --surface: #1A2032; --surface-2: #232A40; --border: #2E3650;

    --ink: #EEF1F8; --ink-soft: #A7AFC6; --ink-faint: #6E7590;

    --accent: #FF6B5C; --gold: #FFD666; --gold-ink: #3A2900;

    --fresh: #3EDCA1; --fresh-ink: #0B2318;

    --shadow: 0 14px 30px -16px rgba(0,0,0,0.55);

  }


  *{ box-sizing: border-box; }

  html{ scroll-behavior: smooth; }

  body{ margin: 0; background: var(--bg); color: var(--ink); font-family: var(--font-body); -webkit-font-smoothing: antialiased; }

  a{ color: inherit; text-decoration: none; }

  button{ font: inherit; color: inherit; }

  :focus-visible{ outline: 2.5px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

  .page{ max-width: 1180px; margin: 0 auto; padding: 20px 20px 56px; }


  .disclosure-bar{ background: var(--surface-2); color: var(--ink-soft); font-size: 12px; text-align: center; padding: 8px 16px; border-radius: 999px; margin-bottom: 18px; }

  .disclosure-bar a{ font-weight: 700; color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }


  .topbar{ display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }

  .brand{ display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

  .brand-mark{ font-size: 26px; line-height: 1; transform: rotate(-8deg); }

  .brand-name{ font-family: var(--font-display); font-weight: 800; font-size: clamp(21px, 3.6vw, 28px); letter-spacing: -0.02em; }

  .brand-tag{ font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.06em; color: var(--ink-faint); margin-left: 2px; align-self: flex-end; padding-bottom: 5px; }


  .live-status{ display: flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 12.5px; font-weight: 600; color: var(--ink-soft); background: var(--surface); border: 1px solid var(--border); padding: 7px 12px; border-radius: 999px; }

  .live-dot{ width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); animation: pulse 2s ease-out infinite; }

  @keyframes pulse{ 0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent);} 70%{box-shadow:0 0 0 7px color-mix(in srgb, var(--accent) 0%, transparent);} 100%{box-shadow:0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent);} }

  .live-label{ color: var(--accent); letter-spacing: 0.08em; }

  .live-sep{ color: var(--border); }

  .live-count{ font-variant-numeric: tabular-nums; color: var(--ink); }


  .site-nav{ display: flex; flex-wrap: wrap; gap: 18px; margin: 18px 0 6px; }

  .site-nav a{ font-size: 13px; font-weight: 600; color: var(--ink-soft); }

  .site-nav a:hover{ color: var(--accent); }


  .filters{ display: flex; flex-wrap: wrap; gap: 8px; margin: 20px 0 12px; }

  .chip{ background: var(--surface); border: 1px solid var(--border); color: var(--ink-soft); padding: 7px 14px; border-radius: 999px; font-size: 13px; font-weight: 600; cursor: pointer; transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease; }

  .chip:hover{ border-color: var(--accent); color: var(--ink); }

  .chip.is-active{ background: var(--ink); border-color: var(--ink); color: var(--bg); }


  .controls{ display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 22px; padding-bottom: 18px; border-bottom: 1px solid var(--border); }

  .search-wrap{ position: relative; flex: 1 1 220px; max-width: 320px; }

  .search-wrap svg{ position: absolute; left: 11px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; color: var(--ink-faint); pointer-events: none; }

  .search-input{ width: 100%; padding: 8px 12px 8px 33px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); color: var(--ink); font-size: 13px; font-family: var(--font-body); }

  .search-input::placeholder{ color: var(--ink-faint); }

  .sort-group{ display: flex; gap: 6px; }

  .saved-toggle.is-active{ background: var(--accent); border-color: var(--accent); color: #fff; }


  .grid{ display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 16px; }

  .grid.is-empty::after{ content: "No deals match — try a different search or category."; grid-column: 1 / -1; color: var(--ink-faint); font-size: 13.5px; padding: 30px 0; text-align: center; }


  .card{ position: relative; display: flex; flex-direction: column; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; overflow: hidden; transition: transform 0.22s ease, opacity 0.22s ease, box-shadow 0.2s ease, border-color 0.2s ease; transform: scale(1); opacity: 1; }

  .card:hover{ transform: translateY(-3px); border-color: color-mix(in srgb, var(--accent) 35%, var(--border)); box-shadow: var(--shadow); }

  .card.card--leaving{ opacity: 0; transform: scale(0.96); }

  .card.card--entering{ animation: card-in 0.42s ease; }

  @keyframes card-in{ 0%{opacity:0; transform: translateY(6px) scale(0.97);} 100%{opacity:1; transform: translateY(0) scale(1);} }


  .card-visual{ position: relative; aspect-ratio: 1 / 1; background: var(--surface-2); display: flex; align-items: center; justify-content: center; }

  .visual-link{ position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }

  .visual-link svg{ width: 38%; height: 38%; color: var(--ink-faint); }


  .new-badge{ position: absolute; top: 10px; right: 10px; font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; color: var(--fresh-ink); background: var(--fresh); padding: 3px 7px; border-radius: 5px; opacity: 0; transform: translateY(-2px); transition: opacity 0.2s ease, transform 0.2s ease; pointer-events: none; }

  .card.is-new .new-badge{ opacity: 1; transform: translateY(0); }


  .save-btn{ position: absolute; top: 9px; left: 9px; width: 27px; height: 27px; border-radius: 50%; border: none; background: color-mix(in srgb, var(--surface) 80%, transparent); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--ink-soft); padding: 0; }

  .save-btn svg{ width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; }

  .save-btn:hover{ color: var(--accent); }

  .save-btn.is-saved{ color: var(--accent); }

  .save-btn.is-saved svg{ fill: var(--accent); stroke: var(--accent); }


  .reel-pill{ position: absolute; bottom: 10px; left: 10px; background: var(--ink); color: var(--bg); font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; letter-spacing: 0.03em; padding: 4px 8px; border-radius: 999px; }

  .reel-pill:hover{ background: var(--accent); color: #fff; }

  .reel-caption{ margin: 0; font-size: 12.5px; color: var(--ink-soft); }

  .price-note{ font-family: var(--font-mono); font-size: 11.5px; font-weight: 700; color: var(--ink-soft); }


  .card-link{ display: block; }

  .card-body{ display: flex; flex-direction: column; gap: 9px; padding: 14px; }

  .card-top{ display: flex; align-items: center; justify-content: space-between; gap: 8px; }

  .store-badge{ font-family: var(--font-mono); font-size: 11px; font-weight: 700; letter-spacing: 0.03em; padding: 4px 8px; border-radius: 6px; }

  .cat-tag{ font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-faint); }


  .card-title{ margin: 0; font-weight: 700; font-size: 14.5px; line-height: 1.35; color: var(--ink); min-height: 2.7em; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

  .price-row{ display: flex; align-items: baseline; gap: 8px; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

  .price-now{ font-size: 19px; font-weight: 700; color: var(--ink); }

  .price-was{ font-size: 13px; font-weight: 500; color: var(--ink-faint); text-decoration: line-through; }

  .card-foot{ display: flex; align-items: center; justify-content: space-between; padding-top: 10px; border-top: 1px dashed var(--border); }

  .off-badge{ font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--gold-ink); background: var(--gold); padding: 3px 8px; border-radius: 6px; }

  .go-link{ font-size: 12.5px; font-weight: 600; color: var(--ink-soft); display: inline-flex; align-items: center; gap: 4px; transition: color 0.15s ease, gap 0.15s ease; }

  .card:hover .go-link{ color: var(--accent); gap: 6px; }


  .section{ padding: 46px 0 6px; border-top: 1px solid var(--border); margin-top: 40px; }

  .section-head{ margin-bottom: 20px; max-width: 62ch; }

  .section-head h2{ font-family: var(--font-display); font-weight: 800; font-size: clamp(21px, 3vw, 27px); margin: 0 0 8px; letter-spacing: -0.01em; text-wrap: balance; }

  .section-head p{ color: var(--ink-soft); margin: 0; font-size: 14px; }

  .prose{ max-width: 65ch; color: var(--ink-soft); line-height: 1.75; font-size: 14.5px; }

  .prose + .prose{ margin-top: 14px; }

  .prose strong{ color: var(--ink); }

  .placeholder-note{ display: inline-block; margin-top: 14px; font-size: 12px; color: var(--ink-faint); background: var(--surface-2); padding: 6px 10px; border-radius: 8px; }


  .contact-links{ display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }

  .contact-links a{ display: inline-flex; align-items: center; gap: 7px; border: 1px solid var(--border); padding: 9px 15px; border-radius: 999px; font-size: 13px; font-weight: 700; }

  .contact-links a.social-instagram{ background: #E1306C; border-color: #E1306C; color: #fff; }

  .contact-links a.social-tiktok{ background: #010101; border-color: #010101; color: #fff; }

  .contact-links a.social-email{ color: var(--ink); }

  .contact-links a.social-email:hover{ border-color: var(--accent); color: var(--accent); }

  .contact-links a:not(.social-email):hover{ opacity: 0.88; }


  .site-footer{ margin-top: 48px; padding-top: 22px; border-top: 1px solid var(--border); display: flex; flex-wrap: wrap; gap: 14px; align-items: center; justify-content: space-between; color: var(--ink-faint); font-size: 12.5px; }

  .footer-nav{ display: flex; gap: 14px; flex-wrap: wrap; }

  .footer-nav a{ color: var(--ink-soft); font-weight: 600; }

  .footer-nav a:hover{ color: var(--accent); }


  @media (prefers-reduced-motion: reduce){

    html{ scroll-behavior: auto; }

    .live-dot{ animation: none; }

    .card, .card.card--entering, .card.card--leaving, .new-badge{ transition: none !important; animation: none !important; }

  }

</style>

</head>

<body>

<div class="page">

  <div class="disclosure-bar">

    As an Amazon.ca Associate, The Wiser Loonie earns from qualifying purchases (prices shown in CAD).

    <a href="#disclosure">Learn more</a>

  </div>


  <header class="topbar">

    <div class="brand">

      <span class="brand-mark" aria-hidden="true">🏷️</span>

      <span class="brand-name">The Wiser Loonie</span>

      <span class="brand-tag">TODAY'S REAL DEALS</span>

    </div>

    <div class="live-status">

      <span class="live-dot" aria-hidden="true"></span>

      <span class="live-label">LIVE</span>

      <span class="live-sep">·</span>

      <span class="live-count" id="dealCount">8 deals</span>

    </div>

  </header>


  <nav class="site-nav" aria-label="Page sections">

    <a href="#deals">Deals</a>

    <a href="#reels">From Our Reels</a>

    <a href="#about">About</a>

    <a href="#disclosure">Affiliate Disclosure</a>

    <a href="#contact">Contact</a>

  </nav>


  <section id="deals">

    <nav class="filters" id="filters" aria-label="Filter by category"></nav>

    <div class="controls">

      <div class="search-wrap">

        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><circle cx="10.5" cy="10.5" r="6.5"/><line x1="15.5" y1="15.5" x2="21" y2="21"/></svg>

        <input type="search" id="searchInput" class="search-input" placeholder="Search deals…" aria-label="Search deals">

      </div>

      <div class="sort-group" role="group" aria-label="Sort deals">

        <button type="button" class="chip is-active" data-sort="default">Featured</button>

        <button type="button" class="chip" data-sort="discount">Biggest discount</button>

      </div>

      <button type="button" class="chip saved-toggle" id="savedToggle">♡ Saved (0)</button>

    </div>

    <main class="grid" id="dealGrid"></main>

  </section>


  <section id="reels" class="section">

    <div class="section-head">

      <h2>Straight From Our Reels</h2>

      <p>The deals we've actually posted about on social — tap through to watch, or skip straight to the deal.</p>

    </div>

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

    <span class="placeholder-note">Products and links are real (Costco.ca) — add each reel's actual Instagram/TikTok URL to replace the "#" placeholders, and send prices if you'd like them shown.</span>

  </section>


  <section id="about" class="section">

    <div class="section-head"><h2>About The Wiser Loonie</h2></div>

    <p class="prose">

      The Wiser Loonie is a small operation built around one habit: checking Canadian prices

      obsessively so you don't have to. We track markdowns across the retailers Canadians actually

      shop — Amazon.ca, Walmart, Costco, Canadian Tire, Best Buy, and more — and surface only the

      ones worth your loonies (and toonies), not just a big percentage-off headline. Every deal is

      checked directly on the retailer's own page, and Amazon.ca picks are additionally verified

      against real price history before we call them a deal.

    </p>

    <p class="prose">

      We keep it about the deals, not us — no faces, just fast, honest price drops, refreshed daily.

    </p>

    <span class="placeholder-note">Placeholder copy — happy to tighten this further once your reel content and voice are set.</span>

  </section>


  <section id="disclosure" class="section">

    <div class="section-head"><h2>Affiliate Disclosure</h2></div>

    <p class="prose">

      <strong>The Wiser Loonie is reader-supported.</strong> Some links on this site are affiliate

      links — if you click through and make a purchase, we may earn a small commission, at no extra

      cost to you. As an Amazon.ca Associate, we earn from qualifying purchases.

    </p>

    <p class="prose">

      A link being an affiliate link never changes which price, product, or discount we show you —

      we only feature deals we'd genuinely consider buying ourselves. This disclosure follows

      Canadian guidance on affiliate and influencer marketing from the Competition Bureau of Canada

      and Ad Standards Canada, which call for clear disclosure of material connections like affiliate

      commissions.

    </p>

    <span class="placeholder-note">Add each affiliate program by name here as you join it (Amazon.ca Associates, Awin, CJ, etc.) — and have a lawyer confirm this wording before it goes live; I'm not one.</span>

  </section>


  <section id="contact" class="section">

    <div class="section-head">

      <h2>Contact</h2>

      <p>Got a deal to share, a broken link to report, or a partnership inquiry?</p>

    </div>

    <div class="contact-links">

      <a class="social-email" href="mailto:[email protected]">✉ [email protected]</a>

      <a class="social-instagram" href="https://instagram.com/thewiserloonie" target="_blank" rel="noopener noreferrer">Instagram · @thewiserloonie</a>

      <a class="social-tiktok" href="https://tiktok.com/@thewiserloonie" target="_blank" rel="noopener noreferrer">TikTok · @thewiserloonie</a>

    </div>

    <span class="placeholder-note">Confirm your actual Instagram/TikTok handles match "@thewiserloonie" — swap if not.</span>

  </section>


  <footer class="site-footer">

    <nav class="footer-nav" aria-label="Footer">

      <a href="#deals">Deals</a>

      <a href="#reels">Reels</a>

      <a href="#about">About</a>

      <a href="#disclosure">Affiliate Disclosure</a>

      <a href="#contact">Contact</a>

    </nav>

    <p>© 2026 The Wiser Loonie · thewiserloonie.ca</p>

  </footer>

</div>


<script>

(function(){

  "use strict";


  var REFRESH_MS = 10000;

  var VISIBLE_COUNT = 8;

  var NEW_BADGE_MS = 4200;

  var SAVE_KEY = "thewiserloonie_saved_ids";


  /* -----------------------------------------------------------------

     Static fallback pool — real deals/links verified on the retailer's

     own page at the time they were added, shown only if /api/deals

     (the worker) isn't reachable yet, so the page never sits empty.

     Once the worker is live at this domain, loadLiveFeed() below

     replaces this array automatically with the real, refreshed feed.

  ----------------------------------------------------------------- */

  var DEAL_POOL = [

    {id:"rfd1", name:"Stanley Fresh-To-Table Stay Hot Crock, 3 QT / 2.8 L", category:"Kitchen", store:"Stanley Canada", now:73, was:98, source:"RedFlagDeals", url:"https://ca.stanley1913.com/products/the-fresh-to-table-stay-hot-crock-3-qt-2-8-l?variant=53973090664808"},

    {id:"rfd2", name:"Stanley Quencher H2.0 FlowState Tumbler, 30 OZ / 0.89 L", category:"Outdoor", store:"Stanley Canada", now:12, was:29, source:"RedFlagDeals", url:"https://ca.stanley1913.com/products/the-quencher-h2-0-flowstate%E2%84%A2-tumbler-30-oz-0-89-l-last-call?variant=53974864822632"},

    {id:"rfd3", name:"Stanley All Day Slim Bottle, 20 OZ / 0.59 L", category:"Outdoor", store:"Stanley Canada", now:16, was:39, source:"RedFlagDeals", url:"https://ca.stanley1913.com/products/all-day-slim-bottle-20-oz-0-59-l-last-call?variant=53974882189672"},

    {id:"rfd4", name:"Stanley Quencher ProTour Flip Straw Tumbler, 40 OZ / 1.18 L", category:"Outdoor", store:"Stanley Canada", now:26, was:65, source:"RedFlagDeals", url:"https://ca.stanley1913.com/products/the-black-friday-quencher-protour-flip-straw-tumbler-40-oz-1-18-l?variant=53973595980136"},

    {id:"rfd5", name:"Stanley Quencher H2.0 FlowState Tumbler, 30 OZ (Valentine's colourway)", category:"Outdoor", store:"Stanley Canada", now:24, was:59, source:"RedFlagDeals", url:"https://ca.stanley1913.com/products/valentines-day-quencher-h2-0-flowstate-tumbler-30-oz-0-88-l?variant=53973664072040"},


    {id:"rfd6", name:"The Ordinary Glycolic Acid 7% Exfoliating Toner", category:"Beauty", store:"The Ordinary", now:9.54, was:10.60, source:"RedFlagDeals", url:"https://theordinary.com/en-ca/glycolic-acid-7-exfoliating-toner-100418.html"},

    {id:"rfd7", name:"The Ordinary Niacinamide 10% + Zinc 1%", category:"Beauty", store:"The Ordinary", now:5.94, was:6.60, source:"RedFlagDeals", url:"https://theordinary.com/en-ca/niacinamide-10-zinc-1-serum-100436.html"},

    {id:"rfd8", name:"The Ordinary Natural Moisturizing Factors + HA", category:"Beauty", store:"The Ordinary", now:7.83, was:8.70, source:"RedFlagDeals", url:"https://theordinary.com/en-ca/natural-moisturizing-factors-ha-moisturizer-100435.html"},

    {id:"rfd9", name:"The Ordinary Multi-Peptide + HA Serum", category:"Beauty", store:"The Ordinary", now:21.15, was:23.50, source:"RedFlagDeals", url:"https://theordinary.com/en-ca/multi-peptide-ha-serum-100613.html"},

    {id:"rfd10", name:"The Ordinary Caffeine Solution 5% + EGCG Eye Serum", category:"Beauty", store:"The Ordinary", now:10.71, was:11.90, source:"RedFlagDeals", url:"https://theordinary.com/en-ca/caffeine-solution-5-egcg-eye-serum-100412.html"},


    {id:"rfd11", name:"Roots Restore Warm Pocket Legging", category:"Fashion", store:"Roots", now:50, was:98, source:"RedFlagDeals", url:"https://www.roots.com/ca/en/restore-warm-pocket-legging-38080141.html?dwvar_38080141_color=001"},

    {id:"rfd12", name:"Roots Summer Cloud Hoodie", category:"Fashion", store:"Roots", now:60, was:98, source:"RedFlagDeals", url:"https://www.roots.com/ca/en/summer-cloud-hoodie-39040904.html?dwvar_39040904_color=21E"},

    {id:"rfd13", name:"Roots Organic Cooper Slim Full Zip Hoodie", category:"Fashion", store:"Roots", now:80, was:108, source:"RedFlagDeals", url:"https://www.roots.com/ca/en/organic-cooper-slim-full-zip-hoodie-38041146.html?dwvar_38041146_color=O76"},

    {id:"rfd14", name:"Roots Renew Knit Jogger", category:"Fashion", store:"Roots", now:40, was:74, source:"RedFlagDeals", url:"https://www.roots.com/ca/en/renew-knit-jogger-38080133.html?dwvar_38080133_color=001"},

    {id:"rfd15", name:"Roots X Wicked Large Zip Pouch", category:"Fashion", store:"Roots", now:50, was:88, source:"RedFlagDeals", url:"https://www.roots.com/ca/en/roots-x-wicked-large-zip-pouch-56130041.html?dwvar_56130041_color=804"},

    {id:"rfd16", name:"Roots Recover Interlock Jogger", category:"Fashion", store:"Roots", now:60, was:98, source:"RedFlagDeals", url:"https://www.roots.com/ca/en/recover-interlock-jogger-39090379.html?dwvar_39090379_color=21E"}

  ];

  var dealMap = {};

  DEAL_POOL.forEach(function(d){ dealMap[d.id] = d; });


  /* -----------------------------------------------------------------

     Deals featured in your actual reels/videos. Products and URLs

     below are real (Costco.ca). Two things still need your input:

       - reelUrl: the actual Instagram/TikTok post for each, in place

         of the "#" placeholder

       - price/was: add these once you confirm the price you posted —

         Costco.ca doesn't expose price to a page fetch, so none is

         shown here rather than guessing one

  ----------------------------------------------------------------- */

  var REELS_FEATURED = [

    {

      name: "Upseat Ergonomic Baby Floor & Booster Seat",

      store: "Costco Canada",

      category: "Home",

      url: "https://www.costco.ca/p/-/upseat-ergonomic-baby-floor-booster-seat/4201030110?langId=-24",

      platform: "Instagram",

      reelUrl: "#",

      note: "Converts between floor seat, activity chair, and booster seat — built for healthy hip and posture support."

    },

    {

      name: "Uber 2 x $50 e-Gift Cards",

      store: "Costco Canada",

      category: "Home",

      url: "https://www.costco.ca/p/-/uber-2-x-50-e-gift-cards/4000298407?langId=-24",

      platform: "Instagram",

      reelUrl: "#",

      note: "Redeemable for Uber rides and Uber Eats across Canada, delivered by email."

    },

    {

      name: "iSpring 6-Stage Reverse Osmosis Water Filtration System",

      store: "Costco Canada",

      category: "Home",

      url: "https://www.costco.ca/p/-/ispring-6-stage-reverse-osmosis-water-filtration-system/4000372275?langId=-24",

      platform: "Instagram",

      reelUrl: "#",

      note: "NSF/ANSI 58 certified — removes up to 99% of contaminants, including lead and chlorine, under the sink."

    }

  ];


  var CATEGORIES = ["All", "Kitchen", "Outdoor", "Beauty", "Fashion", "Electronics", "Tools", "Toys", "Grocery", "Home"];


  var ICONS = {

    "Electronics": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="12" rx="1.5"/><line x1="8" y1="20" x2="16" y2="20"/><line x1="12" y1="16" x2="12" y2="20"/></svg>',

    "Kitchen": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="13" r="6"/><line x1="16.5" y1="11" x2="20" y2="9.5"/><line x1="8" y1="7" x2="14" y2="7"/></svg>',

    "Fashion": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4.5a2 2 0 1 1 2.2 2c-1.1.1-2.2.9-2.2 2"/><path d="M4 18.5l8-5.5 8 5.5"/><line x1="4" y1="18.5" x2="20" y2="18.5"/></svg>',

    "Tools": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4L4.6 16.4l3 3 4.7-4.7a4 4 0 0 0 5.4-5.4l-2.3 2.3-2.7-2.7z"/></svg>',

    "Outdoor": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 19h18"/><path d="M12 5l7 14H5z"/><line x1="12" y1="11" x2="12" y2="19"/></svg>',

    "Toys": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="4.5" y="12" width="6.5" height="6.5" rx="1.2"/><rect x="13" y="5.5" width="6.5" height="6.5" rx="1.2"/></svg>',

    "Grocery": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 9h15l-1.4 9.2a2 2 0 0 1-2 1.7H7.9a2 2 0 0 1-2-1.7L4.5 9z"/><path d="M8 9V7a4 4 0 0 1 8 0v2"/></svg>',

    "Home": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11l8-6.5 8 6.5"/><rect x="6" y="11" width="12" height="8"/><rect x="10.4" y="14" width="3.2" height="5"/></svg>',

    "Beauty": '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="8" y="9" width="8" height="12" rx="2"/><path d="M10 9V5a2 2 0 0 1 4 0v4"/><line x1="9" y1="13" x2="15" y2="13"/></svg>'

  };

  var HEART_SVG = '<svg viewBox="0 0 24 24"><path d="M12 20.2s-7.2-4.5-9.6-9.1C.7 7.7 2.2 4 5.8 4c2.1 0 3.5 1.2 4.9 3.1C12.1 5.2 13.5 4 15.6 4c3.6 0 5.1 3.7 3.4 7.1-2.4 4.6-9 9.1-9 9.1z"/></svg>';


  // Text-only chips in each retailer's recognizable brand color — no

  // logos or trademarked artwork reproduced.

  var STORE_STYLE = {

    "Amazon.ca":               {bg:"#131A22", fg:"#FF9900"},

    "Walmart Canada":          {bg:"#0071CE", fg:"#FFFFFF"},

    "Costco Canada":           {bg:"#E01A2B", fg:"#FFFFFF"},

    "Best Buy Canada":         {bg:"#FFE000", fg:"#003057"},

    "Newegg.ca":               {bg:"#FF8000", fg:"#141414"},

    "The Bay":                 {bg:"#111111", fg:"#FFFFFF"},

    "Sport Chek":              {bg:"#E4002B", fg:"#FFFFFF"},

    "Mark's":                  {bg:"#E8600B", fg:"#FFFFFF"},

    "Canadian Tire":           {bg:"#D0242A", fg:"#FFFFFF"},

    "Home Depot Canada":       {bg:"#F96302", fg:"#FFFFFF"},

    "MEC":                     {bg:"#2F5D42", fg:"#FFFFFF"},

    "Real Canadian Superstore":{bg:"#008542", fg:"#FFFFFF"},

    "London Drugs":            {bg:"#C8102E", fg:"#FFFFFF"},

    "Stanley Canada":          {bg:"#1C3F33", fg:"#FFFFFF"},

    "The Ordinary":            {bg:"#0F0F0F", fg:"#FFFFFF"},

    "Roots":                   {bg:"#5C3A21", fg:"#FFFFFF"}

  };


  // Real search endpoints on each retailer's own Canadian site (best

  // effort on exact query params for the smaller ones — worth a spot

  // check). Append your affiliate/tracking parameter here once enrolled.

  var STORE_SEARCH = {

    "Amazon.ca":               function(q){ return "https://www.amazon.ca/s?k=" + q; },

    "Walmart Canada":          function(q){ return "https://www.walmart.ca/search?q=" + q; },

    "Costco Canada":           function(q){ return "https://www.costco.ca/CatalogSearch?keyword=" + q; },

    "Best Buy Canada":         function(q){ return "https://www.bestbuy.ca/en-ca/search?search=" + q; },

    "Newegg.ca":               function(q){ return "https://www.newegg.ca/p/pl?d=" + q; },

    "The Bay":                 function(q){ return "https://www.thebay.com/search?q=" + q; },

    "Sport Chek":              function(q){ return "https://www.sportchek.ca/search-results.html?q=" + q; },

    "Mark's":                  function(q){ return "https://www.marks.com/en/search?q=" + q; },

    "Canadian Tire":           function(q){ return "https://www.canadiantire.ca/en/search-results.html?q=" + q; },

    "Home Depot Canada":       function(q){ return "https://www.homedepot.ca/search?q=" + q; },

    "MEC":                     function(q){ return "https://www.mec.ca/en/search?q=" + q; },

    "Real Canadian Superstore":function(q){ return "https://www.realcanadiansuperstore.ca/search?search-bar=" + q; },

    "London Drugs":            function(q){ return "https://www.londondrugs.com/search?q=" + q; }

  };


  function dealUrl(deal){

    if (deal.url) return deal.url; // real link from the live feed

    var build = STORE_SEARCH[deal.store]; var q = encodeURIComponent(deal.name);

    return build ? build(q) : ("https://www.google.com/search?q=" + q);

  }

  function hasPrice(deal){ return typeof deal.now === "number" && typeof deal.was === "number"; }

  function pctOff(deal){ return hasPrice(deal) ? Math.round((deal.was - deal.now) / deal.was * 100) : null; }

  function money(n){ return "$" + n.toFixed(2); }


  /* -----------------------------------------------------------------

     Live feed loading. Tries the worker's /api/deals (see the

     thewiserloonie-worker project) with a short timeout; if it's not

     reachable — e.g. this preview isn't running on thewiserloonie.ca,

     or the worker isn't deployed yet — silently keeps the sample pool

     above so the page never breaks.

  ----------------------------------------------------------------- */

  function loadLiveFeed(){

    var controller = new AbortController();

    var timeout = setTimeout(function(){ controller.abort(); }, 2500);

    return fetch("/api/deals", { signal: controller.signal })

      .then(function(res){ if (!res.ok) throw new Error("bad status"); return res.json(); })

      .then(function(data){

        clearTimeout(timeout);

        if (!data || !Array.isArray(data.deals) || data.deals.length === 0) return null;

        return data.deals.map(function(d){

          var out = {

            id: d.id, name: d.name, category: d.category || "General",

            store: d.store, url: d.url, description: d.description || "",

            source: d.source || null

          };

          // Keepa-sourced deals carry real, price-history-checked now/was

          // figures (see the worker) — pass them through so the card shows

          // an actual discount badge instead of falling back to the

          // description-only layout used for RSS items without prices.

          if (typeof d.now === "number") out.now = d.now;

          if (typeof d.was === "number") out.was = d.was;

          return out;

        });

      })

      .catch(function(){ clearTimeout(timeout); return null; });

  }

  function shuffle(arr){ var a = arr.slice(); for (var i = a.length - 1; i > 0; i--){ var j = Math.floor(Math.random() * (i + 1)); var tmp = a[i]; a[i] = a[j]; a[j] = tmp; } return a; }


  var savedIds = (function(){

    try { var raw = window.localStorage.getItem(SAVE_KEY); return new Set(raw ? JSON.parse(raw) : []); }

    catch (err) { return new Set(); }

  })();

  function persistSaved(){

    try { window.localStorage.setItem(SAVE_KEY, JSON.stringify(Array.from(savedIds))); }

    catch (err) { /* private mode / storage blocked */ }

  }


  var activeCategory = "All";

  var searchQuery = "";

  var sortMode = "default";

  var savedOnly = false;

  var visible = [];

  var hoveredIndex = -1;

  var reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;


  function getFilteredPool(){

    var pool = activeCategory === "All" ? DEAL_POOL : DEAL_POOL.filter(function(d){ return d.category === activeCategory; });

    if (searchQuery){ var q = searchQuery.toLowerCase(); pool = pool.filter(function(d){ return d.name.toLowerCase().indexOf(q) !== -1; }); }

    if (savedOnly){ pool = pool.filter(function(d){ return savedIds.has(d.id); }); }

    return pool;

  }

  function applySort(){

    if (sortMode === "discount"){

      visible = visible.slice().sort(function(a, b){

        var bo = hasPrice(b) ? pctOff(b) : -1, ao = hasPrice(a) ? pctOff(a) : -1;

        return bo - ao;

      });

    }

  }


  var gridEl = document.getElementById("dealGrid");

  var reelGridEl = document.getElementById("reelGrid");

  var filtersEl = document.getElementById("filters");

  var countEl = document.getElementById("dealCount");

  var savedToggleEl = document.getElementById("savedToggle");

  var searchInputEl = document.getElementById("searchInput");


  function cardHTML(deal){

    var style = STORE_STYLE[deal.store] || {bg:"#333333", fg:"#FFFFFF"};

    var icon = ICONS[deal.category] || ICONS["Home"];

    var url = dealUrl(deal);

    var priced = hasPrice(deal);

    var label = deal.name + (priced ? (", " + money(deal.now) + ", " + pctOff(deal) + " percent off") : "") + " at " + deal.store;

    var middle = priced

      ? '<div class="price-row"><span class="price-now">' + money(deal.now) + '</span><span class="price-was">' + money(deal.was) + '</span></div>'

      : (deal.description ? '<p class="reel-caption">' + deal.description + '</p>' : '');

    var foot = priced

      ? '<span class="off-badge">-' + pctOff(deal) + '%</span>'

      : '<span class="price-note">See price at ' + deal.store + '</span>';

    return (

      '<div class="card-visual">' +

        '<a class="visual-link" href="' + url + '" target="_blank" rel="noopener noreferrer" aria-hidden="true" tabindex="-1">' + icon + '</a>' +

        '<button type="button" class="save-btn" data-id="' + deal.id + '" aria-label="Save deal" aria-pressed="false">' + HEART_SVG + '</button>' +

        '<span class="new-badge">New</span>' +

      '</div>' +

      '<a class="card-link" href="' + url + '" target="_blank" rel="noopener noreferrer" aria-label="' + label + '">' +

        '<div class="card-body">' +

          '<div class="card-top"><span class="store-badge" style="background:' + style.bg + ';color:' + style.fg + '">' + deal.store + '</span><span class="cat-tag">' + deal.category + '</span></div>' +

          '<h3 class="card-title">' + deal.name + '</h3>' +

          middle +

          '<div class="card-foot">' + foot + '<span class="go-link">View deal →</span></div>' +

        '</div>' +

      '</a>'

    );

  }


  function makeCardEl(deal, isNew){

    var div = document.createElement("div");

    div.className = "card" + (isNew ? " is-new" : "");

    div.dataset.id = deal.id;

    div.innerHTML = cardHTML(deal);

    var btn = div.querySelector(".save-btn");

    if (savedIds.has(deal.id)){ btn.classList.add("is-saved"); btn.setAttribute("aria-pressed", "true"); }

    return div;

  }


  function reelCardHTML(entry){

    var style = STORE_STYLE[entry.store] || {bg:"#333333", fg:"#FFFFFF"};

    var icon = ICONS[entry.category] || ICONS["Home"];

    return (

      '<div class="card-visual">' +

        '<a class="visual-link" href="' + entry.url + '" target="_blank" rel="noopener noreferrer" aria-hidden="true" tabindex="-1">' + icon + '</a>' +

        '<a class="reel-pill" href="' + entry.reelUrl + '" target="_blank" rel="noopener noreferrer">▶ ' + entry.platform + '</a>' +

      '</div>' +

      '<a class="card-link" href="' + entry.url + '" target="_blank" rel="noopener noreferrer" aria-label="' + entry.name + ' at ' + entry.store + '">' +

        '<div class="card-body">' +

          '<div class="card-top"><span class="store-badge" style="background:' + style.bg + ';color:' + style.fg + '">' + entry.store + '</span><span class="cat-tag">' + entry.category + '</span></div>' +

          '<h3 class="card-title">' + entry.name + '</h3>' +

          '<p class="reel-caption">' + entry.note + '</p>' +

          '<div class="card-foot"><span class="price-note">See price on ' + entry.store + '</span><span class="go-link">View deal →</span></div>' +

        '</div>' +

      '</a>'

    );

  }


  function renderReels(){

    reelGridEl.innerHTML = "";

    REELS_FEATURED.forEach(function(entry){

      var div = document.createElement("div");

      div.className = "card";

      div.innerHTML = reelCardHTML(entry);

      reelGridEl.appendChild(div);

    });

  }


  function renderFilters(){

    filtersEl.innerHTML = "";

    CATEGORIES.forEach(function(cat){

      var btn = document.createElement("button");

      btn.type = "button";

      btn.className = "chip" + (cat === activeCategory ? " is-active" : "");

      btn.textContent = cat;

      btn.addEventListener("click", function(){ setCategory(cat); });

      filtersEl.appendChild(btn);

    });

  }


  function renderGrid(){

    gridEl.innerHTML = "";

    visible.forEach(function(deal){ gridEl.appendChild(makeCardEl(deal, false)); });

    gridEl.classList.toggle("is-empty", visible.length === 0);

    countEl.textContent = visible.length + " deal" + (visible.length === 1 ? "" : "s");

    savedToggleEl.textContent = (savedOnly ? "♥" : "♡") + " Saved (" + savedIds.size + ")";

  }


  function rebuildVisible(){ var pool = shuffle(getFilteredPool()); visible = pool.slice(0, VISIBLE_COUNT); applySort(); renderGrid(); }

  function setCategory(cat){ activeCategory = cat; renderFilters(); rebuildVisible(); }

  function setSortMode(mode){

    sortMode = mode;

    document.querySelectorAll(".sort-group .chip").forEach(function(b){ b.classList.toggle("is-active", b.dataset.sort === mode); });

    applySort(); renderGrid();

  }

  function toggleSaved(id){

    if (savedIds.has(id)) savedIds.delete(id); else savedIds.add(id);

    persistSaved();

    if (savedOnly) { rebuildVisible(); return; }

    var btn = gridEl.querySelector('.save-btn[data-id="' + id + '"]');

    if (btn){ var on = savedIds.has(id); btn.classList.toggle("is-saved", on); btn.setAttribute("aria-pressed", on ? "true" : "false"); }

    savedToggleEl.textContent = (savedOnly ? "♥" : "♡") + " Saved (" + savedIds.size + ")";

  }


  function tick(){

    if (savedOnly || visible.length === 0) return;

    var candidates = [];

    visible.forEach(function(d, i){ if (i !== hoveredIndex) candidates.push(i); });

    if (candidates.length === 0) return;

    var targetIndex = candidates[Math.floor(Math.random() * candidates.length)];

    var currentIds = visible.map(function(d){ return d.id; });

    var pool = getFilteredPool().filter(function(d){ return currentIds.indexOf(d.id) === -1; });

    if (pool.length === 0) return;

    var next = pool[Math.floor(Math.random() * pool.length)];

    var cardEl = gridEl.children[targetIndex];

    if (!cardEl) return;

    var finish = function(){

      visible[targetIndex] = next;

      if (sortMode === "discount"){ applySort(); renderGrid(); return; }

      var fresh = makeCardEl(next, true);

      gridEl.replaceChild(fresh, cardEl);

      if (!reduceMotion) fresh.classList.add("card--entering");

      setTimeout(function(){ fresh.classList.remove("is-new"); }, NEW_BADGE_MS);

    };

    if (reduceMotion){ finish(); } else { cardEl.classList.add("card--leaving"); setTimeout(finish, 220); }

  }


  gridEl.addEventListener("mouseover", function(e){ var card = e.target.closest(".card"); if (card) hoveredIndex = Array.prototype.indexOf.call(gridEl.children, card); });

  gridEl.addEventListener("mouseout", function(e){ if (e.target.closest(".card")) hoveredIndex = -1; });

  gridEl.addEventListener("click", function(e){ var btn = e.target.closest(".save-btn"); if (!btn) return; e.preventDefault(); toggleSaved(btn.dataset.id); });

  searchInputEl.addEventListener("input", function(){ searchQuery = searchInputEl.value.trim(); rebuildVisible(); });

  document.querySelectorAll(".sort-group .chip").forEach(function(btn){ btn.addEventListener("click", function(){ setSortMode(btn.dataset.sort); }); });

  savedToggleEl.addEventListener("click", function(){ savedOnly = !savedOnly; savedToggleEl.classList.toggle("is-active", savedOnly); rebuildVisible(); });


  function start(){

    renderFilters();

    rebuildVisible();

    renderReels();

    setInterval(tick, REFRESH_MS);


    // Swap the sample pool for the live feed if the worker is reachable.

    // Runs after the first paint so the page never sits empty waiting

    // on a network call — see loadLiveFeed() for the fallback behavior.

    loadLiveFeed().then(function(liveDeals){

      if (!liveDeals) return;

      DEAL_POOL = liveDeals;

      var cats = ["All"];

      liveDeals.forEach(function(d){ if (cats.indexOf(d.category) === -1) cats.push(d.category); });

      CATEGORIES = cats;

      var tagEl = document.querySelector(".brand-tag");

      if (tagEl) tagEl.textContent = "LIVE FEED";

      activeCategory = "All"; searchQuery = ""; savedOnly = false;

      if (searchInputEl) searchInputEl.value = "";

      renderFilters();

      rebuildVisible();

    });

  }


  start();

})();

</script>

</body>

</html>