Ticketing — Concert Landing
A loud, electric concert ticketing landing page for a fictional stadium tour, built with vanilla HTML, CSS, and JavaScript. Features a full-bleed neon hero with a live countdown to opening night, a filterable tour-dates list with availability badges, a three-act lineup, perforated ticket-tier cards with a sticky cart, a stylized venue map, a hype gallery, an accordion FAQ, mobile navigation, toast feedback, and scroll-reveal animations on a black plus magenta palette.
MCP
Code
:root {
/* Concert palette — black + neon magenta + violet */
--brand: #ff2d78;
--brand-d: #d61f63;
--violet: #8b3dff;
--violet-d: #6d28d9;
--ink: #f4f1f8;
--ink-2: #c9c3da;
--muted: #8b86a0;
--bg: #07060c;
--bg-2: #0d0b15;
--surface: #14111f;
--surface-2: #1c1830;
--line: rgba(255, 255, 255, 0.1);
--line-2: rgba(255, 45, 120, 0.35);
--ok: #2dd4a0;
--warn: #ffb020;
--danger: #ff4d6d;
--accent: #ff2d78;
--tier-ga: #38bdf8;
--tier-low: #a78bfa;
--tier-pit: #ff2d78;
--tier-vip: #ffd166;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--r-xl: 28px;
--shadow: 0 18px 50px rgba(0, 0, 0, 0.55);
--shadow-neon: 0 0 0 1px rgba(255, 45, 120, 0.4), 0 16px 44px rgba(255, 45, 120, 0.28);
--maxw: 1180px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
h1, h2, h3, h4 { margin: 0; line-height: 1.08; letter-spacing: -0.02em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
ul { margin: 0; padding: 0; list-style: none; }
img, figure { display: block; }
.skip-link {
position: absolute; left: 12px; top: -60px;
background: var(--brand); color: #fff; padding: 10px 16px;
border-radius: var(--r-sm); z-index: 200; font-weight: 700;
transition: top .2s;
}
.skip-link:focus { top: 12px; }
:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }
/* ---------- Buttons ---------- */
.btn {
--pad: 12px 22px;
display: inline-flex; align-items: center; justify-content: center;
gap: 8px; padding: var(--pad);
font-family: inherit; font-weight: 700; font-size: .95rem;
border: 1px solid transparent; border-radius: 999px;
cursor: pointer; transition: transform .15s, box-shadow .2s, background .2s, border-color .2s;
white-space: nowrap;
}
.btn:active { transform: translateY(1px) scale(.99); }
.btn--lg { --pad: 16px 30px; font-size: 1.02rem; }
.btn--sm { --pad: 9px 16px; font-size: .85rem; }
.btn--block { width: 100%; }
.btn--neon {
background: linear-gradient(120deg, var(--brand), var(--violet));
color: #fff; box-shadow: var(--shadow-neon);
}
.btn--neon:hover { transform: translateY(-2px); box-shadow: 0 0 0 1px rgba(255,45,120,.6), 0 22px 54px rgba(255,45,120,.42); }
.btn--ghost {
background: rgba(255,255,255,.04); color: var(--ink); border-color: var(--line);
}
.btn--ghost:hover { border-color: var(--line-2); background: rgba(255,45,120,.08); transform: translateY(-2px); }
/* ---------- Nav ---------- */
.nav {
position: sticky; top: 0; z-index: 100;
backdrop-filter: blur(14px);
background: rgba(7,6,12,.72);
border-bottom: 1px solid var(--line);
}
.nav__inner {
max-width: var(--maxw); margin: 0 auto;
display: flex; align-items: center; gap: 20px;
padding: 14px 22px;
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 800; }
.brand__name { font-family: "Space Grotesk", sans-serif; letter-spacing: .02em; font-size: 1.05rem; }
.brand__mark {
width: 22px; height: 22px; border-radius: 7px;
background: linear-gradient(135deg, var(--brand), var(--violet));
box-shadow: 0 0 18px rgba(255,45,120,.7);
position: relative; flex: none;
}
.brand__mark::after {
content: ""; position: absolute; inset: 6px;
border-radius: 3px; background: var(--bg);
}
.nav__links { display: flex; gap: 26px; margin-left: 14px; }
.nav__links a { color: var(--ink-2); font-weight: 600; font-size: .92rem; transition: color .2s; }
.nav__links a:hover { color: var(--brand); }
.nav__actions { margin-left: auto; display: flex; gap: 10px; }
.nav__burger {
display: none; margin-left: auto;
background: none; border: 1px solid var(--line); border-radius: 10px;
width: 44px; height: 44px; cursor: pointer; padding: 0;
flex-direction: column; gap: 5px; align-items: center; justify-content: center;
}
.nav__burger span { width: 20px; height: 2px; background: var(--ink); border-radius: 2px; transition: .25s; }
.nav__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.mobile-nav {
display: none; flex-direction: column; gap: 4px;
padding: 12px 22px 22px; border-bottom: 1px solid var(--line);
background: rgba(7,6,12,.96);
}
.mobile-nav a { padding: 12px 8px; color: var(--ink-2); font-weight: 600; border-radius: 10px; }
.mobile-nav a:hover { background: rgba(255,255,255,.04); color: var(--ink); }
.mobile-nav .btn { margin-top: 8px; }
.mobile-nav.open { display: flex; }
/* ---------- Hero ---------- */
.hero {
position: relative; overflow: hidden;
min-height: 88vh; display: flex; align-items: center;
padding: 80px 22px 64px;
background: radial-gradient(120% 90% at 80% -10%, rgba(139,61,255,.22), transparent 55%),
radial-gradient(90% 80% at 8% 110%, rgba(255,45,120,.22), transparent 55%),
var(--bg);
}
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__glow { position: absolute; border-radius: 50%; filter: blur(70px); opacity: .55; }
.hero__glow--a { width: 460px; height: 460px; background: var(--brand); top: -120px; right: -60px; animation: float 9s ease-in-out infinite; }
.hero__glow--b { width: 420px; height: 420px; background: var(--violet); bottom: -160px; left: -80px; animation: float 11s ease-in-out infinite reverse; }
.hero__grid {
position: absolute; inset: 0;
background-image: linear-gradient(rgba(255,255,255,.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,.04) 1px, transparent 1px);
background-size: 46px 46px;
mask-image: radial-gradient(110% 80% at 50% 20%, #000 30%, transparent 75%);
}
@keyframes float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-26px); } }
.hero__content { position: relative; z-index: 1; max-width: var(--maxw); margin: 0 auto; width: 100%; }
.eyebrow {
display: inline-flex; align-items: center; gap: 9px;
font-weight: 700; font-size: .8rem; letter-spacing: .14em; text-transform: uppercase;
color: var(--ink-2); padding: 7px 14px; border: 1px solid var(--line);
border-radius: 999px; background: rgba(255,255,255,.03);
}
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
.dot--live { background: var(--brand); box-shadow: 0 0 0 0 rgba(255,45,120,.7); animation: pulse 1.8s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255,45,120,.6); } 70% { box-shadow: 0 0 0 9px rgba(255,45,120,0); } 100% { box-shadow: 0 0 0 0 rgba(255,45,120,0); } }
.hero__title {
font-family: "Space Grotesk", sans-serif; font-weight: 700;
font-size: clamp(2.8rem, 9vw, 6.2rem); margin: 18px 0 0;
text-transform: uppercase; letter-spacing: -.03em;
background: linear-gradient(110deg, #fff 20%, var(--brand) 60%, var(--violet) 95%);
-webkit-background-clip: text; background-clip: text; color: transparent;
text-shadow: 0 0 60px rgba(255,45,120,.25);
}
.hero__sub {
display: block; font-size: clamp(1rem, 3vw, 1.6rem); letter-spacing: .04em;
margin-top: 8px; color: var(--ink-2);
background: none; -webkit-text-fill-color: var(--ink-2);
}
.hero__lede { max-width: 560px; margin-top: 20px; color: var(--ink-2); font-size: 1.08rem; }
.hero__meta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.meta-chip {
display: flex; flex-direction: column; gap: 2px;
padding: 12px 18px; border: 1px solid var(--line); border-radius: var(--r-md);
background: rgba(255,255,255,.03);
}
.meta-chip__k { font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.meta-chip__v { font-weight: 700; font-size: 1.05rem; }
.price { color: var(--brand); }
.countdown { display: flex; gap: 10px; margin-top: 28px; }
.cd {
display: flex; flex-direction: column; align-items: center; gap: 2px;
min-width: 72px; padding: 12px 8px;
background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--r-md);
box-shadow: inset 0 0 24px rgba(255,45,120,.06);
}
.cd__num { font-family: "Space Grotesk", sans-serif; font-weight: 700; font-size: 1.9rem; color: #fff; font-variant-numeric: tabular-nums; }
.cd__lbl { font-size: .68rem; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.hero__cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.hero__note { margin-top: 16px; color: var(--muted); font-size: .85rem; }
/* ---------- Marquee ---------- */
.marquee {
overflow: hidden; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
background: linear-gradient(90deg, rgba(255,45,120,.1), rgba(139,61,255,.1));
padding: 12px 0;
}
.marquee__track {
display: inline-flex; gap: 26px; white-space: nowrap;
font-family: "Space Grotesk", sans-serif; font-weight: 700; letter-spacing: .08em;
text-transform: uppercase; color: var(--ink-2); font-size: .9rem;
animation: scroll 22s linear infinite;
}
.marquee__track span { color: var(--brand); }
.marquee__track span:nth-child(even) { color: var(--ink-2); }
@keyframes scroll { to { transform: translateX(-50%); } }
/* ---------- Sections ---------- */
.section { max-width: var(--maxw); margin: 0 auto; padding: 84px 22px; }
.section--dark { max-width: none; background: var(--bg-2); border-block: 1px solid var(--line); }
.section--dark > * { max-width: var(--maxw); margin-inline: auto; }
.section__head { margin-bottom: 36px; }
.section__title {
font-family: "Space Grotesk", sans-serif; font-weight: 700;
font-size: clamp(1.8rem, 4.6vw, 2.8rem); text-transform: uppercase; letter-spacing: -.02em;
}
.section__sub { margin-top: 12px; color: var(--ink-2); max-width: 560px; }
/* ---------- Filters / chips ---------- */
.filters { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 24px; }
.chip {
padding: 9px 18px; border-radius: 999px; cursor: pointer;
background: rgba(255,255,255,.03); color: var(--ink-2);
border: 1px solid var(--line); font-weight: 600; font-size: .88rem;
font-family: inherit; transition: .2s;
}
.chip:hover { border-color: var(--line-2); color: var(--ink); }
.chip--on { background: linear-gradient(120deg, var(--brand), var(--violet)); color: #fff; border-color: transparent; }
/* ---------- Dates ---------- */
.dates { display: flex; flex-direction: column; gap: 12px; }
.date {
display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: 18px;
padding: 16px 20px; border: 1px solid var(--line); border-radius: var(--r-md);
background: var(--surface); transition: border-color .2s, transform .2s, background .2s;
}
.date:hover { border-color: var(--line-2); transform: translateX(4px); background: var(--surface-2); }
.date__when {
display: flex; flex-direction: column; align-items: center; line-height: 1;
min-width: 56px; padding: 8px 6px; border-radius: var(--r-sm);
background: linear-gradient(160deg, rgba(255,45,120,.18), rgba(139,61,255,.18));
border: 1px solid var(--line-2);
}
.date__day { font-family: "Space Grotesk", sans-serif; font-weight: 700; font-size: 1.6rem; }
.date__mo { font-size: .7rem; letter-spacing: .12em; color: var(--ink-2); }
.date__city { display: flex; flex-direction: column; gap: 3px; }
.date__city strong { font-size: 1.08rem; }
.date__city span { color: var(--muted); font-size: .88rem; }
.date__avail { justify-self: end; }
.dates__empty { text-align: center; color: var(--muted); padding: 30px; }
.badge {
display: inline-flex; align-items: center; gap: 6px;
padding: 5px 12px; border-radius: 999px; font-size: .76rem; font-weight: 700;
letter-spacing: .03em;
}
.badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.badge--ok { color: var(--ok); background: rgba(45,212,160,.12); }
.badge--warn { color: var(--warn); background: rgba(255,176,32,.12); }
.badge--out { color: var(--danger); background: rgba(255,77,109,.12); }
/* ---------- Lineup ---------- */
.lineup { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.act {
border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
background: var(--surface); transition: transform .25s, border-color .25s;
}
.act:hover { transform: translateY(-6px); border-color: var(--line-2); }
.act__art {
height: 180px; position: relative;
background:
radial-gradient(120% 100% at 30% 0%, hsl(var(--hue, 320) 90% 60% / .85), transparent 60%),
linear-gradient(160deg, hsl(var(--hue, 320) 80% 45%), #0a0812);
}
.act[data-hue] .act__art { --hue: attr(data-hue); }
.act__art::after {
content: ""; position: absolute; inset: 0;
background: linear-gradient(transparent 40%, var(--surface));
}
.act > * { padding-inline: 22px; }
.act__art { padding: 0; }
.act__tag {
display: inline-block; margin-top: 16px; padding: 5px 12px;
font-size: .72rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
color: var(--brand); background: rgba(255,45,120,.1); border-radius: 999px;
}
.act h3 { margin-top: 12px; font-family: "Space Grotesk", sans-serif; font-size: 1.4rem; }
.act--head h3 { font-size: 1.7rem; }
.act p { margin: 10px 0 22px; color: var(--ink-2); font-size: .92rem; }
/* ---------- Legend ---------- */
.legend { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 26px; }
.legend__item { display: inline-flex; align-items: center; gap: 8px; color: var(--ink-2); font-size: .88rem; font-weight: 600; }
.legend__item i { width: 14px; height: 14px; border-radius: 4px; background: var(--c); box-shadow: 0 0 10px var(--c); }
/* ---------- Tickets ---------- */
.tiers { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.ticket {
position: relative; display: flex; flex-direction: column;
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
overflow: hidden; transition: transform .25s, border-color .25s, box-shadow .25s;
}
.ticket:hover { transform: translateY(-6px); border-color: var(--line-2); box-shadow: var(--shadow); }
.ticket--feat { border-color: var(--brand); box-shadow: var(--shadow-neon); }
.ticket__flag {
position: absolute; top: 14px; right: 14px; z-index: 2;
font-size: .68rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
color: #fff; background: linear-gradient(120deg, var(--brand), var(--violet));
padding: 5px 11px; border-radius: 999px;
}
.ticket__stub {
position: relative; height: 92px;
display: flex; align-items: center; gap: 12px; padding: 0 22px;
background: linear-gradient(120deg, color-mix(in srgb, var(--tc) 30%, #0a0812), #0a0812);
border-bottom: 2px dashed var(--line-2);
}
.ticket__stub::before, .ticket__stub::after {
content: ""; position: absolute; bottom: -9px; width: 16px; height: 16px;
border-radius: 50%; background: var(--bg);
}
.ticket__stub::before { left: -8px; }
.ticket__stub::after { right: -8px; }
.section--dark .ticket__stub::before, .section--dark .ticket__stub::after { background: var(--bg-2); }
.ticket__qr {
width: 42px; height: 42px; border-radius: 6px; flex: none;
background-image:
linear-gradient(45deg, var(--tc) 25%, transparent 25%, transparent 75%, var(--tc) 75%),
linear-gradient(45deg, var(--tc) 25%, transparent 25%, transparent 75%, var(--tc) 75%);
background-size: 10px 10px; background-position: 0 0, 5px 5px;
background-color: #fff; box-shadow: 0 0 14px color-mix(in srgb, var(--tc) 60%, transparent);
}
.ticket__seat {
font-family: "Space Grotesk", sans-serif; font-weight: 700; font-size: 1.5rem;
color: #fff; letter-spacing: .06em;
}
.ticket__body { padding: 22px; display: flex; flex-direction: column; flex: 1; }
.ticket__top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.ticket__top h3 { font-size: 1.2rem; font-family: "Space Grotesk", sans-serif; }
.ticket__price { margin: 14px 0; font-family: "Space Grotesk", sans-serif; font-weight: 700; font-size: 2rem; }
.ticket__price span { font-size: .85rem; font-weight: 500; color: var(--muted); font-family: "Inter", sans-serif; }
.ticket__list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; flex: 1; }
.ticket__list li { position: relative; padding-left: 22px; color: var(--ink-2); font-size: .9rem; }
.ticket__list li::before {
content: "✓"; position: absolute; left: 0; color: var(--brand); font-weight: 800;
}
.cart-bar {
position: sticky; bottom: 16px; z-index: 40; margin-top: 26px;
display: flex; align-items: center; gap: 16px;
padding: 14px 20px; border-radius: 999px;
background: rgba(20,17,31,.94); backdrop-filter: blur(12px);
border: 1px solid var(--line-2); box-shadow: var(--shadow);
}
.cart-bar #cartText { color: var(--ink-2); font-size: .9rem; }
.cart-bar #cartTotal { font-family: "Space Grotesk", sans-serif; font-size: 1.3rem; }
.cart-bar .btn { margin-left: auto; }
/* ---------- Venue ---------- */
.venue { display: grid; grid-template-columns: 1fr 1fr; gap: 36px; align-items: center; }
.venue__addr { color: var(--brand); font-weight: 600; margin-top: 12px; }
.venue__facts { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 24px 0; }
.venue__facts li {
display: flex; flex-direction: column; gap: 3px;
padding: 14px 16px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
}
.venue__facts span { font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.venue__facts strong { font-size: 1.05rem; }
.venue__note { color: var(--muted); font-size: .88rem; }
.venue__map {
display: flex; flex-direction: column; gap: 10px; padding: 22px;
border-radius: var(--r-lg); border: 1px solid var(--line);
background: radial-gradient(110% 100% at 50% 0%, rgba(255,45,120,.12), transparent 60%), var(--surface);
}
.venue__stage {
text-align: center; font-family: "Space Grotesk", sans-serif; font-weight: 700; letter-spacing: .3em;
padding: 14px; border-radius: var(--r-sm); color: #fff;
background: linear-gradient(120deg, var(--brand), var(--violet)); box-shadow: 0 0 24px rgba(255,45,120,.4);
}
.venue__zone {
text-align: center; padding: 16px; border-radius: var(--r-sm);
font-weight: 700; letter-spacing: .14em; font-size: .82rem; color: var(--ink);
background: color-mix(in srgb, var(--zc) 16%, transparent);
border: 1px solid color-mix(in srgb, var(--zc) 50%, transparent);
}
.venue__zone--vip { background: color-mix(in srgb, var(--zc) 22%, transparent); }
/* ---------- Gallery ---------- */
.gallery { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 150px; gap: 14px; }
.shot {
position: relative; margin: 0; border-radius: var(--r-md); overflow: hidden;
background: linear-gradient(160deg, hsl(var(--h, 320) 80% 50%), #0a0812);
border: 1px solid var(--line); transition: transform .3s, box-shadow .3s;
}
.shot::before {
content: ""; position: absolute; inset: 0;
background: radial-gradient(120% 90% at 70% 10%, hsl(var(--h, 320) 90% 62% / .7), transparent 55%);
}
.shot:hover { transform: scale(1.02); box-shadow: var(--shadow-neon); }
.shot--tall { grid-row: span 2; }
.shot--wide { grid-column: span 2; }
.shot figcaption {
position: absolute; left: 12px; bottom: 12px; z-index: 2;
font-size: .78rem; font-weight: 700; color: #fff; letter-spacing: .03em;
text-shadow: 0 2px 8px rgba(0,0,0,.7);
}
/* ---------- FAQ ---------- */
.faq { display: flex; flex-direction: column; gap: 12px; max-width: 820px; }
.qa {
border: 1px solid var(--line); border-radius: var(--r-md);
background: var(--surface); overflow: hidden; transition: border-color .2s;
}
.qa[open] { border-color: var(--line-2); }
.qa summary {
cursor: pointer; list-style: none; padding: 18px 22px;
font-weight: 700; font-size: 1.02rem; display: flex; align-items: center; justify-content: space-between; gap: 14px;
}
.qa summary::-webkit-details-marker { display: none; }
.qa summary::after {
content: "+"; font-size: 1.5rem; color: var(--brand); font-weight: 400; transition: transform .25s; line-height: 1;
}
.qa[open] summary::after { transform: rotate(45deg); }
.qa p { padding: 0 22px 20px; color: var(--ink-2); }
/* ---------- CTA ---------- */
.cta {
position: relative; overflow: hidden; text-align: center;
padding: 100px 22px; margin: 0;
background: radial-gradient(80% 120% at 50% 0%, rgba(139,61,255,.2), transparent 60%), var(--bg-2);
border-top: 1px solid var(--line);
}
.cta__glow {
position: absolute; width: 600px; height: 300px; left: 50%; top: 50%;
transform: translate(-50%, -50%); border-radius: 50%; filter: blur(90px);
background: radial-gradient(var(--brand), transparent 70%); opacity: .25;
}
.cta h2 {
position: relative; font-family: "Space Grotesk", sans-serif;
font-size: clamp(2rem, 6vw, 3.6rem); text-transform: uppercase;
}
.cta p { position: relative; margin: 18px auto 0; max-width: 520px; color: var(--ink-2); font-size: 1.05rem; }
.cta__actions { position: relative; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 30px; }
/* ---------- Footer ---------- */
.footer { background: var(--bg); border-top: 1px solid var(--line); padding: 56px 22px 28px; }
.footer__top { max-width: var(--maxw); margin: 0 auto; display: flex; justify-content: space-between; gap: 40px; flex-wrap: wrap; }
.footer__brand { display: flex; align-items: center; gap: 10px; font-weight: 800; }
.footer__cols { display: flex; gap: 56px; flex-wrap: wrap; }
.footer__cols h4 { font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin-bottom: 12px; }
.footer__cols a { display: block; color: var(--ink-2); font-size: .9rem; padding: 4px 0; transition: color .2s; }
.footer__cols a:hover { color: var(--brand); }
.footer__bar {
max-width: var(--maxw); margin: 36px auto 0; padding-top: 20px;
border-top: 1px solid var(--line); display: flex; justify-content: space-between;
gap: 12px; flex-wrap: wrap; color: var(--muted); font-size: .82rem;
}
/* ---------- Toast ---------- */
.toast {
position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 24px);
background: var(--surface-2); color: var(--ink);
border: 1px solid var(--line-2); border-radius: 999px;
padding: 13px 22px; font-weight: 600; font-size: .9rem;
box-shadow: var(--shadow); opacity: 0; pointer-events: none;
transition: opacity .3s, transform .3s; z-index: 300; max-width: 88vw; text-align: center;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* ---------- Reveal ---------- */
.reveal { opacity: 0; transform: translateY(22px); transition: opacity .6s ease, transform .6s ease; }
.reveal.in { opacity: 1; transform: none; }
/* ---------- Responsive ---------- */
@media (max-width: 920px) {
.lineup, .tiers, .gallery { grid-template-columns: repeat(2, 1fr); }
.gallery { grid-auto-rows: 130px; }
.venue { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
.nav__links, .nav__actions { display: none; }
.nav__burger { display: flex; }
}
@media (max-width: 520px) {
.hero { min-height: auto; padding-top: 56px; }
.hero__meta { gap: 8px; }
.meta-chip { flex: 1 1 100%; }
.countdown { gap: 7px; }
.cd { min-width: 0; flex: 1; padding: 10px 4px; }
.cd__num { font-size: 1.5rem; }
.lineup, .tiers, .gallery { grid-template-columns: 1fr; }
.gallery { grid-auto-rows: 160px; }
.shot--tall, .shot--wide { grid-row: auto; grid-column: auto; }
.date { grid-template-columns: auto 1fr; grid-template-areas: "when city" "avail btn"; row-gap: 12px; }
.date__when { grid-area: when; }
.date__city { grid-area: city; }
.date__avail { grid-area: avail; justify-self: start; align-self: center; }
.date .btn { grid-area: btn; justify-self: end; }
.venue__facts { grid-template-columns: 1fr; }
.footer__top { flex-direction: column; }
.cart-bar { flex-wrap: wrap; }
}
@media (prefers-reduced-motion: reduce) {
* { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
.reveal { opacity: 1; transform: none; transition: none; }
html { scroll-behavior: auto; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
/* ---------- Apply data-hue gradients (attr() fallback) ---------- */
document.querySelectorAll("[data-hue]").forEach(function (el) {
el.style.setProperty("--hue", el.getAttribute("data-hue"));
el.style.setProperty("--h", el.getAttribute("data-hue"));
});
/* ---------- Mobile nav ---------- */
var burger = document.getElementById("burger");
var mobileNav = document.getElementById("mobileNav");
if (burger && mobileNav) {
burger.addEventListener("click", function () {
var open = mobileNav.classList.toggle("open");
burger.setAttribute("aria-expanded", open ? "true" : "false");
burger.setAttribute("aria-label", open ? "Close menu" : "Open menu");
});
mobileNav.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
mobileNav.classList.remove("open");
burger.setAttribute("aria-expanded", "false");
});
});
}
/* ---------- Countdown to opening night ---------- */
var target = new Date("2026-08-14T20:00:00").getTime();
var cdFields = {
days: document.querySelector('[data-cd="days"]'),
hours: document.querySelector('[data-cd="hours"]'),
mins: document.querySelector('[data-cd="mins"]'),
secs: document.querySelector('[data-cd="secs"]'),
};
function pad(n) { return n < 10 ? "0" + n : "" + n; }
function tickCountdown() {
var diff = target - Date.now();
if (diff < 0) diff = 0;
var d = Math.floor(diff / 86400000);
var h = Math.floor((diff % 86400000) / 3600000);
var m = Math.floor((diff % 3600000) / 60000);
var s = Math.floor((diff % 60000) / 1000);
if (cdFields.days) cdFields.days.textContent = pad(d);
if (cdFields.hours) cdFields.hours.textContent = pad(h);
if (cdFields.mins) cdFields.mins.textContent = pad(m);
if (cdFields.secs) cdFields.secs.textContent = pad(s);
}
tickCountdown();
setInterval(tickCountdown, 1000);
/* ---------- Date filters ---------- */
var chips = document.querySelectorAll(".chip[data-filter]");
var dateItems = document.querySelectorAll("#datesList .date");
var emptyMsg = document.getElementById("datesEmpty");
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
chips.forEach(function (c) { c.classList.remove("chip--on"); });
chip.classList.add("chip--on");
var f = chip.getAttribute("data-filter");
var shown = 0;
dateItems.forEach(function (item) {
var match = f === "all" || item.getAttribute("data-status") === f;
item.style.display = match ? "" : "none";
if (match) shown++;
});
if (emptyMsg) emptyMsg.hidden = shown !== 0;
});
});
/* ---------- Waitlist buttons ---------- */
document.querySelectorAll("[data-waitlist]").forEach(function (btn) {
btn.addEventListener("click", function () {
var city = btn.getAttribute("data-waitlist");
btn.textContent = "On waitlist";
btn.disabled = true;
btn.style.opacity = ".7";
toast("You're on the " + city + " waitlist — we'll ping you if seats open.");
});
});
/* ---------- Cart ---------- */
var cart = {};
var cartBar = document.getElementById("cartBar");
var cartText = document.getElementById("cartText");
var cartTotal = document.getElementById("cartTotal");
function renderCart() {
var count = 0, total = 0;
Object.keys(cart).forEach(function (k) {
count += cart[k].qty;
total += cart[k].qty * cart[k].amt;
});
if (count === 0) {
if (cartBar) cartBar.hidden = true;
return;
}
if (cartBar) cartBar.hidden = false;
if (cartText) cartText.textContent = count + (count === 1 ? " ticket" : " tickets");
if (cartTotal) cartTotal.textContent = "$" + total;
}
document.querySelectorAll("[data-buy]").forEach(function (btn) {
btn.addEventListener("click", function () {
var name = btn.getAttribute("data-buy");
var amt = parseInt(btn.getAttribute("data-amt"), 10) || 0;
var current = cart[name] ? cart[name].qty : 0;
if (current >= 4) {
toast("4 ticket limit reached for " + name + ".");
return;
}
cart[name] = { qty: current + 1, amt: amt };
renderCart();
toast("Added " + name + " ($" + amt + ") — " + (current + 1) + " in cart.");
});
});
var checkoutBtn = document.getElementById("checkoutBtn");
if (checkoutBtn) {
checkoutBtn.addEventListener("click", function () {
toast("Checkout is illustrative only — no real tickets are sold here.");
});
}
/* ---------- Scroll reveal ---------- */
var reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("in");
io.unobserve(entry.target);
}
});
}, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" });
reveals.forEach(function (el) { io.observe(el); });
} else {
reveals.forEach(function (el) { el.classList.add("in"); });
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>NOVA PULSE — Aftershock World Tour</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&family=Space+Grotesk:wght@500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<header class="nav" id="top">
<div class="nav__inner">
<a class="brand" href="#top" aria-label="NOVA PULSE home">
<span class="brand__mark" aria-hidden="true"></span>
<span class="brand__name">NOVA PULSE</span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#dates">Tour Dates</a>
<a href="#lineup">Lineup</a>
<a href="#tiers">Tickets</a>
<a href="#venue">Venue</a>
<a href="#faq">FAQ</a>
</nav>
<div class="nav__actions">
<a class="btn btn--ghost" href="#dates">Find a date</a>
<a class="btn btn--neon" href="#tiers">Get tickets</a>
</div>
<button class="nav__burger" id="burger" aria-label="Open menu" aria-expanded="false" aria-controls="mobileNav">
<span></span><span></span><span></span>
</button>
</div>
<nav class="mobile-nav" id="mobileNav" aria-label="Mobile">
<a href="#dates">Tour Dates</a>
<a href="#lineup">Lineup</a>
<a href="#tiers">Tickets</a>
<a href="#venue">Venue</a>
<a href="#faq">FAQ</a>
<a class="btn btn--neon" href="#tiers">Get tickets</a>
</nav>
</header>
<main id="main">
<!-- HERO -->
<section class="hero" aria-labelledby="hero-title">
<div class="hero__media" aria-hidden="true">
<div class="hero__glow hero__glow--a"></div>
<div class="hero__glow hero__glow--b"></div>
<div class="hero__grid"></div>
</div>
<div class="hero__content">
<p class="eyebrow"><span class="dot dot--live"></span> Live 2026 · Stadium Run</p>
<h1 id="hero-title" class="hero__title">NOVA PULSE<span class="hero__sub">Aftershock World Tour</span></h1>
<p class="hero__lede">One band. Twelve cities. A wall of light and bass engineered to make 60,000 people move as one. Doors open at dusk — the floor never stops.</p>
<div class="hero__meta">
<div class="meta-chip"><span class="meta-chip__k">Opening night</span><span class="meta-chip__v">Fri · Aug 14, 2026</span></div>
<div class="meta-chip"><span class="meta-chip__k">First stop</span><span class="meta-chip__v">Helios Arena, LA</span></div>
<div class="meta-chip"><span class="meta-chip__k">From</span><span class="meta-chip__v price">$59</span></div>
</div>
<div class="countdown" id="countdown" aria-label="Time until opening night">
<div class="cd"><span class="cd__num" data-cd="days">00</span><span class="cd__lbl">Days</span></div>
<div class="cd"><span class="cd__num" data-cd="hours">00</span><span class="cd__lbl">Hrs</span></div>
<div class="cd"><span class="cd__num" data-cd="mins">00</span><span class="cd__lbl">Min</span></div>
<div class="cd"><span class="cd__num" data-cd="secs">00</span><span class="cd__lbl">Sec</span></div>
</div>
<div class="hero__cta">
<a class="btn btn--neon btn--lg" href="#tiers">Get tickets</a>
<a class="btn btn--ghost btn--lg" href="#dates">See all dates</a>
</div>
<p class="hero__note">Presale ends Jun 30 · Verified resale only · 4 ticket limit</p>
</div>
</section>
<!-- MARQUEE -->
<div class="marquee" aria-hidden="true">
<div class="marquee__track">
<span>AFTERSHOCK WORLD TOUR</span><span>·</span><span>NOVA PULSE LIVE</span><span>·</span><span>12 CITIES</span><span>·</span><span>ALL-NIGHT FLOOR</span><span>·</span>
<span>AFTERSHOCK WORLD TOUR</span><span>·</span><span>NOVA PULSE LIVE</span><span>·</span><span>12 CITIES</span><span>·</span><span>ALL-NIGHT FLOOR</span><span>·</span>
</div>
</div>
<!-- TOUR DATES -->
<section class="section" id="dates" aria-labelledby="dates-title">
<div class="section__head reveal">
<h2 id="dates-title" class="section__title">Tour Dates</h2>
<p class="section__sub">Filter the run and grab your night before the floor sells out.</p>
</div>
<div class="filters reveal" role="group" aria-label="Filter dates by availability">
<button class="chip chip--on" data-filter="all">All</button>
<button class="chip" data-filter="available">Available</button>
<button class="chip" data-filter="low">Low stock</button>
<button class="chip" data-filter="soldout">Sold out</button>
</div>
<ul class="dates" id="datesList">
<li class="date reveal" data-status="available">
<div class="date__when"><span class="date__day">14</span><span class="date__mo">AUG</span></div>
<div class="date__city"><strong>Los Angeles, CA</strong><span>Helios Arena · 8:00 PM</span></div>
<div class="date__avail"><span class="badge badge--ok">Available</span></div>
<a class="btn btn--neon btn--sm" href="#tiers">Tickets</a>
</li>
<li class="date reveal" data-status="low">
<div class="date__when"><span class="date__day">17</span><span class="date__mo">AUG</span></div>
<div class="date__city"><strong>Phoenix, AZ</strong><span>Sunbelt Coliseum · 7:30 PM</span></div>
<div class="date__avail"><span class="badge badge--warn">Low stock</span></div>
<a class="btn btn--neon btn--sm" href="#tiers">Tickets</a>
</li>
<li class="date reveal" data-status="soldout">
<div class="date__when"><span class="date__day">21</span><span class="date__mo">AUG</span></div>
<div class="date__city"><strong>Denver, CO</strong><span>Altitude Park · 8:00 PM</span></div>
<div class="date__avail"><span class="badge badge--out">Sold out</span></div>
<button class="btn btn--ghost btn--sm" data-waitlist="Denver">Waitlist</button>
</li>
<li class="date reveal" data-status="available">
<div class="date__when"><span class="date__day">24</span><span class="date__mo">AUG</span></div>
<div class="date__city"><strong>Austin, TX</strong><span>Lone Star Dome · 8:30 PM</span></div>
<div class="date__avail"><span class="badge badge--ok">Available</span></div>
<a class="btn btn--neon btn--sm" href="#tiers">Tickets</a>
</li>
<li class="date reveal" data-status="low">
<div class="date__when"><span class="date__day">28</span><span class="date__mo">AUG</span></div>
<div class="date__city"><strong>Chicago, IL</strong><span>Lakeshore Pavilion · 8:00 PM</span></div>
<div class="date__avail"><span class="badge badge--warn">Low stock</span></div>
<a class="btn btn--neon btn--sm" href="#tiers">Tickets</a>
</li>
<li class="date reveal" data-status="soldout">
<div class="date__when"><span class="date__day">02</span><span class="date__mo">SEP</span></div>
<div class="date__city"><strong>Brooklyn, NY</strong><span>Tidewater Hall · 9:00 PM</span></div>
<div class="date__avail"><span class="badge badge--out">Sold out</span></div>
<button class="btn btn--ghost btn--sm" data-waitlist="Brooklyn">Waitlist</button>
</li>
<li class="date reveal" data-status="available">
<div class="date__when"><span class="date__day">06</span><span class="date__mo">SEP</span></div>
<div class="date__city"><strong>Toronto, ON</strong><span>Harbour Sky Arena · 8:00 PM</span></div>
<div class="date__avail"><span class="badge badge--ok">Available</span></div>
<a class="btn btn--neon btn--sm" href="#tiers">Tickets</a>
</li>
</ul>
<p class="dates__empty" id="datesEmpty" hidden>No dates match that filter — try another.</p>
</section>
<!-- LINEUP -->
<section class="section section--dark" id="lineup" aria-labelledby="lineup-title">
<div class="section__head reveal">
<h2 id="lineup-title" class="section__title">The Lineup</h2>
<p class="section__sub">Three acts. One continuous set. Doors at 6, first beat at 7.</p>
</div>
<div class="lineup">
<article class="act act--head reveal">
<div class="act__art" data-hue="320"></div>
<span class="act__tag">Headliner</span>
<h3>NOVA PULSE</h3>
<p>Synth-rock four-piece behind the platinum record <em>Aftershock</em>. Expect the full kinetic stage.</p>
</article>
<article class="act reveal">
<div class="act__art" data-hue="270"></div>
<span class="act__tag">Special guest</span>
<h3>Velvet Static</h3>
<p>Dream-pop duo turning stadiums into slow-motion light fields. 8:15 PM.</p>
</article>
<article class="act reveal">
<div class="act__art" data-hue="200"></div>
<span class="act__tag">Opener</span>
<h3>KORA & THE TIDE</h3>
<p>Percussion-led future-funk that warms the floor from the first note. 7:00 PM.</p>
</article>
</div>
</section>
<!-- TICKET TIERS -->
<section class="section" id="tiers" aria-labelledby="tiers-title">
<div class="section__head reveal">
<h2 id="tiers-title" class="section__title">Ticket Tiers</h2>
<p class="section__sub">Pick your altitude. Prices shown for Los Angeles · Aug 14.</p>
</div>
<div class="legend reveal" aria-hidden="true">
<span class="legend__item"><i style="--c:var(--tier-ga)"></i> General Floor</span>
<span class="legend__item"><i style="--c:var(--tier-low)"></i> Lower Bowl</span>
<span class="legend__item"><i style="--c:var(--tier-pit)"></i> Front Pit</span>
<span class="legend__item"><i style="--c:var(--tier-vip)"></i> VIP Lounge</span>
</div>
<div class="tiers">
<article class="ticket reveal" data-tier="ga">
<div class="ticket__stub" style="--tc:var(--tier-ga)">
<span class="ticket__qr" aria-hidden="true"></span>
<span class="ticket__seat">GA</span>
</div>
<div class="ticket__body">
<div class="ticket__top"><h3>General Floor</h3><span class="badge badge--ok">Available</span></div>
<p class="ticket__price">$59<span>/ person</span></p>
<ul class="ticket__list">
<li>Standing floor access</li>
<li>Entry from 6:00 PM</li>
<li>Mobile ticket + QR</li>
</ul>
<button class="btn btn--ghost btn--block" data-buy="General Floor" data-amt="59">Add to cart</button>
</div>
</article>
<article class="ticket reveal" data-tier="low">
<div class="ticket__stub" style="--tc:var(--tier-low)">
<span class="ticket__qr" aria-hidden="true"></span>
<span class="ticket__seat">LB</span>
</div>
<div class="ticket__body">
<div class="ticket__top"><h3>Lower Bowl</h3><span class="badge badge--warn">Low stock</span></div>
<p class="ticket__price">$94<span>/ person</span></p>
<ul class="ticket__list">
<li>Reserved seat, level 100</li>
<li>Clear stage sightline</li>
<li>Express lane entry</li>
</ul>
<button class="btn btn--ghost btn--block" data-buy="Lower Bowl" data-amt="94">Add to cart</button>
</div>
</article>
<article class="ticket ticket--feat reveal" data-tier="pit">
<span class="ticket__flag">Most popular</span>
<div class="ticket__stub" style="--tc:var(--tier-pit)">
<span class="ticket__qr" aria-hidden="true"></span>
<span class="ticket__seat">PIT</span>
</div>
<div class="ticket__body">
<div class="ticket__top"><h3>Front Pit</h3><span class="badge badge--ok">Available</span></div>
<p class="ticket__price">$149<span>/ person</span></p>
<ul class="ticket__list">
<li>Barricade-front standing</li>
<li>Early doors at 5:15 PM</li>
<li>Commemorative wristband</li>
</ul>
<button class="btn btn--neon btn--block" data-buy="Front Pit" data-amt="149">Add to cart</button>
</div>
</article>
<article class="ticket reveal" data-tier="vip">
<div class="ticket__stub" style="--tc:var(--tier-vip)">
<span class="ticket__qr" aria-hidden="true"></span>
<span class="ticket__seat">VIP</span>
</div>
<div class="ticket__body">
<div class="ticket__top"><h3>VIP Lounge</h3><span class="badge badge--warn">Low stock</span></div>
<p class="ticket__price">$289<span>/ person</span></p>
<ul class="ticket__list">
<li>Skybox lounge + open bar</li>
<li>Dedicated entrance</li>
<li>Soundcheck access</li>
</ul>
<button class="btn btn--ghost btn--block" data-buy="VIP Lounge" data-amt="289">Add to cart</button>
</div>
</article>
</div>
<div class="cart-bar" id="cartBar" hidden aria-live="polite">
<span id="cartText">0 tickets</span>
<strong id="cartTotal">$0</strong>
<button class="btn btn--neon btn--sm" id="checkoutBtn">Checkout</button>
</div>
</section>
<!-- VENUE -->
<section class="section section--dark" id="venue" aria-labelledby="venue-title">
<div class="venue">
<div class="venue__info reveal">
<h2 id="venue-title" class="section__title">Helios Arena</h2>
<p class="venue__addr">1100 Skyline Blvd · Los Angeles, CA 90012</p>
<ul class="venue__facts">
<li><span>Capacity</span><strong>61,400</strong></li>
<li><span>Doors</span><strong>6:00 PM</strong></li>
<li><span>Parking</span><strong>Lots A–E</strong></li>
<li><span>Transit</span><strong>Skyline Line · Helios stop</strong></li>
</ul>
<p class="venue__note">Clear-bag policy in effect. Wheelchair-accessible seating available in every tier — request at checkout.</p>
</div>
<div class="venue__map reveal" aria-label="Stylized venue map" role="img">
<div class="venue__stage">STAGE</div>
<div class="venue__zone" style="--zc:var(--tier-pit)">PIT</div>
<div class="venue__zone" style="--zc:var(--tier-ga)">FLOOR</div>
<div class="venue__zone" style="--zc:var(--tier-low)">LOWER BOWL</div>
<div class="venue__zone venue__zone--vip" style="--zc:var(--tier-vip)">VIP</div>
</div>
</div>
</section>
<!-- GALLERY -->
<section class="section" aria-labelledby="gallery-title">
<div class="section__head reveal">
<h2 id="gallery-title" class="section__title">From the Floor</h2>
<p class="section__sub">Moments from the last run. Yours is next.</p>
</div>
<div class="gallery">
<figure class="shot shot--tall reveal" data-hue="320"><figcaption>Pit · LA 2025</figcaption></figure>
<figure class="shot reveal" data-hue="280"><figcaption>Encore lights</figcaption></figure>
<figure class="shot reveal" data-hue="210"><figcaption>Velvet Static</figcaption></figure>
<figure class="shot shot--wide reveal" data-hue="300"><figcaption>61k strong</figcaption></figure>
<figure class="shot reveal" data-hue="190"><figcaption>Soundcheck</figcaption></figure>
</div>
</section>
<!-- FAQ -->
<section class="section section--dark" id="faq" aria-labelledby="faq-title">
<div class="section__head reveal">
<h2 id="faq-title" class="section__title">FAQ</h2>
<p class="section__sub">Everything you need before doors.</p>
</div>
<div class="faq">
<details class="qa reveal">
<summary>How will I receive my tickets?</summary>
<p>All tickets are mobile-only. A QR code drops to your account 48 hours before doors — screenshots won't scan, so bring the live pass.</p>
</details>
<details class="qa reveal">
<summary>What's the ticket limit?</summary>
<p>Four tickets per person per show. Orders over the limit are auto-cancelled to keep bots off the floor.</p>
</details>
<details class="qa reveal">
<summary>Can I resell a ticket I can't use?</summary>
<p>Yes — only through verified resale inside your account. Off-platform tickets cannot be scanned at the gate.</p>
</details>
<details class="qa reveal">
<summary>Are the shows all-ages?</summary>
<p>All ages welcome. Under-16s must be with an adult in seated tiers. Front Pit is 16+ for safety.</p>
</details>
<details class="qa reveal">
<summary>What can I bring in?</summary>
<p>Clear bags up to 12"×6"×12", a sealed water bottle, and your energy. No pro cameras, no outside food.</p>
</details>
</div>
</section>
<!-- CTA -->
<section class="cta" aria-labelledby="cta-title">
<div class="cta__glow" aria-hidden="true"></div>
<h2 id="cta-title">Don't watch the clips.<br />Be in them.</h2>
<p>Floors are moving fast across the run. Lock your night before it flips to sold out.</p>
<div class="cta__actions">
<a class="btn btn--neon btn--lg" href="#tiers">Get tickets</a>
<a class="btn btn--ghost btn--lg" href="#dates">View tour dates</a>
</div>
</section>
</main>
<footer class="footer">
<div class="footer__top">
<div class="footer__brand">
<span class="brand__mark" aria-hidden="true"></span>
<span class="brand__name">NOVA PULSE</span>
</div>
<nav class="footer__cols" aria-label="Footer">
<div><h4>Tour</h4><a href="#dates">Dates</a><a href="#tiers">Tickets</a><a href="#venue">Venues</a></div>
<div><h4>Help</h4><a href="#faq">FAQ</a><a href="#main">Resale</a><a href="#main">Accessibility</a></div>
<div><h4>Follow</h4><a href="#main">Instagram</a><a href="#main">TikTok</a><a href="#main">Newsletter</a></div>
</nav>
</div>
<div class="footer__bar">
<p>© 2026 NOVA PULSE Touring. Illustrative demo — fictional events.</p>
<p>Built for the floor.</p>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Concert Landing
A high-energy landing page for the fictional NOVA PULSE — Aftershock World Tour. The full-bleed hero pairs a gradient-lit stage backdrop with a neon-gradient title, event meta chips (date, venue, starting price), and a live countdown that ticks down to opening night. Primary calls-to-action drop you straight into tour dates or ticket tiers, and a scrolling marquee keeps the hype loud between sections.
The page is fully interactive. Tour dates filter by availability (all / available / low stock / sold out) with status badges and a graceful empty state, and sold-out shows swap their button for a one-tap waitlist join. Ticket tiers are rendered as perforated stubs with QR motifs and a seat-tier color legend; adding tiers feeds a sticky cart bar that tracks count and total while enforcing a four-ticket limit, with toast feedback throughout.
Below the fold, a three-act lineup, a stylized venue map with color-coded zones, a hype gallery, and an accordion FAQ round out the page. A hamburger-driven mobile nav, IntersectionObserver scroll reveals, and a prefers-reduced-motion fallback keep it responsive down to ~360px and accessible. No frameworks, no build step — just HTML, CSS, and vanilla JS.
Illustrative UI only — fictional events, not a real ticketing service.