Ticketing — Sports Landing
A bold stadium ticketing landing page for a fictional football derby, built with semantic HTML, CSS and vanilla JavaScript. Features a team-vs-team fixture hero in deep blue and red with a live kickoff countdown, buy-by-section ticket cards with tier colours and stock badges, a clickable seating-map teaser, an upcoming fixtures list, hospitality packages, an expandable fan-info FAQ, sticky cart bar, toast feedback, mobile nav and scroll reveals.
MCP
Code
/* Ticketing — Sports Landing :: TixGate Sports
Palette override: stadium team colours — deep blue + red + white */
:root {
/* team colours */
--brand: #0b2a6b; /* deep team blue */
--brand-d: #07205a;
--brand-l: #1d3f8f;
--accent: #d6202b; /* team red */
--accent-d: #b01620;
--gold: #f4b400;
--ink: #0e0e16;
--ink-2: #2a2f3d;
--muted: #6c6c80;
--bg: #eef1f7;
--surface: #ffffff;
--surface-2: #f6f8fc;
--line: rgba(11, 42, 107, 0.12);
--line-strong: rgba(11, 42, 107, 0.24);
--ok: #16a34a;
--warn: #d97706;
--danger: #dc2626;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--sh-1: 0 1px 2px rgba(7, 32, 90, 0.08), 0 4px 14px rgba(7, 32, 90, 0.08);
--sh-2: 0 8px 28px rgba(7, 32, 90, 0.16);
--sh-3: 0 18px 48px rgba(7, 32, 90, 0.24);
--maxw: 1180px;
--display: "Oswald", "Inter", system-ui, sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
color: var(--ink);
background: var(--bg);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { margin: 0; line-height: 1.08; }
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 22px; }
.skip-link {
position: absolute; left: -999px; top: 0; z-index: 200;
background: var(--accent); color: #fff; padding: 10px 16px; border-radius: 0 0 var(--r-sm) 0;
font-weight: 700;
}
.skip-link:focus { left: 0; }
/* ---------- buttons ---------- */
.btn {
--b: var(--brand);
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
font-weight: 700; font-size: 0.92rem;
padding: 11px 18px; border-radius: 999px; border: 1px solid transparent;
cursor: pointer; transition: transform .12s ease, box-shadow .15s ease, background .15s ease, color .15s ease;
white-space: nowrap; letter-spacing: 0.01em;
}
.btn:active { transform: translateY(1px) scale(0.99); }
.btn--primary { background: var(--accent); color: #fff; box-shadow: 0 6px 18px rgba(214, 32, 43, 0.32); }
.btn--primary:hover { background: var(--accent-d); box-shadow: 0 10px 26px rgba(214, 32, 43, 0.42); transform: translateY(-1px); }
.btn--ghost { background: transparent; color: var(--brand); border-color: var(--line-strong); }
.btn--ghost:hover { background: var(--surface); border-color: var(--brand); }
.btn--lg { padding: 15px 28px; font-size: 1.02rem; }
.btn:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
/* ---------- nav ---------- */
.nav {
position: sticky; top: 0; z-index: 100;
background: rgba(255, 255, 255, 0.86);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--line);
transition: box-shadow .2s ease, background .2s ease;
}
.nav.is-scrolled { box-shadow: var(--sh-1); background: rgba(255, 255, 255, 0.95); }
.nav__inner { display: flex; align-items: center; gap: 18px; height: 66px; }
.brand { display: inline-flex; align-items: center; gap: 9px; font-weight: 800; font-size: 1.18rem; letter-spacing: -0.01em; }
.brand__mark {
display: inline-grid; place-items: center; width: 30px; height: 30px;
background: var(--brand); color: #fff; border-radius: 8px; font-size: 0.9rem;
box-shadow: inset 0 0 0 2px var(--accent);
}
.brand__name { font-family: var(--display); text-transform: uppercase; letter-spacing: 0.02em; }
.brand__accent { color: var(--accent); }
.nav__links { display: flex; gap: 4px; margin-left: 8px; }
.nav__links a {
padding: 8px 12px; border-radius: var(--r-sm); font-weight: 600; font-size: 0.92rem; color: var(--ink-2);
transition: background .15s ease, color .15s ease;
}
.nav__links a:hover { background: var(--surface-2); color: var(--brand); }
.nav__actions { display: flex; gap: 10px; margin-left: auto; }
.nav__toggle {
display: none; flex-direction: column; gap: 4px; margin-left: auto;
background: none; border: 0; cursor: pointer; padding: 8px;
}
.nav__toggle span { width: 22px; height: 2.4px; background: var(--brand); border-radius: 2px; transition: transform .2s ease, opacity .2s ease; }
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.4px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.4px) rotate(-45deg); }
.mobile-nav { display: none; flex-direction: column; gap: 2px; padding: 12px 22px 20px; border-top: 1px solid var(--line); background: var(--surface); }
.mobile-nav a { padding: 12px 6px; font-weight: 600; border-bottom: 1px solid var(--line); color: var(--ink-2); }
.mobile-nav__cta { margin-top: 12px; justify-content: center; border-bottom: 0; color: #fff; }
.mobile-nav.is-open { display: flex; }
/* ---------- hero ---------- */
.hero { position: relative; overflow: hidden; color: #fff; isolation: isolate; }
.hero__bg {
position: absolute; inset: 0; z-index: -2;
background:
radial-gradient(120% 90% at 80% -10%, rgba(214, 32, 43, 0.55), transparent 55%),
radial-gradient(120% 120% at 0% 110%, rgba(29, 63, 143, 0.7), transparent 60%),
linear-gradient(150deg, #07205a 0%, #0b2a6b 42%, #131a3a 100%);
}
.hero__grain {
position: absolute; inset: 0; z-index: -1; opacity: 0.5; pointer-events: none;
background-image:
repeating-linear-gradient(115deg, rgba(255,255,255,0.05) 0 2px, transparent 2px 9px),
radial-gradient(60% 60% at 50% 0%, rgba(255,255,255,0.08), transparent);
mix-blend-mode: overlay;
}
.hero__inner { padding: 56px 22px 70px; text-align: center; display: flex; flex-direction: column; align-items: center; }
.hero__meta { display: flex; gap: 10px; margin-bottom: 26px; flex-wrap: wrap; justify-content: center; }
.pill {
display: inline-flex; align-items: center; gap: 7px;
padding: 6px 14px; border-radius: 999px; font-size: 0.78rem; font-weight: 700;
text-transform: uppercase; letter-spacing: 0.06em;
background: rgba(255,255,255,0.12); border: 1px solid rgba(255,255,255,0.22);
}
.pill--live::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 0 rgba(214,32,43,0.6); animation: ping 1.6s infinite; }
@keyframes ping { 0% { box-shadow: 0 0 0 0 rgba(214,32,43,0.55); } 70% { box-shadow: 0 0 0 9px rgba(214,32,43,0); } 100% { box-shadow: 0 0 0 0 rgba(214,32,43,0); } }
.fixture {
display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 14px;
width: 100%; max-width: 720px; margin: 0 auto 26px;
}
.fixture__team { display: flex; align-items: center; gap: 14px; }
.fixture__team--home { justify-content: flex-end; }
.fixture__team--away { justify-content: flex-start; }
.crest {
display: grid; place-items: center; width: 64px; height: 64px; border-radius: 16px;
font-family: var(--display); font-weight: 700; font-size: 1.5rem; letter-spacing: 0.02em;
color: #fff; flex-shrink: 0; box-shadow: var(--sh-2), inset 0 0 0 2px rgba(255,255,255,0.18);
}
.crest--home { background: linear-gradient(160deg, #1d3f8f, #0b2a6b); }
.crest--away { background: linear-gradient(160deg, #e23b44, #b01620); }
.fixture__teaminfo { display: flex; flex-direction: column; text-align: right; }
.fixture__teaminfo--right { text-align: left; }
.fixture__name { font-family: var(--display); font-size: 1.32rem; font-weight: 700; text-transform: uppercase; line-height: 1.05; }
.fixture__form { font-size: 0.72rem; letter-spacing: 0.18em; color: rgba(255,255,255,0.7); font-weight: 600; margin-top: 3px; }
.fixture__vs { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.fixture__vslabel { font-family: var(--display); font-size: 1.5rem; font-weight: 700; color: var(--gold); }
.fixture__kick { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; padding: 3px 9px; border-radius: 999px; background: rgba(255,255,255,0.14); }
.hero__title { font-family: var(--display); font-size: clamp(2.6rem, 8vw, 5rem); font-weight: 700; text-transform: uppercase; letter-spacing: 0.005em; margin-bottom: 8px; text-shadow: 0 4px 24px rgba(0,0,0,0.3); }
.hero__sub { color: rgba(255,255,255,0.82); font-size: 1.05rem; font-weight: 500; margin: 0 0 26px; }
.countdown { display: flex; align-items: center; gap: 8px; margin-bottom: 30px; }
.countdown__unit {
display: flex; flex-direction: column; align-items: center;
background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.18);
border-radius: var(--r-md); padding: 12px 14px; min-width: 66px; backdrop-filter: blur(4px);
}
.countdown__unit span { font-family: var(--display); font-size: 1.9rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.countdown__unit small { font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255,255,255,0.7); margin-top: 2px; }
.countdown__sep { font-family: var(--display); font-size: 1.6rem; color: rgba(255,255,255,0.4); }
.hero__cta { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin-bottom: 36px; }
.hero__cta .btn--ghost { color: #fff; border-color: rgba(255,255,255,0.35); }
.hero__cta .btn--ghost:hover { background: rgba(255,255,255,0.12); border-color: #fff; }
.hero__stats { display: flex; gap: 34px; padding-top: 26px; border-top: 1px solid rgba(255,255,255,0.16); }
.hero__stats div { display: flex; flex-direction: column; align-items: center; }
.hero__stats strong { font-family: var(--display); font-size: 1.6rem; font-weight: 700; }
.hero__stats span { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.1em; color: rgba(255,255,255,0.65); margin-top: 2px; }
/* ---------- sections ---------- */
.section { padding: 72px 0; }
.section--alt { background: var(--surface); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.section__head { max-width: 640px; margin-bottom: 34px; }
.section__head h2 { font-family: var(--display); font-size: clamp(1.8rem, 4vw, 2.6rem); font-weight: 700; text-transform: uppercase; letter-spacing: 0.005em; }
.section__head h2::after { content: ""; display: block; width: 52px; height: 4px; background: var(--accent); border-radius: 3px; margin-top: 12px; }
.section__head p { color: var(--muted); font-size: 1.04rem; margin: 14px 0 0; }
/* legend */
.legend { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 24px; }
.legend__item { display: inline-flex; align-items: center; gap: 8px; font-size: 0.86rem; font-weight: 600; color: var(--ink-2); }
.dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
.dot--gold { background: var(--gold); }
.dot--blue { background: var(--brand-l); }
.dot--red { background: var(--accent); }
.dot--grey { background: #8a93a6; }
/* ---------- tickets ---------- */
.tickets { display: grid; grid-template-columns: repeat(auto-fill, minmax(248px, 1fr)); gap: 18px; }
.tcard {
position: relative; background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-lg); padding: 20px; display: flex; flex-direction: column; gap: 4px;
box-shadow: var(--sh-1); transition: transform .15s ease, box-shadow .18s ease, border-color .15s ease; overflow: hidden;
}
.tcard::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px; background: var(--tier, var(--brand)); }
.tcard:hover { transform: translateY(-4px); box-shadow: var(--sh-2); border-color: var(--line-strong); }
.tcard__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.tcard__tier { font-family: var(--display); font-size: 1.18rem; font-weight: 700; text-transform: uppercase; }
.tcard__loc { font-size: 0.84rem; color: var(--muted); font-weight: 500; }
.tcard__price { margin: 14px 0 4px; font-family: var(--display); font-size: 2.1rem; font-weight: 700; color: var(--brand); }
.tcard__price small { font-size: 0.82rem; color: var(--muted); font-weight: 600; font-family: "Inter", sans-serif; }
.tcard__perf { border-top: 2px dashed var(--line-strong); margin: 14px -20px; position: relative; }
.tcard__perf::before, .tcard__perf::after { content: ""; position: absolute; top: -9px; width: 18px; height: 18px; border-radius: 50%; background: var(--bg); }
.tcard__perf::before { left: -9px; }
.tcard__perf::after { right: -9px; }
.section--alt .tcard__perf::before, .section--alt .tcard__perf::after { background: var(--surface); }
.tcard__feat { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.tcard__feat li { font-size: 0.86rem; color: var(--ink-2); display: flex; gap: 8px; }
.tcard__feat li::before { content: "✓"; color: var(--ok); font-weight: 800; }
.tcard__btn { margin-top: auto; width: 100%; }
.tcard.is-selected { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent), var(--sh-2); }
.badge { font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; padding: 4px 9px; border-radius: 999px; white-space: nowrap; }
.badge--low { background: #fff3e6; color: var(--warn); }
.badge--out { background: #fdeaea; color: var(--danger); }
.badge--good { background: #eafaf0; color: var(--ok); }
.tcard.is-sold { opacity: 0.62; }
.tcard.is-sold .tcard__btn { background: #e6e9f0; color: var(--muted); cursor: not-allowed; box-shadow: none; }
/* cart bar */
.cart-bar {
position: sticky; bottom: 14px; z-index: 40; margin-top: 24px;
display: flex; align-items: center; justify-content: space-between; gap: 14px;
background: var(--brand); color: #fff; padding: 14px 18px; border-radius: var(--r-lg);
box-shadow: var(--sh-3); animation: rise .25s ease;
}
@keyframes rise { from { transform: translateY(10px); opacity: 0; } to { transform: none; opacity: 1; } }
.cart-bar__info { display: flex; flex-direction: column; line-height: 1.25; }
.cart-bar__info strong { font-size: 1.02rem; }
.cart-bar__info span { font-family: var(--display); font-size: 1.3rem; font-weight: 700; color: var(--gold); }
/* ---------- fixtures ---------- */
.fixtures { display: flex; flex-direction: column; gap: 10px; }
.frow {
display: grid; grid-template-columns: 92px 1fr auto auto; align-items: center; gap: 16px;
background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md); padding: 16px 20px;
transition: transform .14s ease, box-shadow .16s ease, background .14s ease;
}
.section--alt .frow { background: var(--surface-2); }
.frow:hover { transform: translateX(4px); box-shadow: var(--sh-1); }
.frow__date { display: flex; flex-direction: column; align-items: center; text-align: center; border-right: 1px solid var(--line-strong); padding-right: 12px; }
.frow__day { font-family: var(--display); font-size: 1.5rem; font-weight: 700; color: var(--brand); line-height: 1; }
.frow__mon { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); font-weight: 700; }
.frow__match { font-weight: 700; font-size: 1.02rem; }
.frow__sub { font-size: 0.82rem; color: var(--muted); margin-top: 2px; }
.frow__comp { font-size: 0.74rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--brand-l); padding: 4px 10px; border-radius: 999px; background: rgba(29,63,143,0.1); }
.frow__btn { white-space: nowrap; }
/* ---------- seating ---------- */
.seating { display: grid; grid-template-columns: 1fr 1.05fr; gap: 44px; align-items: center; }
.seating__copy h2 { font-family: var(--display); font-size: clamp(1.8rem, 4vw, 2.6rem); font-weight: 700; text-transform: uppercase; }
.seating__copy > p { color: var(--muted); margin: 16px 0 20px; font-size: 1.04rem; }
.seating__list { list-style: none; margin: 0 0 20px; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.seating__list li { display: flex; align-items: center; gap: 10px; font-weight: 600; color: var(--ink-2); font-size: 0.95rem; }
.seating__hint { font-weight: 700; color: var(--brand); font-size: 0.95rem; }
.pitch {
display: flex; flex-direction: column; gap: 12px;
background: linear-gradient(150deg, #0b2a6b, #07205a); padding: 18px; border-radius: var(--r-lg);
box-shadow: var(--sh-3); aspect-ratio: 4 / 3;
}
.pitch__mid { display: grid; grid-template-columns: 64px 1fr 64px; gap: 12px; flex: 1; }
.pitch__field {
border-radius: var(--r-md);
background:
repeating-linear-gradient(90deg, #1f7a3a 0 14%, #2a8c46 14% 28%),
#2a8c46;
display: grid; place-items: center; box-shadow: inset 0 0 0 3px rgba(255,255,255,0.4), inset 0 0 30px rgba(0,0,0,0.3); position: relative;
}
.pitch__field::before { content: ""; position: absolute; width: 50%; height: 50%; border: 3px solid rgba(255,255,255,0.4); border-radius: 50%; }
.pitch__field span { font-family: var(--display); font-weight: 700; color: rgba(255,255,255,0.9); text-align: center; font-size: 0.86rem; letter-spacing: 0.06em; line-height: 1.2; position: relative; z-index: 1; text-shadow: 0 1px 4px rgba(0,0,0,0.4); }
.stand {
border: 0; cursor: pointer; color: #fff; font-family: var(--display); font-weight: 700;
text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.82rem;
border-radius: var(--r-sm); padding: 10px; transition: transform .14s ease, box-shadow .16s ease, filter .14s ease;
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.18);
}
.stand--north { background: var(--gold); color: #1a1400; }
.stand--south { background: var(--accent); }
.stand--east, .stand--west { background: var(--brand-l); writing-mode: vertical-rl; text-orientation: mixed; }
.stand:hover, .stand.is-active { transform: scale(1.03); box-shadow: 0 0 0 3px var(--gold), var(--sh-2); filter: brightness(1.08); z-index: 1; }
.stand:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
/* ---------- hospitality ---------- */
.hosp { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; align-items: stretch; }
.hosp__card {
position: relative; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
overflow: hidden; box-shadow: var(--sh-1); display: flex; flex-direction: column;
transition: transform .16s ease, box-shadow .18s ease;
}
.hosp__card:hover { transform: translateY(-5px); box-shadow: var(--sh-2); }
.hosp__card--feature { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(214,32,43,0.18), var(--sh-2); }
.ribbon { position: absolute; top: 14px; right: -34px; transform: rotate(45deg); background: var(--accent); color: #fff; font-size: 0.7rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; padding: 5px 40px; z-index: 2; box-shadow: var(--sh-1); }
.hosp__img { height: 150px; position: relative; }
.hosp__img--a { background: linear-gradient(150deg, #1d3f8f, #0b2a6b); }
.hosp__img--b { background: linear-gradient(150deg, #e23b44, #07205a); }
.hosp__img--c { background: linear-gradient(150deg, #f4b400, #b01620); }
.hosp__img::after { content: ""; position: absolute; inset: 0; background: repeating-linear-gradient(115deg, rgba(255,255,255,0.06) 0 3px, transparent 3px 11px); }
.hosp__body { padding: 20px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.hosp__body h3 { font-family: var(--display); font-size: 1.34rem; font-weight: 700; text-transform: uppercase; }
.hosp__body p { color: var(--muted); font-size: 0.92rem; margin: 0; flex: 1; }
.hosp__foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 8px; }
.hosp__price { font-family: var(--display); font-size: 1.7rem; font-weight: 700; color: var(--brand); }
.hosp__price small { font-size: 0.78rem; color: var(--muted); font-weight: 600; font-family: "Inter", sans-serif; }
/* ---------- faq ---------- */
.faq { display: flex; flex-direction: column; gap: 10px; max-width: 820px; }
.faq__item { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md); padding: 0 20px; transition: box-shadow .16s ease, border-color .15s ease; }
.faq__item[open] { box-shadow: var(--sh-1); border-color: var(--line-strong); }
.faq__item summary { list-style: none; cursor: pointer; padding: 18px 0; font-weight: 700; font-size: 1.02rem; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after { content: "+"; font-family: var(--display); font-size: 1.5rem; color: var(--accent); transition: transform .2s ease; line-height: 1; }
.faq__item[open] summary::after { transform: rotate(45deg); }
.faq__item p { margin: 0 0 18px; color: var(--ink-2); font-size: 0.96rem; }
/* ---------- cta ---------- */
.cta { padding: 80px 0; background: var(--brand); color: #fff; position: relative; overflow: hidden; }
.cta::before { content: ""; position: absolute; inset: 0; background: radial-gradient(80% 120% at 100% 0%, rgba(214,32,43,0.5), transparent 60%); }
.cta__inner { position: relative; text-align: center; max-width: 640px; margin: 0 auto; }
.cta__inner h2 { font-family: var(--display); font-size: clamp(2rem, 5vw, 3rem); font-weight: 700; text-transform: uppercase; margin-bottom: 10px; }
.cta__inner p { color: rgba(255,255,255,0.82); font-size: 1.1rem; margin: 0 0 26px; }
.cta__perf { position: absolute; left: 50%; top: -10px; transform: translateX(-50%); width: 70%; border-top: 2px dashed rgba(255,255,255,0.3); }
/* ---------- footer ---------- */
.footer { background: #0a1326; color: rgba(255,255,255,0.7); padding: 52px 0 24px; }
.footer__inner { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 28px; }
.footer__brand .brand { color: #fff; margin-bottom: 12px; }
.footer__brand .brand__mark { background: var(--accent); box-shadow: none; }
.footer__brand p { font-size: 0.88rem; max-width: 320px; margin: 0; }
.footer__col h4 { font-family: var(--display); text-transform: uppercase; color: #fff; font-size: 0.92rem; letter-spacing: 0.06em; margin-bottom: 14px; }
.footer__col a { display: block; padding: 5px 0; font-size: 0.9rem; transition: color .14s ease; }
.footer__col a:hover { color: #fff; }
.footer__bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-top: 36px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.12); font-size: 0.82rem; }
.footer__legal a:hover { color: #fff; }
/* ---------- toast ---------- */
.toast {
position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 30px);
background: var(--ink); color: #fff; padding: 13px 20px; border-radius: var(--r-md);
font-weight: 600; font-size: 0.92rem; box-shadow: var(--sh-3); z-index: 300;
opacity: 0; pointer-events: none; transition: opacity .22s ease, transform .22s ease; max-width: 90vw;
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }
.toast::before { content: "🎟"; margin-right: 8px; }
/* ---------- reveal ---------- */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .55s ease, transform .55s ease; }
.reveal.is-in { opacity: 1; transform: none; }
/* ---------- responsive ---------- */
@media (max-width: 900px) {
.nav__links, .nav__actions { display: none; }
.nav__toggle { display: flex; }
.seating { grid-template-columns: 1fr; gap: 28px; }
.footer__inner { grid-template-columns: 1fr 1fr; }
.footer__brand { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
.wrap { padding: 0 16px; }
.section { padding: 52px 0; }
.hero__inner { padding: 40px 16px 52px; }
.fixture { grid-template-columns: 1fr; gap: 18px; }
.fixture__team { justify-content: center; }
.fixture__team--home, .fixture__team--away { flex-direction: column; text-align: center; }
.fixture__teaminfo, .fixture__teaminfo--right { text-align: center; }
.fixture__vs { order: 2; }
.crest { width: 56px; height: 56px; }
.countdown__unit { min-width: 56px; padding: 10px; }
.countdown__unit span { font-size: 1.5rem; }
.hero__stats { gap: 22px; }
.frow { grid-template-columns: 70px 1fr; row-gap: 8px; }
.frow__comp { grid-column: 2; justify-self: start; }
.frow__btn { grid-column: 1 / -1; }
.footer__inner { grid-template-columns: 1fr; }
.footer__bar { flex-direction: column; gap: 8px; text-align: center; }
.cart-bar { flex-direction: column; align-items: stretch; }
.cart-bar .btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; scroll-behavior: auto; }
.reveal { opacity: 1; transform: none; transition: none; }
}/* TixGate Sports — Harbor Derby landing
Vanilla JS: toast, mobile nav, scroll reveal, countdown,
section ticket cards + cart, fixtures list, seating teaser. */
(function () {
"use strict";
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2600);
}
var gbp = new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" });
/* ---------- sticky nav shadow ---------- */
var nav = document.getElementById("nav");
function onScroll() {
if (window.scrollY > 8) nav.classList.add("is-scrolled");
else nav.classList.remove("is-scrolled");
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- mobile nav ---------- */
var toggle = document.getElementById("navToggle");
var mobileNav = document.getElementById("mobileNav");
function closeMobile() {
mobileNav.classList.remove("is-open");
mobileNav.hidden = true;
toggle.setAttribute("aria-expanded", "false");
}
toggle.addEventListener("click", function () {
var open = mobileNav.classList.toggle("is-open");
mobileNav.hidden = !open;
toggle.setAttribute("aria-expanded", String(open));
});
mobileNav.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", closeMobile);
});
/* ---------- scroll reveal ---------- */
var revealEls = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) {
e.target.classList.add("is-in");
io.unobserve(e.target);
}
});
}, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" });
revealEls.forEach(function (el) { io.observe(el); });
} else {
revealEls.forEach(function (el) { el.classList.add("is-in"); });
}
/* ---------- countdown ---------- */
var KICKOFF = new Date("2026-06-27T19:45:00");
var cdMap = {
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 String(n).padStart(2, "0"); }
function tick() {
var diff = KICKOFF - new Date();
if (diff < 0) diff = 0;
var s = Math.floor(diff / 1000);
var d = Math.floor(s / 86400); s -= d * 86400;
var h = Math.floor(s / 3600); s -= h * 3600;
var m = Math.floor(s / 60); s -= m * 60;
if (cdMap.days) cdMap.days.textContent = pad(d);
if (cdMap.hours) cdMap.hours.textContent = pad(h);
if (cdMap.mins) cdMap.mins.textContent = pad(m);
if (cdMap.secs) cdMap.secs.textContent = pad(s);
}
tick();
setInterval(tick, 1000);
/* ---------- ticket sections ---------- */
var sections = [
{ id: "north", tier: "North Stand", loc: "Premium · halfway line", price: 64, color: "var(--gold)",
feats: ["Padded seats", "Best sightlines", "Covered roof"], stock: "low" },
{ id: "west", tier: "West Stand", loc: "Standard · home end", price: 42, color: "var(--brand-l)",
feats: ["Vocal atmosphere", "Lower & upper tier"], stock: "good" },
{ id: "east", tier: "East Stand", loc: "Standard · home end", price: 42, color: "var(--brand-l)",
feats: ["Singing section", "Closest to tunnel"], stock: "low" },
{ id: "south", tier: "South Family", loc: "Family · alcohol-free", price: 24, color: "var(--accent)",
feats: ["Under-16 from £8", "Mascot zone"], stock: "good" },
{ id: "corner", tier: "Corner Box", loc: "Premium · NE corner", price: 88, color: "var(--gold)",
feats: ["Padded VIP seat", "Lounge access"], stock: "out" },
{ id: "away", tier: "Away Lower", loc: "Allocated · away fans", price: 38, color: "#8a93a6",
feats: ["Riverside FC supporters", "ID required"], stock: "good" }
];
var grid = document.getElementById("ticketGrid");
var cart = {}; // id -> {qty, price, tier}
function badgeFor(stock) {
if (stock === "out") return '<span class="badge badge--out">Sold out</span>';
if (stock === "low") return '<span class="badge badge--low">Low stock</span>';
return '<span class="badge badge--good">Available</span>';
}
function renderTickets() {
grid.innerHTML = "";
sections.forEach(function (sec) {
var sold = sec.stock === "out";
var card = document.createElement("article");
card.className = "tcard" + (sold ? " is-sold" : "");
card.style.setProperty("--tier", sec.color);
card.innerHTML =
'<div class="tcard__top">' +
'<div><div class="tcard__tier">' + sec.tier + '</div>' +
'<div class="tcard__loc">' + sec.loc + '</div></div>' +
badgeFor(sec.stock) +
'</div>' +
'<div class="tcard__price">' + gbp.format(sec.price) + ' <small>/ adult</small></div>' +
'<div class="tcard__perf"></div>' +
'<ul class="tcard__feat">' + sec.feats.map(function (f) { return "<li>" + f + "</li>"; }).join("") + '</ul>' +
'<button class="btn btn--primary tcard__btn" type="button"' + (sold ? " disabled" : "") + '>' +
(sold ? "Sold out" : "Add seat") + '</button>';
var btn = card.querySelector(".tcard__btn");
btn.addEventListener("click", function () {
if (sold) return;
addToCart(sec, card);
});
grid.appendChild(card);
});
}
/* ---------- cart ---------- */
var cartBar = document.getElementById("cartBar");
var cartCount = document.getElementById("cartCount");
var cartTotal = document.getElementById("cartTotal");
var checkoutBtn = document.getElementById("checkoutBtn");
function addToCart(sec, card) {
if (!cart[sec.id]) cart[sec.id] = { qty: 0, price: sec.price, tier: sec.tier };
cart[sec.id].qty += 1;
card.classList.add("is-selected");
toast("Added " + sec.tier + " · " + gbp.format(sec.price));
updateCart();
}
function updateCart() {
var seats = 0, total = 0;
Object.keys(cart).forEach(function (k) {
seats += cart[k].qty;
total += cart[k].qty * cart[k].price;
});
if (seats === 0) {
cartBar.hidden = true;
return;
}
cartBar.hidden = false;
cartCount.textContent = seats + (seats === 1 ? " seat" : " seats");
cartTotal.textContent = gbp.format(total);
}
checkoutBtn.addEventListener("click", function () {
var seats = Object.keys(cart).reduce(function (a, k) { return a + cart[k].qty; }, 0);
toast("Reserved " + seats + " seat" + (seats === 1 ? "" : "s") + " — opening seat selector (demo)");
cart = {};
document.querySelectorAll(".tcard.is-selected").forEach(function (c) { c.classList.remove("is-selected"); });
updateCart();
});
renderTickets();
/* ---------- fixtures ---------- */
var fixtures = [
{ day: "27", mon: "Jun", match: "Northgate United vs Riverside FC", sub: "Sat · 19:45 · Harbor Stadium", comp: "League", soon: true },
{ day: "04", mon: "Jul", match: "Eastfield Town vs Northgate United", sub: "Sat · 15:00 · The Mill (Away)", comp: "League" },
{ day: "11", mon: "Jul", match: "Northgate United vs Port Albion", sub: "Sat · 17:30 · Harbor Stadium", comp: "Cup" },
{ day: "18", mon: "Jul", match: "Northgate United vs Westbay Rangers", sub: "Sat · 15:00 · Harbor Stadium", comp: "League" },
{ day: "26", mon: "Jul", match: "Highcross City vs Northgate United", sub: "Sun · 14:00 · Crown Park (Away)", comp: "League" }
];
var fixturesList = document.getElementById("fixturesList");
fixtures.forEach(function (f) {
var row = document.createElement("div");
row.className = "frow reveal";
row.innerHTML =
'<div class="frow__date"><span class="frow__day">' + f.day + '</span><span class="frow__mon">' + f.mon + '</span></div>' +
'<div><div class="frow__match">' + f.match + '</div><div class="frow__sub">' + f.sub + '</div></div>' +
'<span class="frow__comp">' + f.comp + '</span>' +
'<button class="btn ' + (f.soon ? "btn--primary" : "btn--ghost") + ' frow__btn" type="button">' +
(f.soon ? "Buy now" : "Notify me") + '</button>';
row.querySelector(".frow__btn").addEventListener("click", function () {
if (f.soon) {
document.getElementById("tickets").scrollIntoView({ behavior: "smooth" });
toast("Pick your section for the Harbor Derby");
} else {
toast("We'll alert you when " + f.match.split(" vs ")[0] + " tickets go live");
}
});
fixturesList.appendChild(row);
if (io) io.observe(row);
});
/* ---------- seating teaser ---------- */
var seatHint = document.getElementById("seatHint");
var stands = document.querySelectorAll(".stand");
function showStand(el) {
stands.forEach(function (s) { s.classList.remove("is-active"); });
el.classList.add("is-active");
seatHint.innerHTML = "<strong>" + el.dataset.stand + "</strong> — from " +
el.dataset.price + " · <span style=\"color:var(--accent)\">" + el.dataset.avail + "</span>";
}
stands.forEach(function (el) {
el.addEventListener("mouseenter", function () { showStand(el); });
el.addEventListener("focus", function () { showStand(el); });
el.addEventListener("click", function () {
showStand(el);
document.getElementById("tickets").scrollIntoView({ behavior: "smooth" });
toast(el.dataset.stand + " tickets from " + el.dataset.price);
});
});
/* ---------- generic CTA hooks ---------- */
document.querySelectorAll('.hosp__foot a').forEach(function (a) {
a.addEventListener("click", function (ev) {
ev.preventDefault();
var name = a.closest(".hosp__card").querySelector("h3").textContent;
toast("Hospitality enquiry started — " + name);
});
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Harbor Derby — Northgate United vs Riverside FC | TixGate Sports</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=Oswald:wght@500;600;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="nav">
<div class="wrap nav__inner">
<a class="brand" href="#top" aria-label="TixGate Sports home">
<span class="brand__mark" aria-hidden="true">▣</span>
<span class="brand__name">TixGate<span class="brand__accent">Sports</span></span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#tickets">Tickets</a>
<a href="#fixtures">Fixtures</a>
<a href="#seating">Seating</a>
<a href="#hospitality">Hospitality</a>
<a href="#faninfo">Fan Info</a>
</nav>
<div class="nav__actions">
<a class="btn btn--ghost" href="#tickets">Sign in</a>
<a class="btn btn--primary" href="#tickets">Buy tickets</a>
</div>
<button class="nav__toggle" id="navToggle" aria-expanded="false" aria-controls="mobileNav" aria-label="Open menu">
<span></span><span></span><span></span>
</button>
</div>
<div class="mobile-nav" id="mobileNav" hidden>
<a href="#tickets">Tickets</a>
<a href="#fixtures">Fixtures</a>
<a href="#seating">Seating</a>
<a href="#hospitality">Hospitality</a>
<a href="#faninfo">Fan Info</a>
<a class="btn btn--primary mobile-nav__cta" href="#tickets">Buy tickets</a>
</div>
</header>
<main id="main">
<a id="top"></a>
<!-- HERO -->
<section class="hero" aria-labelledby="hero-title">
<div class="hero__bg" aria-hidden="true"></div>
<div class="hero__grain" aria-hidden="true"></div>
<div class="wrap hero__inner">
<div class="hero__meta reveal">
<span class="pill pill--live">Matchday • Round 18</span>
<span class="pill pill--venue">Harbor Stadium</span>
</div>
<div class="fixture reveal">
<div class="fixture__team fixture__team--home">
<span class="crest crest--home" aria-hidden="true">NU</span>
<div class="fixture__teaminfo">
<span class="fixture__name">Northgate United</span>
<span class="fixture__form">W W D W L</span>
</div>
</div>
<div class="fixture__vs">
<span class="fixture__vslabel">VS</span>
<span class="fixture__kick">19:45 KO</span>
</div>
<div class="fixture__team fixture__team--away">
<div class="fixture__teaminfo fixture__teaminfo--right">
<span class="fixture__name">Riverside FC</span>
<span class="fixture__form">L W W D W</span>
</div>
<span class="crest crest--away" aria-hidden="true">RF</span>
</div>
</div>
<h1 id="hero-title" class="hero__title reveal">The Harbor Derby</h1>
<p class="hero__sub reveal">Saturday 27 June 2026 · Harbor Stadium, North Dock · Premier League</p>
<div class="countdown reveal" id="countdown" aria-label="Time until kickoff">
<div class="countdown__unit"><span data-cd="days">00</span><small>Days</small></div>
<div class="countdown__sep">:</div>
<div class="countdown__unit"><span data-cd="hours">00</span><small>Hrs</small></div>
<div class="countdown__sep">:</div>
<div class="countdown__unit"><span data-cd="mins">00</span><small>Min</small></div>
<div class="countdown__sep">:</div>
<div class="countdown__unit"><span data-cd="secs">00</span><small>Sec</small></div>
</div>
<div class="hero__cta reveal">
<a class="btn btn--primary btn--lg" href="#tickets">Buy by section</a>
<a class="btn btn--ghost btn--lg" href="#seating">View seating map</a>
</div>
<div class="hero__stats reveal">
<div><strong>42,180</strong><span>Capacity</span></div>
<div><strong>89%</strong><span>Sold</span></div>
<div><strong>£24+</strong><span>From</span></div>
</div>
</div>
</section>
<!-- TICKETS / BUY BY SECTION -->
<section class="section" id="tickets" aria-labelledby="tickets-title">
<div class="wrap">
<div class="section__head reveal">
<h2 id="tickets-title">Buy by section</h2>
<p>Pick your stand. Prices shown per adult ticket — concessions available at checkout.</p>
</div>
<div class="legend reveal" aria-label="Seat tier legend">
<span class="legend__item"><i class="dot dot--gold"></i>Premium</span>
<span class="legend__item"><i class="dot dot--blue"></i>Standard</span>
<span class="legend__item"><i class="dot dot--red"></i>Family</span>
<span class="legend__item"><i class="dot dot--grey"></i>Away</span>
</div>
<div class="tickets" id="ticketGrid">
<!-- cards injected by JS -->
</div>
<div class="cart-bar" id="cartBar" hidden>
<div class="cart-bar__info">
<strong id="cartCount">0 seats</strong>
<span id="cartTotal">£0.00</span>
</div>
<button class="btn btn--primary" id="checkoutBtn">Checkout</button>
</div>
</div>
</section>
<!-- FIXTURES -->
<section class="section section--alt" id="fixtures" aria-labelledby="fixtures-title">
<div class="wrap">
<div class="section__head reveal">
<h2 id="fixtures-title">Upcoming fixtures</h2>
<p>Season ticket holders get priority access 48 hours before general sale.</p>
</div>
<div class="fixtures" id="fixturesList">
<!-- rows injected by JS -->
</div>
</div>
</section>
<!-- SEATING MAP TEASER -->
<section class="section" id="seating" aria-labelledby="seating-title">
<div class="wrap seating">
<div class="seating__copy reveal">
<h2 id="seating-title">Find your seat</h2>
<p>Hover a stand to preview pricing and availability. The full interactive seat selector opens at checkout with live row-by-row inventory.</p>
<ul class="seating__list">
<li><i class="dot dot--gold"></i> North Stand — best views, padded seats</li>
<li><i class="dot dot--blue"></i> East & West — vocal home support</li>
<li><i class="dot dot--red"></i> South Family — alcohol-free zone</li>
<li><i class="dot dot--grey"></i> Lower Tier — allocated away fans</li>
</ul>
<p class="seating__hint" id="seatHint" aria-live="polite">Hover or tap a stand →</p>
</div>
<div class="pitch reveal" aria-label="Stadium seating map">
<button class="stand stand--north" data-stand="North Stand" data-price="£64" data-avail="Limited">North Stand</button>
<div class="pitch__mid">
<button class="stand stand--west" data-stand="West Stand" data-price="£42" data-avail="Good">West</button>
<div class="pitch__field"><span>HARBOR<br>STADIUM</span></div>
<button class="stand stand--east" data-stand="East Stand" data-price="£42" data-avail="Selling fast">East</button>
</div>
<button class="stand stand--south" data-stand="South Family" data-price="£24" data-avail="Good">South Family</button>
</div>
</div>
</section>
<!-- HOSPITALITY -->
<section class="section section--alt" id="hospitality" aria-labelledby="hosp-title">
<div class="wrap">
<div class="section__head reveal">
<h2 id="hosp-title">Hospitality packages</h2>
<p>Matchday hospitality with dining, premium seating and access to exclusive lounges.</p>
</div>
<div class="hosp">
<article class="hosp__card reveal">
<div class="hosp__img hosp__img--a" aria-hidden="true"></div>
<div class="hosp__body">
<h3>The Anchor Lounge</h3>
<p>Shared lounge, three-course meal, padded halfway-line seat and a complimentary first drink.</p>
<div class="hosp__foot"><span class="hosp__price">£189<small>/guest</small></span><a class="btn btn--ghost" href="#tickets">Enquire</a></div>
</div>
</article>
<article class="hosp__card hosp__card--feature reveal">
<span class="ribbon">Most popular</span>
<div class="hosp__img hosp__img--b" aria-hidden="true"></div>
<div class="hosp__body">
<h3>Captain's Table</h3>
<p>Private box for up to 10, chef-served dining, padded directors' seats and a stadium tour.</p>
<div class="hosp__foot"><span class="hosp__price">£420<small>/guest</small></span><a class="btn btn--primary" href="#tickets">Enquire</a></div>
</div>
</article>
<article class="hosp__card reveal">
<div class="hosp__img hosp__img--c" aria-hidden="true"></div>
<div class="hosp__body">
<h3>Harbour View Suite</h3>
<p>Rooftop terrace overlooking the dock, grazing buffet, open bar and premium upper-tier seating.</p>
<div class="hosp__foot"><span class="hosp__price">£275<small>/guest</small></span><a class="btn btn--ghost" href="#tickets">Enquire</a></div>
</div>
</article>
</div>
</div>
</section>
<!-- FAN INFO -->
<section class="section" id="faninfo" aria-labelledby="fan-title">
<div class="wrap">
<div class="section__head reveal">
<h2 id="fan-title">Fan info</h2>
<p>Everything you need before kickoff. Tap a question to expand.</p>
</div>
<div class="faq" id="faq">
<details class="faq__item reveal">
<summary>What time do gates open?</summary>
<p>Turnstiles open 90 minutes before kickoff at 18:15. We recommend arriving early as the Harbor Derby draws large crowds and security checks are in place at all entrances.</p>
</details>
<details class="faq__item reveal">
<summary>How do I get to Harbor Stadium?</summary>
<p>The North Dock tram stops directly outside the South Family stand. Park-and-ride is available at Pier 7 with shuttles every 10 minutes. There is no public parking at the stadium on matchdays.</p>
</details>
<details class="faq__item reveal">
<summary>What is the bag policy?</summary>
<p>Bags larger than A4 (210×297mm) are not permitted. A free bag-drop is available near the East Stand. Sealed water bottles up to 500ml are allowed.</p>
</details>
<details class="faq__item reveal">
<summary>Are tickets digital?</summary>
<p>Yes — all tickets are issued as a QR code in the TixGate app. You can transfer a ticket to a friend up to two hours before kickoff. No printouts are accepted at the turnstiles.</p>
</details>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta" aria-labelledby="cta-title">
<div class="wrap cta__inner reveal">
<div class="cta__perf" aria-hidden="true"></div>
<h2 id="cta-title">Don't miss the Harbor Derby</h2>
<p>89% sold. Lock in your seats before general sale closes.</p>
<a class="btn btn--primary btn--lg" href="#tickets">Get tickets now</a>
</div>
</section>
</main>
<footer class="footer">
<div class="wrap footer__inner">
<div class="footer__brand">
<span class="brand"><span class="brand__mark" aria-hidden="true">▣</span><span class="brand__name">TixGate<span class="brand__accent">Sports</span></span></span>
<p>Official ticketing partner of Northgate United. Fictional demo — not a real ticketing service.</p>
</div>
<nav class="footer__col" aria-label="Tickets">
<h4>Tickets</h4>
<a href="#tickets">Single match</a>
<a href="#hospitality">Hospitality</a>
<a href="#fixtures">Season tickets</a>
<a href="#tickets">Group bookings</a>
</nav>
<nav class="footer__col" aria-label="Support">
<h4>Support</h4>
<a href="#faninfo">Fan info</a>
<a href="#faninfo">Refunds</a>
<a href="#faninfo">Accessibility</a>
<a href="#faninfo">Contact</a>
</nav>
<nav class="footer__col" aria-label="Club">
<h4>Club</h4>
<a href="#top">About</a>
<a href="#fixtures">Stadium</a>
<a href="#hospitality">Sponsors</a>
<a href="#top">Careers</a>
</nav>
</div>
<div class="wrap footer__bar">
<span>© 2026 TixGate Sports · Demo data only</span>
<span class="footer__legal"><a href="#top">Terms</a> · <a href="#top">Privacy</a></span>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Sports Landing
A high-contrast matchday landing page for the fictional Harbor Derby between Northgate United and Riverside FC. The stadium hero pairs both team crests around a bold condensed VS block, surfaces the fixture, date and venue, and runs a live countdown to kickoff that ticks every second. Deep team blue, team red and white drive the energetic, competitive feel throughout.
The Buy-by-section grid renders ticket cards from data, each with a coloured tier stripe, perforated ticket edge, feature list and a stock badge (available, low stock, sold out). Adding a seat selects the card, fires a toast and updates a sticky cart bar that totals seats and price; checkout clears the selection. A clickable seating-map teaser previews per-stand pricing and availability on hover, focus or tap, and a fixtures list lets fans buy or set reminders for future matches.
Supporting sections cover hospitality packages, an accessible expandable fan-info FAQ, a closing CTA and a multi-column footer. The page is fully responsive down to ~360px with a hamburger mobile nav, uses semantic landmarks and ARIA, respects reduced-motion preferences, and reveals sections on scroll. No frameworks, no build step — just HTML, CSS and vanilla JS.
Illustrative UI only — fictional events, not a real ticketing service.