<!DOCTYPE html>

<html lang="vi">

<head>

<meta charset="UTF-8">

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

<meta name="theme-color" content="#fdf9f3">

<title>DealVerse - Săn deal xịn, tiêu tiền thông minh</title>

<meta name="description" content="DealVerse - voucher mua sắm, đồ ăn, đi lại, xem phim. Review thật từ cộng đồng săn deal, cập nhật mỗi ngày.">

<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ccircle cx='32' cy='32' r='30' fill='%23ffd6e8' stroke='%231e1b2e' stroke-width='3'/%3E%3Cpath d='M20 16 Q15 6 22 4 Q20 11 26 14 Z' fill='%23ffc24b'/%3E%3Cpath d='M44 16 Q49 6 42 4 Q44 11 38 14 Z' fill='%23ffc24b'/%3E%3Cellipse cx='32' cy='32' rx='13' ry='14' fill='%23fff'/%3E%3Ccircle cx='26.5' cy='29' r='2' fill='%231e1b2e'/%3E%3Ccircle cx='37.5' cy='29' r='2' fill='%231e1b2e'/%3E%3Cellipse cx='32' cy='40' rx='6.5' ry='5' fill='%23e3d7ff'/%3E%3Ccircle cx='30' cy='39.5' r='1' fill='%231e1b2e'/%3E%3Ccircle cx='34' cy='39.5' r='1' fill='%231e1b2e'/%3E%3C/svg%3E">

 

<!-- Google Analytics 4 -->

<script async src="https://www.googletagmanager.com/gtag/js?id=G-B8TBEYXJ3G"></script>

<script>

window.dataLayer = window.dataLayer || [];

function gtag(){dataLayer.push(arguments);}

gtag('js', new Date());

gtag('config', 'G-B8TBEYXJ3G');

</script>

 

<style>

:root{

  --bg:#fdf9f3; --card:#ffffff; --ink:#1e1b2e; --muted:#6f6a80; --dim:#a39fb0;

  --line:#e5e0d8; --pink:#ff5fa2; --violet:#8b5cf6; --mint:#c8f4e4; --lilac:#e3d7ff;

  --rose:#ffd6e8; --butter:#fde68a; --sky:#c8e4ff; --star:#f7a400; --red:#ff2e63;

  --grad:linear-gradient(90deg,#ff5fa2,#8b5cf6);

}

*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}

html{scroll-behavior:smooth}

body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--ink)}

button,input{font-family:inherit}

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

.container{max-width:1080px;margin:0 auto;padding:0 20px}

 

/* Header */

header{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.92);backdrop-filter:blur(8px);border-bottom:1.5px solid var(--ink)}

.hd{display:flex;align-items:center;justify-content:space-between;height:60px;gap:10px}

.brand{display:flex;align-items:center;gap:9px;font-size:17px;font-weight:800}

.brand .logo{width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--rose),var(--lilac));border:1.5px solid var(--ink);display:flex;align-items:center;justify-content:center}

nav.menu{display:flex;gap:18px;font-size:13.5px;color:var(--muted);font-weight:600}

nav.menu a:hover{color:var(--ink)}

.hd-btns{display:flex;gap:8px}

.btn{border:1.5px solid var(--ink);border-radius:999px;padding:8px 15px;font-size:12.5px;font-weight:800;cursor:pointer;background:#fff;transition:.12s}

.btn:active{transform:translate(1px,1px)}

.btn.bell{box-shadow:2px 2px 0 var(--rose)}

.btn.join{background:var(--grad);color:#fff;box-shadow:2px 2px 0 var(--ink)}

 

/* Hero */

.hero{background:linear-gradient(115deg,#ffe1ee 0%,#e6d9ff 45%,#cdf5e7 100%);border-bottom:1.5px solid var(--ink);overflow:hidden}

.hero-in{display:flex;align-items:stretch;min-height:280px}

.hero-l{flex:0 0 61.8%;padding:38px 0 30px}

.hero-r{flex:1;position:relative;min-height:220px}

.badge{display:inline-block;background:#fff;border:1.5px solid var(--ink);border-radius:999px;padding:5px 13px;font-size:11px;font-weight:800;box-shadow:2px 2px 0 var(--ink)}

.hero h1{font-size:38px;font-weight:800;line-height:1.2;margin-top:14px;letter-spacing:-.5px}

.hero .sub{font-size:15px;color:#4a4560;margin-top:8px;max-width:430px}

.stats{display:flex;gap:10px;margin-top:20px;flex-wrap:wrap}

.stat{background:#fff;border:1.5px solid var(--ink);border-radius:14px;padding:9px 14px;box-shadow:2px 2px 0 var(--ink)}

.stat b{font-size:17px}

.stat div{font-size:9.5px;color:var(--muted);font-weight:800;letter-spacing:.4px}

.hero-r svg.scene{position:absolute;inset:0;width:100%;height:100%}

 

/* Section shells */

.sect{padding:26px 0 30px}

.sect-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}

.sect-head h2{font-size:20px;font-weight:800}

.band-lilac{background:#f6f0ff;border-top:1.5px solid var(--ink);border-bottom:1.5px solid var(--ink)}

.band-mint{background:#e9fbf2;border-bottom:1.5px solid var(--ink)}

 

/* Tabs */

.tabs{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;padding-bottom:4px;margin-bottom:14px}

.tabs::-webkit-scrollbar{display:none}

.tab{flex:0 0 auto;padding:8px 17px;border-radius:999px;border:1.5px solid var(--line);background:#fff;font-size:13px;font-weight:700;color:var(--muted);cursor:pointer;transition:.15s}

.tab.active{background:var(--ink);color:#fff;border-color:var(--ink)}

 

/* Deal grid */

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

.state{padding:50px 18px;text-align:center;color:var(--muted);font-size:14px;grid-column:1/-1}

.card{background:#fff;border:1.5px solid var(--ink);border-radius:16px;padding:14px;position:relative;box-shadow:3px 3px 0 var(--rose)}

.card:nth-child(3n+2){box-shadow:3px 3px 0 var(--mint)}

.card:nth-child(3n){box-shadow:3px 3px 0 var(--lilac)}

.hotb{position:absolute;top:-10px;right:12px;background:linear-gradient(90deg,#ff5fa2,#ff9d2e);color:#fff;font-size:10px;font-weight:800;padding:3px 11px;border-radius:999px;border:1.5px solid var(--ink)}

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

.chip-p{font-size:11px;font-weight:800;padding:3px 10px;border-radius:99px}

.rating{font-size:11.5px;color:var(--muted);white-space:nowrap}

.rating b{color:var(--ink)}

.star-on{color:var(--star)} .star-off{color:#dcd7cd}

.card h3{font-size:14.5px;font-weight:700;line-height:1.35;margin-top:9px}

.card .desc{font-size:12px;color:var(--muted);margin-top:2px;line-height:1.45}

.meta{display:flex;justify-content:space-between;margin-top:9px;font-size:11px;color:var(--muted)}

.meta b{color:var(--ink)}

.meta .low{color:var(--red);font-weight:700}

.bar{height:6px;background:#f1ece4;border:1px solid var(--line);border-radius:99px;margin-top:6px;overflow:hidden}

.bar i{display:block;height:100%;background:var(--grad);border-radius:99px}

.actions{display:flex;gap:8px;margin-top:11px}

.code-box{flex:1;display:flex;align-items:center;justify-content:space-between;border:1.5px dashed var(--violet);border-radius:10px;padding:8px 11px;background:#f6f2ff;cursor:pointer;user-select:none}

.code-box .code{font-family:ui-monospace,Menlo,monospace;font-weight:800;font-size:12.5px;color:var(--violet);letter-spacing:.5px}

.code-box .cp{font-size:10.5px;font-weight:800;color:var(--violet)}

.btn-go{background:var(--ink);color:#fff;border-radius:10px;padding:9px 15px;font-size:12.5px;font-weight:800;cursor:pointer;border:none;display:inline-flex;align-items:center}

.btn-go.full{flex:1;justify-content:center}

.btn-go:active{transform:scale(.97)}

 

/* Comments */

.cmt-toggle{margin-top:11px;padding-top:9px;border-top:1.5px dashed var(--line);display:flex;justify-content:space-between;align-items:center;cursor:pointer}

.cmt-toggle .lbl{font-size:11.5px;font-weight:800}

.cmt-toggle .act{font-size:10.5px;color:var(--violet);font-weight:700}

.cmt-wrap{display:none;margin-top:8px}

.cmt-wrap.open{display:block}

.cmt-list{max-height:230px;overflow-y:auto;display:flex;flex-direction:column;gap:6px}

.cmt{background:#faf7f0;border-radius:10px;padding:8px 10px}

.cmt .who{font-size:10.5px}

.cmt .who span{color:var(--dim)}

.cmt .txt{font-size:12px;color:#4a4560;margin-top:2px;line-height:1.45;word-break:break-word}

.cmt-form{display:flex;gap:6px;margin-top:8px}

.cmt-form input{border:1.5px solid var(--line);border-radius:99px;padding:8px 12px;font-size:12px;background:#fff;outline:none;min-width:0}

.cmt-form input:focus{border-color:var(--violet)}

.cmt-form .nick{flex:0 0 30%}

.cmt-form .body{flex:1}

.cmt-form button{background:var(--grad);color:#fff;border:none;border-radius:99px;padding:8px 15px;font-size:11.5px;font-weight:800;cursor:pointer;flex:0 0 auto}

.rate-row{display:none;margin-top:9px;align-items:center;justify-content:space-between}

.rate-row.show{display:flex}

.rate-row .q{font-size:11.5px;color:var(--muted)}

.rate-stars{font-size:18px;letter-spacing:2px;cursor:pointer;color:#dcd7cd;user-select:none}

.rate-thanks{font-size:11.5px;color:#009e4f;font-weight:700}

 

/* Tips */

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

.tcard{background:#fff;border:1.5px solid var(--ink);border-radius:16px;padding:13px;box-shadow:3px 3px 0 var(--butter);cursor:pointer;transition:.12s}

.tcard:nth-child(2n){box-shadow:3px 3px 0 var(--sky)}

.tcard:hover{transform:translate(-1px,-1px)}

.tchips{display:flex;gap:6px;flex-wrap:wrap}

.tchip{font-size:10px;font-weight:800;padding:3px 9px;border-radius:99px}

.tchip.save{color:#b47b00;background:#fdf3d7}

.tcard h3{font-size:13.5px;font-weight:700;margin-top:8px;line-height:1.4}

.tcard .sum{font-size:11.5px;color:var(--muted);margin-top:4px;line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

.tfoot{display:flex;justify-content:space-between;align-items:center;margin-top:10px;padding-top:8px;border-top:1.5px dashed var(--line);font-size:10.5px;color:var(--muted)}

.tfoot .more{color:var(--violet);font-weight:800}

 

/* Jobs */

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

.jcard{background:#fff;border:1.5px solid var(--ink);border-radius:16px;padding:15px;box-shadow:3px 3px 0 var(--ink)}

.jcard h3{font-size:14.5px;font-weight:800}

.jcard p{font-size:12px;color:var(--muted);margin-top:4px;line-height:1.5}

.jtags{display:flex;gap:6px;margin-top:9px;flex-wrap:wrap}

.jtag{font-size:10px;font-weight:800;border:1px solid var(--ink);padding:3px 9px;border-radius:99px}

.jcard.creator .jtag{background:#fff0f7}

.jcard.affiliate .jtag{background:#eefff6}

.jcard a{display:block;margin-top:12px;background:var(--ink);color:#fff;text-align:center;border-radius:10px;padding:9px;font-size:12px;font-weight:800}

 

/* Newsletter strip */

.news{background:var(--grad);padding:20px 0}

.news-in{display:flex;align-items:center;gap:14px;flex-wrap:wrap}

.news h3{font-size:15px;font-weight:800;color:#fff}

.news p{font-size:11.5px;color:#ffe3f0}

.news form{flex:1;display:flex;gap:7px;min-width:260px}

.news input{flex:1;background:#fff;border:1.5px solid var(--ink);border-radius:99px;padding:10px 15px;font-size:12.5px;outline:none;min-width:0}

.news button{background:var(--ink);color:#fff;border:1.5px solid var(--ink);border-radius:99px;padding:10px 17px;font-size:12px;font-weight:800;cursor:pointer;flex:0 0 auto}

 

footer.ft{text-align:center;padding:20px;font-size:11.5px;color:var(--dim)}

 

/* Modal */

.overlay{display:none;position:fixed;inset:0;background:rgba(30,27,46,.55);z-index:100;align-items:center;justify-content:center;padding:20px}

.overlay.open{display:flex}

.modal{background:#fff;border:1.5px solid var(--ink);border-radius:18px;box-shadow:4px 4px 0 var(--ink);max-width:560px;width:100%;max-height:85vh;overflow-y:auto;padding:20px}

.modal .close{float:right;font-size:20px;cursor:pointer;color:var(--muted);line-height:1}

.modal h3{font-size:17px;font-weight:800;padding-right:26px}

.modal .body{font-size:13.5px;color:#4a4560;line-height:1.65;margin-top:12px;white-space:pre-line}

.modal .src a{color:var(--violet);font-weight:700;font-size:12px}

.like-btn{display:inline-flex;align-items:center;gap:6px;border:1.5px solid var(--ink);background:#fff;border-radius:99px;padding:7px 15px;font-size:12px;font-weight:800;cursor:pointer;box-shadow:2px 2px 0 var(--butter);margin-top:14px}

.like-btn.liked{background:var(--butter)}

 

#toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%) translateY(90px);background:var(--ink);color:#fff;padding:10px 20px;border-radius:999px;font-size:13px;font-weight:700;transition:.25s;opacity:0;z-index:200;max-width:90vw;text-align:center}

#toast.show{transform:translateX(-50%) translateY(0);opacity:1}

 

/* Mobile */

@media (max-width:760px){

  nav.menu{display:none}

  .hero h1{font-size:26px}

  .hero-in{flex-direction:column;min-height:0}

  .hero-l{flex:1;padding:26px 0 6px}

  .hero-r{min-height:170px}

  .btn{padding:7px 11px;font-size:11px}

}

</style>

</head>

<body>

 

<header>

  <div class="container hd">

    <a class="brand" href="#top">

      <span class="logo">

        <svg viewBox="0 0 64 64" width="22" height="22" aria-hidden="true"><path d="M20 16 Q15 6 22 4 Q20 11 26 14 Z" fill="#f7a400"/><path d="M44 16 Q49 6 42 4 Q44 11 38 14 Z" fill="#f7a400"/><ellipse cx="32" cy="34" rx="15" ry="16" fill="#fff" stroke="#1e1b2e" stroke-width="2.5"/><circle cx="26" cy="30" r="2.2" fill="#1e1b2e"/><circle cx="38" cy="30" r="2.2" fill="#1e1b2e"/><ellipse cx="32" cy="42" rx="7" ry="5.5" fill="#e3d7ff"/><circle cx="29.5" cy="41" r="1.1" fill="#1e1b2e"/><circle cx="34.5" cy="41" r="1.1" fill="#1e1b2e"/></svg>

      </span>

      <span id="siteName">DealVerse</span>

    </a>

    <nav class="menu">

      <a href="#deals">Deal hot</a>

      <a href="#tips">Mẹo chi tiêu</a>

      <a href="#crew">Kiếm thêm</a>

    </nav>

    <div class="hd-btns">

      <button class="btn bell" id="bellBtn">🔔 Nhận deal tuần</button>

      <button class="btn join" id="joinBtn">Gia nhập</button>

    </div>

  </div>

</header>

 

<div class="hero" id="top">

  <div class="container hero-in">

    <div class="hero-l">

      <span class="badge" id="heroBadge">🚀 MỚI CẬP NHẬT</span>

      <h1 id="heroTitle">Săn deal xịn,<br>tiêu tiền thông minh 💸</h1>

      <p class="sub" id="heroSub">Voucher thật, review thật từ cộng đồng săn deal. Cập nhật tự động mỗi ngày, bấm là dùng luôn.</p>

      <div class="stats">

        <div class="stat"><b id="statDeals">--</b><div>DEAL ĐANG CHẠY</div></div>

        <div class="stat"><b id="statClaims">--</b><div>LƯỢT LẤY</div></div>

        <div class="stat"><b id="statRating">--</b><div>ĐÁNH GIÁ TB</div></div>

      </div>

    </div>

    <div class="hero-r">

      <svg class="scene" viewBox="0 0 340 250" preserveAspectRatio="xMidYMid meet" role="img" aria-label="Dê vũ trụ giữa các hành tinh và vé voucher">

        <defs>

          <linearGradient id="pl" x1="0" y1="0" x2="1" y2="1">

            <stop offset="0" stop-color="#ffd166"/><stop offset="1" stop-color="#ff9d2e"/>

          </linearGradient>

        </defs>

        <text x="30" y="34" font-size="13" fill="#8b5cf6" opacity=".8"></text>

        <text x="290" y="26" font-size="10" fill="#ff5fa2" opacity=".8"></text>

        <text x="52" y="200" font-size="10" fill="#1e1b2e" opacity=".5"></text>

        <text x="300" y="215" font-size="12" fill="#8b5cf6" opacity=".7"></text>

        <circle cx="60" cy="70" r="14" fill="#c8e4ff" stroke="#1e1b2e" stroke-width="1.5"/>

        <circle cx="55" cy="66" r="3" fill="#fff" opacity=".8"/>

        <circle cx="285" cy="180" r="10" fill="#e3d7ff" stroke="#1e1b2e" stroke-width="1.5"/>

        <circle cx="170" cy="118" r="58" fill="url(#pl)" stroke="#1e1b2e" stroke-width="1.5"/>

        <ellipse cx="170" cy="122" rx="86" ry="20" fill="none" stroke="#1e1b2e" stroke-width="1.5" opacity=".75" transform="rotate(-14 170 122)"/>

        <g transform="translate(170 100) rotate(6)">

          <circle cx="0" cy="0" r="34" fill="#fff" stroke="#1e1b2e" stroke-width="2"/>

          <path d="M-14 -26 Q-20 -40 -10 -42 Q-13 -33 -6 -29 Z" fill="#f7a400"/>

          <path d="M14 -26 Q20 -40 10 -42 Q13 -33 6 -29 Z" fill="#f7a400"/>

          <ellipse cx="-22" cy="-12" rx="7" ry="4" fill="#fff" stroke="#1e1b2e" stroke-width="1.5" transform="rotate(-30 -22 -12)"/>

          <ellipse cx="22" cy="-12" rx="7" ry="4" fill="#fff" stroke="#1e1b2e" stroke-width="1.5" transform="rotate(30 22 -12)"/>

          <ellipse cx="0" cy="2" rx="19" ry="21" fill="#fff" stroke="#1e1b2e" stroke-width="1.5"/>

          <circle cx="-7" cy="-3" r="2.6" fill="#1e1b2e"/>

          <circle cx="7" cy="-3" r="2.6" fill="#1e1b2e"/>

          <ellipse cx="0" cy="12" rx="9" ry="7" fill="#e3d7ff"/>

          <circle cx="-3" cy="11" r="1.4" fill="#1e1b2e"/>

          <circle cx="3" cy="11" r="1.4" fill="#1e1b2e"/>

          <path d="M-3 19 L0 25 L3 19 Z" fill="#fff" stroke="#1e1b2e" stroke-width="1"/>

        </g>

        <g transform="translate(268 60) rotate(10)">

          <rect x="-34" y="-13" width="68" height="26" rx="7" fill="#fff" stroke="#ff5fa2" stroke-width="1.5" stroke-dasharray="4 3"/>

          <text x="0" y="4.5" text-anchor="middle" font-size="11" font-weight="800" fill="#ff5fa2">-50K 🎟️</text>

        </g>

        <g transform="translate(68 160) rotate(-9)">

          <rect x="-40" y="-13" width="80" height="26" rx="7" fill="#fff" stroke="#8b5cf6" stroke-width="1.5" stroke-dasharray="4 3"/>

          <text x="0" y="4.5" text-anchor="middle" font-size="10.5" font-weight="800" fill="#8b5cf6">FREESHIP 🚚</text>

        </g>

        <g transform="translate(262 222) rotate(6)">

          <rect x="-40" y="-13" width="80" height="26" rx="7" fill="#fff" stroke="#009e4f" stroke-width="1.5" stroke-dasharray="4 3"/>

          <text x="0" y="4.5" text-anchor="middle" font-size="10.5" font-weight="800" fill="#009e4f">HOÀN XU 💰</text>

        </g>

      </svg>

    </div>

  </div>

</div>

 

<section class="sect" id="deals">

  <div class="container">

    <div class="sect-head"><h2>Deal đang hot 🔥</h2></div>

    <div class="tabs" id="tabs"></div>

    <div class="grid" id="dealGrid"><div class="state">Đang tải deal...</div></div>

  </div>

</section>

 

<section class="band-lilac sect" id="tips">

  <div class="container">

    <div class="sect-head"><h2>Mẹo chi tiêu thông minh 💡</h2></div>

    <div class="tgrid" id="tipGrid"><div class="state">Đang tải mẹo hay...</div></div>

  </div>

</section>

 

<section class="band-mint sect" id="crew">

  <div class="container">

    <div class="sect-head"><h2>Gia nhập phi hành đoàn 🐐🚀</h2></div>

    <div class="jgrid" id="jobGrid"><div class="state">Đang tải job...</div></div>

  </div>

</section>

 

<div class="news">

  <div class="container news-in">

    <div>

      <h3 id="newsTitle">🔔 Bản tin deal tuần</h3>

      <p id="newsSub">Mỗi thứ 2, gửi 5 deal ngon nhất tuần</p>

    </div>

    <form id="newsForm">

      <input type="text" id="newsContact" placeholder="Email hoặc số Zalo của bạn..." maxlength="120">

      <button type="submit">Đăng ký nhận</button>

    </form>

  </div>

</div>

 

<footer class="ft" id="footNote">Deal bay nhanh lắm - nhanh tay kẻo lỡ 🐐</footer>

 

<!-- Modal: tip detail -->

<div class="overlay" id="tipOverlay">

  <div class="modal">

    <span class="close" data-close="tipOverlay"></span>

    <div class="tchips" id="tipMChips"></div>

    <h3 id="tipMTitle" style="margin-top:10px"></h3>

    <div class="body" id="tipMBody"></div>

    <div class="src" id="tipMSrc" style="margin-top:10px"></div>

    <button class="like-btn" id="tipLikeBtn">👍 Hữu ích (<span id="tipLikeN">0</span>)</button>

    <div class="cmt-toggle" style="cursor:default"><span class="lbl">💬 Bình luận (<span id="tipCmtN">0</span>)</span></div>

    <div class="cmt-wrap open">

      <div class="cmt-list" id="tipCmtList"></div>

      <div class="cmt-form">

        <input class="nick" id="tipNick" placeholder="Nickname..." maxlength="30">

        <input class="body" id="tipCmtInput" placeholder="Bình luận (bỏ trống tên = Ẩn danh)" maxlength="300">

        <button id="tipCmtSend">Gửi</button>

      </div>

    </div>

  </div>

</div>

 

<!-- Modal: newsletter -->

<div class="overlay" id="bellOverlay">

  <div class="modal" style="max-width:420px">

    <span class="close" data-close="bellOverlay"></span>

    <h3>🔔 Nhận bản tin deal tuần</h3>

    <p style="font-size:13px;color:var(--muted);margin-top:6px">Mỗi thứ 2 nhận 5 deal ngon nhất tuần, không spam, hủy lúc nào cũng được.</p>

    <div class="cmt-form" style="margin-top:14px">

      <input class="body" id="bellContact" placeholder="Email hoặc số Zalo..." maxlength="120">

      <button id="bellSend">Đăng ký</button>

    </div>

  </div>

</div>

 

<div id="toast">Đã copy mã</div>

 

<script>

/* =========================================================

   CẤU HÌNH - chỉ cần sửa 2 dòng dưới

   - SHEET_ID: id Google Sheet

   - SCRIPT_URL: URL Web App của Apps Script (Deploy > Web app)

     Để trống '' thì web vẫn chạy, chỉ tắt gửi comment/đánh giá/đăng ký

========================================================= */

const SHEET_ID = '1DyzadS-R-xdwondrUrrTVfopYM-RS5u9NXXQEEDmdf8';

const SCRIPT_URL = ' https://script.google.com/macros/s/AKfycbzRtpTLMWjCSRi5HjiaBGoxoVaK2MF83tlGoVO42ZHxX0otZvUSZ2lwUjqLNTvZ1SGg/exec';

 

/* Kênh nguồn: link bio dạng ?src=tiktok_kenh1 */

const src = new URLSearchParams(location.search).get('src') || sessionStorage.getItem('src') || 'direct';

sessionStorage.setItem('src', src);

 

const PCOLORS = [

  ['shopeefood',['#ee4d2d','#feeee9']], ['shopee',['#ee4d2d','#feeee9']],

  ['lazada',['#0f156d','#ebecf7']], ['tiktok',['#1e1b2e','#eeeef0']],

  ['tiki',['#1a94ff','#e6f2ff']], ['grab',['#009e4f','#e5f6ec']],

  ['be',['#b58900','#fdf4dc']], ['xanh',['#0a7c5a','#e3f4ec']],

  ['momo',['#a50064','#f9e6f1']], ['galaxy',['#e8590c','#fdeee3']],

  ['cgv',['#e03131','#fdeaea']], ['ngân hàng',['#1b5fa8','#e8f0f9']], ['bank',['#1b5fa8','#e8f0f9']],

];

const TIPCOLORS = { 'ăn uống':['#009e4f','#e5f6ec'], 'mua sắm':['#ee4d2d','#feeee9'], 'tài chính':['#1b5fa8','#e8f0f9'], 'đi lại':['#b58900','#fdf4dc'], 'giải trí':['#a50064','#f9e6f1'] };

 

function pColor(name){

  const n = (name||'').toLowerCase();

  for (const [k,c] of PCOLORS) if (n.includes(k)) return c;

  return ['#5f5e5a','#f1efe8'];

}

function tColor(name){ return TIPCOLORS[(name||'').toLowerCase()] || ['#5f5e5a','#f1efe8']; }

 

function esc(s){

  return (s||'').toString().replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[m]));

}

function fmtNum(n){

  const x = parseFloat(n);

  return isNaN(x) ? (n||'0') : x.toLocaleString('vi-VN');

}

function stars(r){

  let s = '';

  for (let i=1;i<=5;i++) s += '<span class="'+(i<=Math.round(r)?'star-on':'star-off')+'"></span>';

  return s;

}

function buildLink(base, id){

  try{ const u = new URL(base); u.searchParams.set('sub1', src); u.searchParams.set('sub2', id); return u.toString(); }

  catch{ return base; }

}

function track(ev, params){ try{ gtag('event', ev, Object.assign({channel:src}, params||{})); }catch(e){} }

function toast(msg){

  const t = document.getElementById('toast');

  t.textContent = msg; t.classList.add('show');

  setTimeout(() => t.classList.remove('show'), 1800);

}

 

/* ============ ĐỌC SHEET (gviz theo tab) ============ */

async function readTab(name){

  const url = 'https://docs.google.com/spreadsheets/d/'+SHEET_ID+'/gviz/tq?tqx=out:json&headers=1&sheet='+encodeURIComponent(name)+'&t='+Date.now();

  const res = await fetch(url);

  const text = await res.text();

  const json = JSON.parse(text.substring(text.indexOf('(')+1, text.lastIndexOf(')')));

  const cols = json.table.cols.map(c => (c.label||'').trim().toLowerCase());

  return json.table.rows.map(r => {

    const o = {};

    cols.forEach((name2, i) => {

      const c = r.c && r.c[i];

      o[name2] = c ? ((c.f != null ? c.f : (c.v != null ? c.v : '')) + '').trim() : '';

    });

    return o;

  });

}

async function safeTab(name){ try{ return await readTab(name); }catch(e){ return []; } }

 

/* ============ GỬI DỮ LIỆU (Apps Script) ============ */

let lastPost = 0;

function postData(payload){

  if (!SCRIPT_URL){ toast('Tính năng đang bảo trì, thử lại sau nhé'); return false; }

  const now = Date.now();

  if (now - lastPost < 30000){ toast('Từ từ thôi, 30 giây gửi 1 lần nhé'); return false; }

  lastPost = now;

  const body = new URLSearchParams(Object.assign({src:src}, payload));

  fetch(SCRIPT_URL, { method:'POST', mode:'no-cors', body:body });

  return true;

}

function cleanText(s){

  s = (s||'').trim().substring(0,300);

  if (/https?:\/\/|www\./i.test(s)) return null;

  return s;

}

 

/* ============ STATE ============ */

let DEALS = [], TIPS = [], JOBS = [], CFG = {}, COMMENTS = [], RATINGS = [];

let currentTip = null;

 

function ratingFor(loai, id, seedSao, seedN){

  const rows = RATINGS.filter(r => r.loai===loai && r.id===id && parseFloat(r.diem)>0);

  const sSao = parseFloat(seedSao)||0, sN = parseFloat(seedN)||0;

  const sum = rows.reduce((a,r)=>a+parseFloat(r.diem),0);

  const n = sN + rows.length;

  if (!n) return {avg:0, n:0};

  return { avg: Math.round(((sSao*sN + sum)/n)*10)/10, n:n };

}

function likesFor(id, seed){

  return (parseFloat(seed)||0) + RATINGS.filter(r => r.loai==='tip' && r.id===id && r.diem==='like').length;

}

function commentsFor(loai, id){

  return COMMENTS.filter(c => c.loai===loai && c.id===id && c.an==='').reverse();

}

function cmtHTML(c){

  return '<div class="cmt"><div class="who"><b>'+esc(c.nickname||'Ẩn danh')+'</b> <span>· '+esc(c.time||'')+'</span></div><div class="txt">'+esc(c.noi_dung)+'</div></div>';

}

 

/* ============ DEALS ============ */

function renderTabs(){

  const cats = [...new Set(DEALS.map(d => d.nganh).filter(Boolean))];

  const tabs = document.getElementById('tabs');

  tabs.innerHTML = '';

  ['Tất cả', ...cats].forEach((c,i) => {

    const b = document.createElement('button');

    b.className = 'tab'+(i===0?' active':'');

    b.textContent = c;

    b.addEventListener('click', () => {

      document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));

      b.classList.add('active');

      renderDeals(c);

    });

    tabs.appendChild(b);

  });

}

 

function renderDeals(cat){

  const grid = document.getElementById('dealGrid');

  grid.innerHTML = '';

  const items = DEALS.filter(d => cat==='Tất cả' || d.nganh===cat);

  if (!items.length){ grid.innerHTML = '<div class="state">Chưa có deal trong mục này, quay lại sau nhé.</div>'; return; }

  items.forEach(d => {

    const [pc,pbg] = pColor(d.nen_tang);

    const rt = ratingFor('deal', d.id, d.sao, d.luot_danh_gia);

    const cmts = commentsFor('deal', d.id);

    const conLai = parseFloat(d.con_lai_phan_tram)||0;

    const low = conLai>0 && conLai<=20;

    const rated = localStorage.getItem('rated_'+d.id);

    const el = document.createElement('div');

    el.className = 'card';

    el.innerHTML =

      (d.hot!=='' ? '<div class="hotb">HOT 🔥</div>' : '') +

      '<div class="row1"><span class="chip-p" style="color:'+pc+';background:'+pbg+';">'+esc(d.nen_tang)+'</span>' +

      (rt.n ? '<span class="rating">'+stars(rt.avg)+' <b>'+rt.avg+'</b> ('+fmtNum(rt.n)+')</span>' : '') + '</div>' +

      '<h3>'+esc(d.tieu_de)+'</h3>' +

      '<div class="desc">'+esc(d.mo_ta)+(d.hsd?' · HSD '+esc(d.hsd):'')+'</div>' +

      '<div class="meta"><span><b>'+fmtNum(d.luot_lay)+'</b> lượt lấy</span>' +

      (conLai>0 ? '<span class="'+(low?'low':'')+'">'+(low?'Sắp hết, còn ':'Còn ')+conLai+'%</span>' : '') + '</div>' +

      (conLai>0 ? '<div class="bar"><i style="width:'+(100-conLai)+'%"></i></div>' : '') +

      '<div class="actions">' +

        (d.ma

          ? '<div class="code-box act-claim" data-id="'+esc(d.id)+'"><span class="code">'+esc(d.ma)+'</span><span class="cp">COPY</span></div>' +

            '<a class="btn-go act-claim" data-id="'+esc(d.id)+'" href="'+esc(buildLink(d.link,d.id))+'" target="_blank" rel="noopener">Dùng ngay</a>'

          : '<a class="btn-go full act-claim" data-id="'+esc(d.id)+'" href="'+esc(buildLink(d.link,d.id))+'" target="_blank" rel="noopener">Lấy deal</a>') +

      '</div>' +

      '<div class="rate-row'+(rated?' show':'')+'" id="rate-'+esc(d.id)+'">' +

        (rated

          ? '<span class="rate-thanks">Bạn đã đánh giá '+rated+' sao, cảm ơn nhé</span>'

          : '<span class="q">Mã dùng ổn không? Chấm sao nhé</span><span class="rate-stars" data-id="'+esc(d.id)+'"><span data-s="1"></span><span data-s="2"></span><span data-s="3"></span><span data-s="4"></span><span data-s="5"></span></span>') +

      '</div>' +

      '<div class="cmt-toggle" data-id="'+esc(d.id)+'"><span class="lbl">💬 Bình luận ('+cmts.length+')</span><span class="act">Xem</span></div>' +

      '<div class="cmt-wrap" id="cw-'+esc(d.id)+'">' +

        '<div class="cmt-list">'+(cmts.length ? cmts.map(cmtHTML).join('') : '<div class="cmt"><div class="txt">Chưa có bình luận, làm người đầu tiên nhé!</div></div>')+'</div>' +

        '<div class="cmt-form"><input class="nick" placeholder="Nickname..." maxlength="30"><input class="body" placeholder="Bình luận (bỏ trống tên = Ẩn danh)" maxlength="300"><button data-id="'+esc(d.id)+'">Gửi</button></div>' +

      '</div>';

    grid.appendChild(el);

  });

  bindDealEvents(grid);

}

 

function bindDealEvents(grid){

  grid.querySelectorAll('.act-claim').forEach(el => {

    el.addEventListener('click', () => {

      const d = DEALS.find(x => x.id===el.dataset.id);

      if (!d) return;

      if (el.classList.contains('code-box')){

        navigator.clipboard.writeText(d.ma).then(() => toast('Đã copy mã '+d.ma));

      }

      track('claim_voucher', {deal_id:d.id, deal_title:d.tieu_de, platform:d.nen_tang, nganh:d.nganh});

      const rr = document.getElementById('rate-'+d.id);

      if (rr && !localStorage.getItem('rated_'+d.id)) rr.classList.add('show');

    });

  });

  grid.querySelectorAll('.rate-stars span').forEach(st => {

    st.addEventListener('click', e => {

      const wrap = e.target.parentElement, id = wrap.dataset.id, n = parseInt(e.target.dataset.s);

      if (postData({type:'rating', loai:'deal', id:id, diem:n})){

        localStorage.setItem('rated_'+id, n);

        track('rate_voucher', {deal_id:id, stars:n});

        wrap.parentElement.innerHTML = '<span class="rate-thanks">Bạn đã đánh giá '+n+' sao, cảm ơn nhé</span>';

        toast('Cảm ơn bạn đã đánh giá '+n+' sao');

      }

    });

  });

  grid.querySelectorAll('.cmt-toggle').forEach(tg => {

    tg.addEventListener('click', () => {

      const w = document.getElementById('cw-'+tg.dataset.id);

      w.classList.toggle('open');

      tg.querySelector('.act').textContent = w.classList.contains('open') ? 'Thu gọn' : 'Xem';

    });

  });

  grid.querySelectorAll('.cmt-form button').forEach(btn => {

    btn.addEventListener('click', () => {

      const form = btn.parentElement;

      const nick = form.querySelector('.nick').value.trim().substring(0,30) || 'Ẩn danh';

      const body = cleanText(form.querySelector('.body').value);

      if (!body){ toast('Bình luận trống hoặc chứa link, sửa lại nhé'); return; }

      if (postData({type:'comment', loai:'deal', id:btn.dataset.id, nickname:nick, noi_dung:body})){

        const list = form.parentElement.querySelector('.cmt-list');

        list.insertAdjacentHTML('afterbegin', cmtHTML({nickname:nick, time:'vừa xong', noi_dung:body}));

        form.querySelector('.body').value = '';

        track('comment', {loai:'deal', id:btn.dataset.id});

        toast('Đã gửi bình luận');

      }

    });

  });

}

 

/* ============ TIPS ============ */

function renderTips(){

  const grid = document.getElementById('tipGrid');

  grid.innerHTML = '';

  const items = TIPS.filter(t => t.an==='');

  if (!items.length){ grid.innerHTML = '<div class="state">Mẹo hay đang được cập nhật.</div>'; return; }

  items.forEach(t => {

    const [tc,tbg] = tColor(t.danh_muc);

    const likes = likesFor(t.id, t.huu_ich);

    const nc = commentsFor('tip', t.id).length;

    const el = document.createElement('div');

    el.className = 'tcard';

    el.innerHTML =

      '<div class="tchips"><span class="tchip" style="color:'+tc+';background:'+tbg+';">'+esc(t.danh_muc)+'</span>' +

      (t.tiet_kiem ? '<span class="tchip save">Tiết kiệm '+esc(t.tiet_kiem)+'</span>' : '') + '</div>' +

      '<h3>'+esc(t.tieu_de)+'</h3>' +

      '<div class="sum">'+esc(t.tom_tat)+'</div>' +

      '<div class="tfoot"><span>👍 Hữu ích ('+fmtNum(likes)+') · 💬 '+nc+'</span><span class="more">Đọc tiếp →</span></div>';

    el.addEventListener('click', () => openTip(t));

    grid.appendChild(el);

  });

}

 

function openTip(t){

  currentTip = t;

  const [tc,tbg] = tColor(t.danh_muc);

  document.getElementById('tipMChips').innerHTML =

    '<span class="tchip" style="color:'+tc+';background:'+tbg+';">'+esc(t.danh_muc)+'</span>' +

    (t.tiet_kiem ? '<span class="tchip save">Tiết kiệm '+esc(t.tiet_kiem)+'</span>' : '') +

    (t.do_kho ? '<span class="tchip" style="color:#6f6a80;background:#f1efe8;">Độ khó: '+esc(t.do_kho)+'</span>' : '');

  document.getElementById('tipMTitle').textContent = t.tieu_de;

  document.getElementById('tipMBody').textContent = t.noi_dung || t.tom_tat;

  document.getElementById('tipMSrc').innerHTML = t.nguon ? 'Nguồn tham khảo: <a href="'+esc(t.nguon)+'" target="_blank" rel="noopener">'+esc(t.nguon)+'</a>' : '';

  document.getElementById('tipLikeN').textContent = fmtNum(likesFor(t.id, t.huu_ich));

  const likeBtn = document.getElementById('tipLikeBtn');

  likeBtn.classList.toggle('liked', !!localStorage.getItem('liked_'+t.id));

  const cmts = commentsFor('tip', t.id);

  document.getElementById('tipCmtN').textContent = cmts.length;

  document.getElementById('tipCmtList').innerHTML = cmts.length ? cmts.map(cmtHTML).join('') : '<div class="cmt"><div class="txt">Chưa có bình luận, làm người đầu tiên nhé!</div></div>';

  document.getElementById('tipOverlay').classList.add('open');

  track('tip_read', {tip_id:t.id, tip_title:t.tieu_de});

}

 

document.getElementById('tipLikeBtn').addEventListener('click', () => {

  if (!currentTip || localStorage.getItem('liked_'+currentTip.id)) return;

  if (postData({type:'rating', loai:'tip', id:currentTip.id, diem:'like'})){

    localStorage.setItem('liked_'+currentTip.id, '1');

    const n = document.getElementById('tipLikeN');

    n.textContent = fmtNum(parseFloat(n.textContent.replace(/\./g,''))+1);

    document.getElementById('tipLikeBtn').classList.add('liked');

    toast('Cảm ơn bạn!');

  }

});

document.getElementById('tipCmtSend').addEventListener('click', () => {

  if (!currentTip) return;

  const nick = document.getElementById('tipNick').value.trim().substring(0,30) || 'Ẩn danh';

  const body = cleanText(document.getElementById('tipCmtInput').value);

  if (!body){ toast('Bình luận trống hoặc chứa link, sửa lại nhé'); return; }

  if (postData({type:'comment', loai:'tip', id:currentTip.id, nickname:nick, noi_dung:body})){

    document.getElementById('tipCmtList').insertAdjacentHTML('afterbegin', cmtHTML({nickname:nick, time:'vừa xong', noi_dung:body}));

    document.getElementById('tipCmtInput').value = '';

    toast('Đã gửi bình luận');

  }

});

 

/* ============ JOBS ============ */

function renderJobs(){

  const grid = document.getElementById('jobGrid');

  grid.innerHTML = '';

  const items = JOBS.filter(j => j.an==='');

  if (!items.length){ grid.innerHTML = '<div class="state">Job đang được cập nhật.</div>'; return; }

  items.forEach(j => {

    const icon = (j.nhom||'').toLowerCase()==='creator' ? '🎬' : '🔗';

    const el = document.createElement('div');

    el.className = 'jcard '+esc((j.nhom||'').toLowerCase());

    el.innerHTML =

      '<h3>'+icon+' '+esc(j.tieu_de)+'</h3>' +

      '<p>'+esc(j.mo_ta)+'</p>' +

      '<div class="jtags">'+(j.tags||'').split('|').filter(Boolean).map(t => '<span class="jtag">'+esc(t.trim())+'</span>').join('')+'</div>' +

      '<a href="'+esc(j.link_dang_ky||'#')+'" target="_blank" rel="noopener" data-id="'+esc(j.id)+'">Đăng ký ngay</a>';

    el.querySelector('a').addEventListener('click', () => track('job_signup_click', {job_id:j.id, nhom:j.nhom}));

    grid.appendChild(el);

  });

}

 

/* ============ NEWSLETTER + NÚT HEADER ============ */

function subscribe(inputId){

  const v = document.getElementById(inputId).value.trim();

  if (v.length < 5){ toast('Nhập email hoặc số Zalo hợp lệ nhé'); return; }

  if (postData({type:'subscribe', contact:v.substring(0,120)})){

    document.getElementById(inputId).value = '';

    document.getElementById('bellOverlay').classList.remove('open');

    track('subscribe', {});

    toast('Đăng ký thành công, hẹn gặp thứ 2 nhé!');

  }

}

document.getElementById('newsForm').addEventListener('submit', e => { e.preventDefault(); subscribe('newsContact'); });

document.getElementById('bellSend').addEventListener('click', () => subscribe('bellContact'));

document.getElementById('bellBtn').addEventListener('click', () => document.getElementById('bellOverlay').classList.add('open'));

document.getElementById('joinBtn').addEventListener('click', () => {

  if (CFG.join_link){ track('join_click', {}); window.open(CFG.join_link, '_blank'); }

  else document.getElementById('crew').scrollIntoView({behavior:'smooth'});

});

document.querySelectorAll('.overlay .close').forEach(c => c.addEventListener('click', () => document.getElementById(c.dataset.close).classList.remove('open')));

document.querySelectorAll('.overlay').forEach(o => o.addEventListener('click', e => { if (e.target===o) o.classList.remove('open'); }));

 

/* ============ CONFIG ============ */

function applyConfig(){

  const set = (id, key, html) => { if (CFG[key]){ const el = document.getElementById(id); if (html) el.innerHTML = CFG[key]; else el.textContent = CFG[key]; } };

  set('siteName','site_name'); set('heroBadge','badge'); set('heroSub','hero_sub');

  set('newsTitle','newsletter_title'); set('newsSub','newsletter_sub'); set('footNote','footer_note');

  if (CFG.hero_title) document.getElementById('heroTitle').innerHTML = esc(CFG.hero_title).replace(/\n/g,'<br>');

  document.getElementById('statDeals').textContent = CFG.stat_deals || DEALS.length;

  document.getElementById('statClaims').textContent = CFG.stat_claims || fmtNum(DEALS.reduce((a,d)=>a+(parseFloat(d.luot_lay)||0),0));

  if (CFG.stat_rating) document.getElementById('statRating').textContent = CFG.stat_rating;

  else {

    const rs = DEALS.map(d => ratingFor('deal', d.id, d.sao, d.luot_danh_gia)).filter(r => r.n);

    const avg = rs.length ? Math.round(rs.reduce((a,r)=>a+r.avg,0)/rs.length*10)/10 : '--';

    document.getElementById('statRating').textContent = avg + '';

  }

  const d = new Date();

  if (!CFG.badge) document.getElementById('heroBadge').textContent = '🚀 MỚI CẬP NHẬT '+d.getDate()+'/'+(d.getMonth()+1);

}

 

/* ============ KHỞI ĐỘNG ============ */

(async function init(){

  const [vouchers, auto, tips, jobs, config, comments, ratings] = await Promise.all([

    safeTab('vouchers'), safeTab('auto_voucher'), safeTab('tips'),

    safeTab('jobs'), safeTab('config'), safeTab('comments'), safeTab('ratings'),

  ]);

  COMMENTS = comments; RATINGS = ratings;

  const norm = d => Object.assign({hot:'',an:''}, d, {hot:(d.hot||'').trim(), an:(d.an||'').trim()});

  DEALS = [...vouchers, ...auto].map(norm).filter(d => d.id && d.an==='' && d.tieu_de);

  TIPS = tips.map(norm).filter(t => t.id && t.tieu_de);

  JOBS = jobs.map(norm).filter(j => j.id && j.tieu_de);

  config.forEach(r => { if (r.key) CFG[r.key.trim()] = (r.value||'').trim(); });

 

  if (!DEALS.length){

    document.getElementById('dealGrid').innerHTML = '<div class="state">Không tải được deal, thử tải lại trang nhé.</div>';

  } else { renderTabs(); renderDeals('Tất cả'); }

  renderTips();

  renderJobs();

  applyConfig();

})();

</script>

</body>

</html>