Shop — Promo / Countdown Banner
A self-contained e-commerce urgency kit built with vanilla HTML, CSS, and JavaScript. It pairs a dismissible sticky announcement bar that copies a promo code and remembers being closed, a bold hero sale banner with a live days-hours-minutes-seconds countdown, and a compact flash-deal card whose animated stock meter and add-to-cart button decrement real, working stock. On-palette, accessible, and responsive down to small phones.
MCP
Code
:root {
--bg: #ffffff;
--ink: #16181d;
--muted: #6b7280;
--brand: #3457ff;
--brand-d: #2742d6;
--brand-soft: #eef1ff;
--sale: #e0245e;
--sale-d: #c01a4d;
--ok: #1f9d55;
--warn: #f59e0b;
--line: rgba(16, 18, 29, 0.1);
--ink-grad: linear-gradient(135deg, #1f2440 0%, #2a3a8f 55%, #3457ff 100%);
--radius: 16px;
--shadow-sm: 0 1px 2px rgba(16, 18, 29, 0.06), 0 6px 18px rgba(16, 18, 29, 0.06);
--shadow-md: 0 18px 50px -18px rgba(31, 36, 64, 0.45);
}
* {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
background:
radial-gradient(1100px 480px at 88% -10%, rgba(52, 87, 255, 0.08), transparent 60%),
radial-gradient(900px 420px at -10% 110%, rgba(224, 36, 94, 0.06), transparent 60%),
var(--bg);
color: var(--ink);
font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
}
p {
margin: 0;
}
:focus-visible {
outline: 3px solid rgba(52, 87, 255, 0.55);
outline-offset: 2px;
border-radius: 8px;
}
/* ============ Announcement bar ============ */
.announce {
position: sticky;
top: 0;
z-index: 50;
background: var(--ink-grad);
color: #fff;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06), var(--shadow-sm);
}
.announce.is-hidden {
display: none;
}
.announce__inner {
max-width: 1080px;
margin: 0 auto;
display: flex;
align-items: center;
gap: 10px;
padding: 10px 16px;
}
.announce__spark {
font-size: 14px;
color: #cdd6ff;
animation: spark 2.4s ease-in-out infinite;
}
@keyframes spark {
0%, 100% { transform: scale(1); opacity: 0.85; }
50% { transform: scale(1.35) rotate(20deg); opacity: 1; }
}
.announce__text {
flex: 1;
font-size: 14px;
font-weight: 500;
letter-spacing: 0.01em;
min-width: 0;
}
.announce__text strong {
font-weight: 800;
}
.code-pill {
display: inline-flex;
align-items: center;
gap: 6px;
margin-left: 4px;
padding: 3px 9px;
border: 1px dashed rgba(255, 255, 255, 0.55);
border-radius: 999px;
background: rgba(255, 255, 255, 0.12);
color: #fff;
font: inherit;
font-weight: 800;
font-size: 13px;
letter-spacing: 0.04em;
cursor: pointer;
transition: background 0.15s ease, transform 0.12s ease, border-color 0.15s ease;
}
.code-pill:hover {
background: rgba(255, 255, 255, 0.22);
border-color: #fff;
}
.code-pill:active {
transform: translateY(1px) scale(0.98);
}
.code-pill.is-copied {
background: var(--ok);
border-color: var(--ok);
}
.code-pill__icon {
font-size: 12px;
opacity: 0.85;
}
.announce__close {
flex: none;
display: grid;
place-items: center;
width: 30px;
height: 30px;
border: none;
border-radius: 9px;
background: rgba(255, 255, 255, 0.12);
color: #fff;
cursor: pointer;
transition: background 0.15s ease;
}
.announce__close:hover {
background: rgba(255, 255, 255, 0.26);
}
/* ============ Layout ============ */
.wrap {
max-width: 1080px;
margin: 0 auto;
padding: 40px 20px 64px;
}
.page-head {
margin-bottom: 28px;
}
.page-head__eyebrow {
display: inline-block;
font-size: 12px;
font-weight: 800;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--brand);
background: var(--brand-soft);
padding: 5px 11px;
border-radius: 999px;
}
.page-head__title {
margin: 14px 0 8px;
font-size: clamp(28px, 5vw, 40px);
font-weight: 900;
letter-spacing: -0.025em;
}
.page-head__sub {
max-width: 60ch;
color: var(--muted);
font-size: 15.5px;
}
/* ============ Hero sale banner ============ */
.hero {
position: relative;
display: grid;
grid-template-columns: 230px 1fr;
gap: 12px;
align-items: center;
border-radius: 24px;
background: var(--ink-grad);
color: #fff;
padding: 36px 40px;
overflow: hidden;
box-shadow: var(--shadow-md);
margin-bottom: 26px;
}
.hero__art {
position: relative;
display: grid;
place-items: center;
align-self: stretch;
min-height: 200px;
}
.hero__blob {
position: absolute;
border-radius: 50%;
filter: blur(2px);
}
.hero__blob--1 {
width: 210px;
height: 210px;
background: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0) 70%);
}
.hero__blob--2 {
width: 150px;
height: 150px;
right: 0;
bottom: 6px;
background: radial-gradient(circle at 60% 40%, rgba(224, 36, 94, 0.42), rgba(224, 36, 94, 0) 72%);
}
.hero__bag {
position: relative;
z-index: 1;
filter: drop-shadow(0 18px 26px rgba(0, 0, 0, 0.35));
animation: float 5s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0) rotate(-2deg); }
50% { transform: translateY(-10px) rotate(2deg); }
}
.hero__body {
position: relative;
z-index: 1;
}
.hero__flag {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
font-weight: 800;
letter-spacing: 0.12em;
text-transform: uppercase;
color: #fff;
background: var(--sale);
padding: 5px 11px;
border-radius: 999px;
box-shadow: 0 6px 16px -4px rgba(224, 36, 94, 0.7);
}
.hero__title {
margin: 14px 0 10px;
font-size: clamp(26px, 4.4vw, 38px);
font-weight: 900;
letter-spacing: -0.03em;
line-height: 1.08;
}
.hero__pct {
color: #ffd54a;
text-shadow: 0 2px 12px rgba(255, 213, 74, 0.35);
}
.hero__lede {
max-width: 46ch;
color: rgba(255, 255, 255, 0.82);
font-size: 15px;
}
/* countdown */
.countdown {
display: inline-flex;
align-items: flex-end;
gap: 8px;
margin: 22px 0;
padding: 14px 18px;
border-radius: 16px;
background: rgba(0, 0, 0, 0.22);
border: 1px solid rgba(255, 255, 255, 0.14);
backdrop-filter: blur(4px);
}
.countdown__unit {
display: grid;
justify-items: center;
gap: 4px;
min-width: 54px;
}
.countdown__num {
font-variant-numeric: tabular-nums;
font-size: clamp(26px, 5vw, 34px);
font-weight: 900;
letter-spacing: -0.02em;
line-height: 1;
font-feature-settings: "tnum";
}
.countdown__unit--sec .countdown__num {
color: #ffd54a;
}
.countdown__lbl {
font-size: 10.5px;
font-weight: 700;
letter-spacing: 0.14em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.65);
}
.countdown__sep {
font-size: 26px;
font-weight: 800;
color: rgba(255, 255, 255, 0.4);
padding-bottom: 18px;
animation: blink 1s steps(2, start) infinite;
}
@keyframes blink {
50% { opacity: 0.25; }
}
.countdown.is-pulse {
animation: cdPulse 0.45s ease;
}
@keyframes cdPulse {
0% { transform: scale(1); }
40% { transform: scale(1.015); box-shadow: 0 0 0 4px rgba(255, 213, 74, 0.18); }
100% { transform: scale(1); }
}
.countdown.is-ended {
background: rgba(224, 36, 94, 0.28);
border-color: rgba(224, 36, 94, 0.5);
}
.hero__actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.hero__trust {
display: flex;
flex-wrap: wrap;
gap: 8px 18px;
margin: 22px 0 0;
padding: 0;
list-style: none;
font-size: 13px;
font-weight: 600;
color: rgba(255, 255, 255, 0.85);
}
.hero__trust li {
display: inline-flex;
align-items: center;
gap: 6px;
}
/* ============ Buttons ============ */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
border: none;
border-radius: 12px;
padding: 13px 22px;
font: inherit;
font-weight: 800;
font-size: 15px;
letter-spacing: -0.01em;
cursor: pointer;
text-decoration: none;
transition: transform 0.12s ease, box-shadow 0.18s ease, background 0.18s ease, filter 0.18s ease;
}
.btn:active {
transform: translateY(1px);
}
.btn--brand {
background: var(--brand);
color: #fff;
box-shadow: 0 10px 24px -8px rgba(52, 87, 255, 0.85);
}
.btn--brand:hover {
background: var(--brand-d);
box-shadow: 0 14px 30px -8px rgba(52, 87, 255, 0.95);
}
.btn--ghost {
background: rgba(255, 255, 255, 0.1);
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.28);
}
.btn--ghost:hover {
background: rgba(255, 255, 255, 0.2);
}
.btn--block {
width: 100%;
}
.btn__price {
font-weight: 900;
}
.btn.is-added {
background: var(--ok);
box-shadow: 0 10px 24px -8px rgba(31, 157, 85, 0.8);
}
.btn[disabled] {
cursor: not-allowed;
filter: grayscale(0.35) opacity(0.65);
box-shadow: none;
}
/* ============ Flash deal card ============ */
.deal {
display: grid;
grid-template-columns: 280px 1fr;
gap: 0;
border: 1px solid var(--line);
border-radius: var(--radius);
background: var(--bg);
box-shadow: var(--shadow-sm);
overflow: hidden;
}
.deal__media {
position: relative;
display: grid;
place-items: center;
padding: 20px;
background:
radial-gradient(120px 120px at 70% 20%, rgba(52, 87, 255, 0.16), transparent 70%),
linear-gradient(160deg, #f3f5ff 0%, #e9edff 100%);
border-right: 1px solid var(--line);
}
.deal__badge {
position: absolute;
top: 14px;
left: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 11px;
font-weight: 800;
letter-spacing: 0.1em;
text-transform: uppercase;
color: #fff;
background: var(--sale);
padding: 5px 10px;
border-radius: 999px;
box-shadow: 0 6px 14px -5px rgba(224, 36, 94, 0.7);
}
.deal__shoe {
max-width: 240px;
filter: drop-shadow(0 16px 18px rgba(31, 36, 64, 0.18));
}
.deal__info {
padding: 22px 24px;
display: grid;
align-content: start;
gap: 10px;
}
.deal__rating {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
font-weight: 700;
color: var(--muted);
}
.deal__stars {
color: var(--warn);
letter-spacing: 1px;
}
.deal__name {
margin: 0;
font-size: 22px;
font-weight: 800;
letter-spacing: -0.02em;
}
.deal__prices {
display: flex;
align-items: baseline;
gap: 10px;
flex-wrap: wrap;
}
.deal__price {
font-size: 28px;
font-weight: 900;
letter-spacing: -0.02em;
color: var(--ink);
}
.deal__was {
font-size: 16px;
font-weight: 600;
color: var(--muted);
text-decoration: line-through;
}
.deal__off {
font-size: 13px;
font-weight: 800;
color: var(--sale);
background: rgba(224, 36, 94, 0.1);
padding: 3px 8px;
border-radius: 8px;
}
/* stock meter */
.deal__stock {
margin: 4px 0 2px;
}
.deal__stock-head {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 7px;
font-size: 13px;
}
.deal__stock-label {
font-weight: 800;
color: var(--sale);
}
.deal__stock-left {
color: var(--muted);
font-weight: 600;
}
.deal__stock-left strong {
color: var(--ink);
font-weight: 800;
}
.stockbar {
height: 10px;
border-radius: 999px;
background: rgba(16, 18, 29, 0.08);
overflow: hidden;
}
.stockbar__fill {
display: block;
height: 100%;
width: 0;
border-radius: 999px;
background: linear-gradient(90deg, var(--warn), var(--sale));
box-shadow: 0 0 12px rgba(224, 36, 94, 0.4);
transition: width 1.1s cubic-bezier(0.22, 1, 0.36, 1);
}
.deal__note {
font-size: 13px;
color: var(--muted);
display: flex;
align-items: center;
gap: 6px;
}
/* ============ Restore + toast ============ */
.restore {
position: fixed;
bottom: 18px;
left: 18px;
z-index: 40;
border: 1px solid var(--line);
background: var(--bg);
color: var(--ink);
font: inherit;
font-weight: 700;
font-size: 13px;
padding: 9px 14px;
border-radius: 999px;
box-shadow: var(--shadow-sm);
cursor: pointer;
}
.restore:hover {
border-color: var(--brand);
color: var(--brand);
}
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 18px);
z-index: 80;
display: flex;
align-items: center;
gap: 9px;
max-width: calc(100% - 32px);
padding: 12px 18px;
border-radius: 12px;
background: var(--ink);
color: #fff;
font-size: 14px;
font-weight: 600;
box-shadow: var(--shadow-md);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
}
.toast.is-show {
opacity: 1;
transform: translate(-50%, 0);
}
/* ============ Responsive ============ */
@media (max-width: 760px) {
.hero {
grid-template-columns: 1fr;
padding: 28px 22px;
}
.hero__art {
min-height: 130px;
}
.hero__bag {
width: 130px;
height: 130px;
}
.deal {
grid-template-columns: 1fr;
}
.deal__media {
border-right: none;
border-bottom: 1px solid var(--line);
min-height: 170px;
}
}
@media (max-width: 480px) {
.wrap {
padding: 28px 16px 56px;
}
.announce__text {
font-size: 12.5px;
}
.countdown {
width: 100%;
justify-content: space-between;
padding: 14px;
}
.countdown__unit {
min-width: 0;
}
.countdown__sep {
display: none;
}
.hero__actions .btn {
flex: 1 1 auto;
}
}
@media (prefers-reduced-motion: reduce) {
.hero__bag,
.announce__spark,
.countdown__sep,
.stockbar__fill {
animation: none !important;
transition: none !important;
}
}(function () {
"use strict";
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg, icon) {
if (!toastEl) return;
toastEl.innerHTML =
'<span aria-hidden="true">' + (icon || "✓") + "</span><span></span>";
toastEl.lastChild.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2400);
}
/* ---------- persistence (degrades gracefully) ---------- */
var store = {
get: function (k) {
try {
return window.localStorage.getItem(k);
} catch (e) {
return null;
}
},
set: function (k, v) {
try {
window.localStorage.setItem(k, v);
} catch (e) {}
},
del: function (k) {
try {
window.localStorage.removeItem(k);
} catch (e) {}
},
};
var DISMISS_KEY = "stealthis_promo_announce_dismissed";
/* ---------- announcement bar dismiss / restore ---------- */
var announce = document.getElementById("announce");
var closeBtn = document.getElementById("announceClose");
var restoreBtn = document.getElementById("restoreBar");
function setBar(hidden) {
if (!announce) return;
announce.classList.toggle("is-hidden", hidden);
if (restoreBtn) restoreBtn.hidden = !hidden;
}
if (store.get(DISMISS_KEY) === "1") {
setBar(true);
}
if (closeBtn) {
closeBtn.addEventListener("click", function () {
setBar(true);
store.set(DISMISS_KEY, "1");
toast("Banner hidden — preference saved", "🙈");
if (restoreBtn) restoreBtn.focus();
});
}
if (restoreBtn) {
restoreBtn.addEventListener("click", function () {
setBar(false);
store.del(DISMISS_KEY);
if (closeBtn) closeBtn.focus();
});
}
/* ---------- copy promo code ---------- */
var copyBtn = document.getElementById("copyCode");
var copyResetTimer = null;
if (copyBtn) {
copyBtn.addEventListener("click", function () {
var code = "FREESHIP75";
function done() {
copyBtn.classList.add("is-copied");
var icon = copyBtn.querySelector(".code-pill__icon");
if (icon) icon.textContent = "✓";
toast("Code " + code + " copied to clipboard", "🏷️");
clearTimeout(copyResetTimer);
copyResetTimer = setTimeout(function () {
copyBtn.classList.remove("is-copied");
if (icon) icon.textContent = "⧉";
}, 1800);
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(code).then(done, fallbackCopy);
} else {
fallbackCopy();
}
function fallbackCopy() {
try {
var ta = document.createElement("textarea");
ta.value = code;
ta.setAttribute("readonly", "");
ta.style.position = "absolute";
ta.style.left = "-9999px";
document.body.appendChild(ta);
ta.select();
document.execCommand("copy");
document.body.removeChild(ta);
done();
} catch (e) {
toast("Copy failed — code is FREESHIP75", "⚠️");
}
}
});
}
/* ---------- live countdown ---------- */
var els = {
days: document.getElementById("cdDays"),
hours: document.getElementById("cdHours"),
mins: document.getElementById("cdMins"),
secs: document.getElementById("cdSecs"),
};
var cdWrap = document.getElementById("countdown");
// Target = a fixed-feeling deadline a few days out, recomputed per load.
var DURATION_MS = 2 * 86400000 + 14 * 3600000 + 9 * 60000 + 33 * 1000;
var target = Date.now() + DURATION_MS;
function pad(n) {
return n < 10 ? "0" + n : "" + n;
}
function setNum(el, val) {
if (el && el.textContent !== val) el.textContent = val;
}
var lastSec = -1;
var cdInterval = null;
function renderCountdown() {
var diff = target - Date.now();
if (diff <= 0) {
setNum(els.days, "00");
setNum(els.hours, "00");
setNum(els.mins, "00");
setNum(els.secs, "00");
if (cdWrap) {
cdWrap.classList.add("is-ended");
cdWrap.setAttribute("aria-label", "Sale has ended");
}
if (cdInterval) {
clearInterval(cdInterval);
cdInterval = null;
toast("Time's up — sale prices have ended", "⏰");
}
return;
}
var s = Math.floor(diff / 1000);
var days = Math.floor(s / 86400);
var hours = Math.floor((s % 86400) / 3600);
var mins = Math.floor((s % 3600) / 60);
var secs = s % 60;
setNum(els.days, pad(days));
setNum(els.hours, pad(hours));
setNum(els.mins, pad(mins));
setNum(els.secs, pad(secs));
// subtle pulse once per second
if (cdWrap && secs !== lastSec) {
lastSec = secs;
cdWrap.classList.remove("is-pulse");
// force reflow to restart animation
void cdWrap.offsetWidth;
cdWrap.classList.add("is-pulse");
}
}
renderCountdown();
cdInterval = setInterval(renderCountdown, 1000);
/* ---------- flash-deal stock meter ---------- */
var STOCK_TOTAL = 60;
var stockFill = document.getElementById("stockFill");
var stockLeftEl = document.getElementById("stockLeft");
var stockBar = stockFill ? stockFill.parentElement : null;
var stockLeft = stockLeftEl ? parseInt(stockLeftEl.textContent, 10) || 9 : 9;
function paintStock() {
var pctSold = ((STOCK_TOTAL - stockLeft) / STOCK_TOTAL) * 100;
if (stockFill) stockFill.style.width = pctSold.toFixed(1) + "%";
if (stockLeftEl) stockLeftEl.textContent = stockLeft;
if (stockBar) stockBar.setAttribute("aria-valuenow", String(stockLeft));
}
// animate the bar in after first paint
if (stockFill) {
requestAnimationFrame(function () {
requestAnimationFrame(paintStock);
});
}
/* ---------- add to cart (decrements live stock) ---------- */
var addBtn = document.getElementById("addBtn");
if (addBtn) {
var addResetTimer = null;
addBtn.addEventListener("click", function () {
if (stockLeft <= 0) {
toast("Sorry — this flash deal sold out", "🛑");
return;
}
stockLeft -= 1;
paintStock();
addBtn.classList.add("is-added");
var label = addBtn.firstChild;
if (label) label.textContent = "Added to cart · ";
if (stockLeft <= 0) {
addBtn.disabled = true;
addBtn.innerHTML = "Sold out";
toast("Last pair claimed — sold out!", "🔥");
} else {
toast("Aero Knit Sneaker added · " + stockLeft + " left", "🛒");
clearTimeout(addResetTimer);
addResetTimer = setTimeout(function () {
addBtn.classList.remove("is-added");
if (addBtn.firstChild) addBtn.firstChild.textContent = "Add to cart · ";
}, 1600);
}
});
}
/* ---------- hero "Shop the sale" ---------- */
document.querySelectorAll("[data-shop]").forEach(function (btn) {
btn.addEventListener("click", function () {
toast("Browsing the Mid-Season Sale", "🛍️");
});
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Shop — Promo / Countdown Banner</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- Sticky announcement bar -->
<div class="announce" id="announce" role="region" aria-label="Promotional announcement">
<div class="announce__inner">
<span class="announce__spark" aria-hidden="true">✦</span>
<p class="announce__text">
Free express shipping on orders over <strong>$75</strong> — use code
<button class="code-pill" id="copyCode" type="button" aria-label="Copy promo code FREESHIP75">
<span class="code-pill__label">FREESHIP75</span>
<span class="code-pill__icon" aria-hidden="true">⧉</span>
</button>
</p>
<button class="announce__close" id="announceClose" type="button" aria-label="Dismiss announcement">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
<path d="M6 6l12 12M18 6L6 18" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" />
</svg>
</button>
</div>
</div>
<main class="wrap">
<header class="page-head">
<span class="page-head__eyebrow">Seasonal Event</span>
<h1 class="page-head__title">Promo & Countdown Banner</h1>
<p class="page-head__sub">
A drop-in urgency kit — a dismissible announcement bar, a hero sale banner with a live
countdown, and a compact flash-deal card with an animated stock meter.
</p>
</header>
<!-- Hero sale banner with countdown -->
<section class="hero" aria-labelledby="heroTitle">
<div class="hero__art" aria-hidden="true">
<span class="hero__blob hero__blob--1"></span>
<span class="hero__blob hero__blob--2"></span>
<svg class="hero__bag" viewBox="0 0 120 120" width="180" height="180">
<defs>
<linearGradient id="bagGrad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#fff" stop-opacity=".95" />
<stop offset="1" stop-color="#dbe3ff" stop-opacity=".9" />
</linearGradient>
</defs>
<path d="M28 40h64l-6 64a8 8 0 0 1-8 7H42a8 8 0 0 1-8-7L28 40Z" fill="url(#bagGrad)" />
<path d="M44 40v-6a16 16 0 0 1 32 0v6" fill="none" stroke="#3457ff" stroke-width="6" stroke-linecap="round" />
<text x="60" y="86" text-anchor="middle" font-size="26" font-weight="900" fill="#3457ff" font-family="Inter, sans-serif">%</text>
</svg>
</div>
<div class="hero__body">
<span class="hero__flag">Mid-Season Sale</span>
<h2 class="hero__title" id="heroTitle">
Up to <span class="hero__pct">50% off</span> everything
</h2>
<p class="hero__lede">
Outerwear, footwear, and the best of new-season essentials. Prices drop when the timer
hits zero — then the sale is gone.
</p>
<div class="countdown" id="countdown" role="timer" aria-live="polite" aria-label="Time remaining in sale">
<div class="countdown__unit">
<span class="countdown__num" id="cdDays">00</span>
<span class="countdown__lbl">Days</span>
</div>
<span class="countdown__sep" aria-hidden="true">:</span>
<div class="countdown__unit">
<span class="countdown__num" id="cdHours">00</span>
<span class="countdown__lbl">Hrs</span>
</div>
<span class="countdown__sep" aria-hidden="true">:</span>
<div class="countdown__unit">
<span class="countdown__num" id="cdMins">00</span>
<span class="countdown__lbl">Min</span>
</div>
<span class="countdown__sep" aria-hidden="true">:</span>
<div class="countdown__unit countdown__unit--sec">
<span class="countdown__num" id="cdSecs">00</span>
<span class="countdown__lbl">Sec</span>
</div>
</div>
<div class="hero__actions">
<button class="btn btn--brand" type="button" data-shop>Shop the sale</button>
<a class="btn btn--ghost" href="#deal">See flash deal</a>
</div>
<ul class="hero__trust" aria-label="Shopping perks">
<li><span aria-hidden="true">🔒</span> Secure checkout</li>
<li><span aria-hidden="true">↩</span> 30-day returns</li>
<li><span aria-hidden="true">★</span> 4.8 / 5 · 12,400 reviews</li>
</ul>
</div>
</section>
<!-- Flash deal card -->
<section class="deal" id="deal" aria-labelledby="dealTitle">
<div class="deal__media" aria-hidden="true">
<span class="deal__badge">Flash deal</span>
<svg class="deal__shoe" viewBox="0 0 200 120" width="100%" height="100%" preserveAspectRatio="xMidYMid meet">
<defs>
<linearGradient id="shoeBody" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#ffffff" />
<stop offset="1" stop-color="#e7ecff" />
</linearGradient>
</defs>
<path d="M18 86c10-4 22-6 34-18 8-8 16-22 30-22 6 0 9 5 9 12 0 6 4 9 12 11l60 14c12 3 18 9 18 16v3a6 6 0 0 1-6 6H24a8 8 0 0 1-8-8l2-24Z" fill="url(#shoeBody)" stroke="#cdd6ff" stroke-width="2" />
<path d="M52 64c10 6 22 8 32 6" fill="none" stroke="#3457ff" stroke-width="3" stroke-linecap="round" />
<circle cx="40" cy="100" r="3" fill="#3457ff" />
<circle cx="150" cy="100" r="3" fill="#3457ff" />
<path d="M70 50l10 6m4-14l12 8m4-12l12 8" fill="none" stroke="#9fb0ff" stroke-width="3" stroke-linecap="round" />
</svg>
</div>
<div class="deal__info">
<div class="deal__rating" aria-label="Rated 4.9 out of 5 from 218 reviews">
<span class="deal__stars" aria-hidden="true">★★★★★</span>
<span class="deal__reviews">4.9 · 218 reviews</span>
</div>
<h3 class="deal__name" id="dealTitle">Aero Knit Running Sneaker</h3>
<div class="deal__prices">
<span class="deal__price">$64.00</span>
<span class="deal__was">$128.00</span>
<span class="deal__off">−50%</span>
</div>
<div class="deal__stock">
<div class="deal__stock-head">
<span class="deal__stock-label">Almost gone</span>
<span class="deal__stock-left"><strong id="stockLeft">9</strong> of 60 left</span>
</div>
<div class="stockbar" role="progressbar" aria-valuemin="0" aria-valuemax="60" aria-valuenow="9" aria-label="Stock remaining">
<span class="stockbar__fill" id="stockFill"></span>
</div>
</div>
<button class="btn btn--brand btn--block" type="button" id="addBtn">
Add to cart · <span class="btn__price">$64.00</span>
</button>
<p class="deal__note"><span aria-hidden="true">⚡</span> Selling fast — price returns to $128 after the sale.</p>
</div>
</section>
</main>
<!-- restore announcement helper -->
<button class="restore" id="restoreBar" type="button" hidden>Show announcement bar</button>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Promo / Countdown Banner
A ready-to-drop promotional set for a storefront, tuned for urgency without the tackiness. A sticky announcement bar runs across the top with a free-shipping note and a dashed code pill — click it to copy FREESHIP75 to the clipboard with a confirmation toast. Dismiss the bar and it stays gone via localStorage, with a small “Show announcement bar” button to bring it back.
Below it, a deep ink-to-brand hero banner anchors the sale with a live countdown that ticks every second across days, hours, minutes, and seconds, pulsing gently on each tick and flipping to an “ended” state when it reaches zero. A compact flash-deal card sits underneath: star rating, struck-through original price, percent-off chip, and an animated “almost gone” stock meter. Adding the item to the cart decrements real stock, updates the progress bar, and disables the button once it sells out.
Everything is vanilla — no frameworks, no images, no CDNs beyond the Google Fonts link. Product art is rendered as inline SVG on softly tinted tiles, the layout collapses cleanly to a single column on small screens, controls are keyboard-usable with visible focus rings, and a prefers-reduced-motion query stills the animations.
Illustrative storefront UI only — fictional products, prices, and reviews. No real checkout.