Comics — Western Superhero Comic Landing
A bold western superhero comic universe landing page with an explosive Bangers hero title, a CSS-drawn caped figure over a halftone sky with speed lines and a city skyline, a Read Issue #1 call to action, an interactive featured-heroes strip, a sliding issues-and-arcs carousel with dot navigation, a creators bullpen band, and a validated newsletter subscribe footer. Hard ink borders, Ben-Day dot textures, gold and hero-red accents, animated entrance, and a sticky comic-styled nav.
MCP
الكود
:root {
--ink: #0e0e12;
--ink-2: #23232b;
--paper: #fdfcf7;
--panel: #ffffff;
--accent: #e62329; /* hero red */
--accent-2: #ffd23f; /* gold */
--accent-blue: #1b3fa0; /* deep blue */
--muted: #6b6b78;
--line: rgba(14, 14, 18, 0.14);
--line-2: rgba(14, 14, 18, 0.28);
--halftone: radial-gradient(circle, rgba(14, 14, 18, 0.18) 1px, transparent 1.6px);
--halftone-light: radial-gradient(circle, rgba(255, 255, 255, 0.22) 1px, transparent 1.6px);
--r-sm: 6px;
--r-md: 12px;
--r-lg: 18px;
--shadow: 6px 6px 0 var(--ink);
--shadow-sm: 3px 3px 0 var(--ink);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: "Inter", system-ui, sans-serif;
font-weight: 400;
line-height: 1.5;
color: var(--ink);
background-color: var(--paper);
background-image: var(--halftone);
background-size: 7px 7px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1, h2, h3 { margin: 0; line-height: 1.05; }
p { margin: 0; }
img { max-width: 100%; display: block; }
.sr-only {
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* ===== Buttons ===== */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: .5rem;
font-family: "Inter", sans-serif;
font-weight: 800;
font-size: .95rem;
text-transform: uppercase;
letter-spacing: .04em;
text-decoration: none;
color: var(--ink);
padding: .8rem 1.3rem;
border: 3px solid var(--ink);
border-radius: var(--r-md);
background: var(--panel);
box-shadow: var(--shadow-sm);
cursor: pointer;
transition: transform .12s ease, box-shadow .12s ease, background .12s ease;
}
.btn:hover { transform: translate(-2px, -2px); box-shadow: 5px 5px 0 var(--ink); }
.btn:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--ink); }
.btn:focus-visible { outline: 3px solid var(--accent-blue); outline-offset: 3px; }
.btn--accent { background: var(--accent); color: #fff; }
.btn--blue { background: var(--accent-blue); color: #fff; }
.btn--ghost { background: var(--accent-2); }
/* ===== Nav ===== */
.nav {
position: sticky;
top: 0;
z-index: 50;
background: var(--paper);
border-bottom: 3px solid var(--ink);
transition: box-shadow .2s ease, padding .2s ease;
}
.nav.is-stuck { box-shadow: 0 6px 0 -2px var(--ink), 0 10px 24px rgba(14,14,18,.18); }
.nav__inner {
max-width: 1180px;
margin: 0 auto;
display: flex;
align-items: center;
gap: 1rem;
padding: .7rem 1.2rem;
}
.brand { display: flex; align-items: center; gap: .55rem; text-decoration: none; color: var(--ink); margin-right: auto; }
.brand__mark {
width: 38px; height: 38px;
display: grid; place-items: center;
background: var(--accent); color: #fff;
border: 3px solid var(--ink);
border-radius: var(--r-sm);
box-shadow: var(--shadow-sm);
font-size: 1.3rem;
}
.brand__name {
font-family: "Bangers", system-ui, sans-serif;
font-size: 1.7rem;
letter-spacing: 1.5px;
-webkit-text-stroke: .5px var(--ink);
}
.nav__links { display: flex; gap: 1.4rem; align-items: center; }
.nav__links a {
font-weight: 700; font-size: .92rem; text-transform: uppercase; letter-spacing: .03em;
color: var(--ink); text-decoration: none; position: relative; padding: .2rem 0;
}
.nav__links a::after {
content: ""; position: absolute; left: 0; bottom: -3px; height: 3px; width: 0;
background: var(--accent); transition: width .18s ease;
}
.nav__links a:hover::after, .nav__links a:focus-visible::after { width: 100%; }
.nav__cta { padding: .55rem .95rem; font-size: .82rem; }
.nav__burger { display: none; flex-direction: column; gap: 5px; background: none; border: 3px solid var(--ink); border-radius: var(--r-sm); padding: 8px; cursor: pointer; }
.nav__burger span { width: 22px; height: 3px; background: var(--ink); display: block; }
/* ===== Hero ===== */
.hero {
position: relative;
overflow: hidden;
border-bottom: 3px solid var(--ink);
background:
var(--halftone),
linear-gradient(160deg, var(--accent-blue) 0%, #0c1c4d 60%, #07112e 100%);
background-size: 7px 7px, cover;
}
.hero__sky { position: absolute; inset: 0; pointer-events: none; }
.speed-line {
position: absolute; left: -10%; height: 4px; width: 120%;
background: rgba(255,255,255,.5);
transform-origin: left center;
}
.speed-line:nth-child(1) { top: 12%; transform: rotate(-7deg); }
.speed-line:nth-child(2) { top: 30%; transform: rotate(-3deg); opacity: .35; height: 3px; }
.speed-line:nth-child(3) { top: 48%; transform: rotate(2deg); opacity: .25; }
.speed-line:nth-child(4) { top: 66%; transform: rotate(5deg); opacity: .4; height: 6px; }
.speed-line:nth-child(5) { top: 82%; transform: rotate(-2deg); opacity: .2; }
.hero__skyline {
position: absolute; left: 0; right: 0; bottom: 0; height: 38%;
display: flex; align-items: flex-end; gap: 1.4%;
padding: 0 2%;
pointer-events: none;
}
.hero__skyline span {
flex: 0 0 var(--w);
height: var(--h);
background: rgba(7, 12, 30, .85);
border-top: 3px solid rgba(255,255,255,.18);
border-left: 2px solid rgba(255,255,255,.08);
background-image: var(--halftone-light);
background-size: 8px 8px;
}
.hero__grid {
position: relative;
z-index: 2;
max-width: 1180px;
margin: 0 auto;
display: grid;
grid-template-columns: 1.1fr .9fr;
gap: 2rem;
align-items: center;
padding: clamp(2.5rem, 6vw, 5rem) 1.2rem;
}
.kicker {
display: inline-block;
font-weight: 800; text-transform: uppercase; letter-spacing: .12em; font-size: .78rem;
color: var(--ink);
background: var(--accent-2);
border: 3px solid var(--ink);
border-radius: 999px;
padding: .35rem .85rem;
box-shadow: var(--shadow-sm);
margin-bottom: 1rem;
}
.hero__title {
font-family: "Bangers", system-ui, sans-serif;
font-size: clamp(3.5rem, 12vw, 7.5rem);
letter-spacing: 2px;
color: var(--accent-2);
-webkit-text-stroke: 3px var(--ink);
text-shadow: 7px 7px 0 var(--accent), 9px 9px 0 var(--ink);
}
.hero__lead { color: #f4f5fb; max-width: 38ch; margin: 1.2rem 0 1.6rem; font-size: 1.05rem; }
.hero__cta { display: flex; flex-wrap: wrap; gap: .8rem; }
.hero__stats { list-style: none; display: flex; gap: 1.6rem; padding: 0; margin: 2rem 0 0; }
.hero__stats li { display: flex; flex-direction: column; color: #fff; }
.hero__stats b { font-family: "Bangers", sans-serif; font-size: 1.9rem; color: var(--accent-2); -webkit-text-stroke: 1px var(--ink); letter-spacing: 1px; }
.hero__stats span { font-size: .72rem; text-transform: uppercase; letter-spacing: .1em; font-weight: 700; opacity: .85; }
/* ===== CSS hero figure ===== */
.hero__art { display: grid; place-items: center; }
.figure {
position: relative;
width: min(320px, 70vw);
aspect-ratio: 3 / 4;
filter: drop-shadow(8px 10px 0 rgba(7,12,30,.55));
}
.figure__cape {
position: absolute; top: 14%; left: 50%; width: 62%; height: 70%;
transform: translateX(-50%) rotate(-3deg);
background: var(--accent);
border: 3px solid var(--ink);
border-radius: 50% 50% 12% 88% / 8% 8% 90% 90%;
z-index: 1;
}
.figure__body { position: absolute; inset: 0; z-index: 2; }
.figure__head {
position: absolute; top: 6%; left: 50%; transform: translateX(-50%);
width: 21%; aspect-ratio: 1; border-radius: 50%;
background: var(--accent-2); border: 3px solid var(--ink);
}
.figure__torso {
position: absolute; top: 24%; left: 50%; transform: translateX(-50%);
width: 40%; height: 38%;
background: var(--accent-blue); border: 3px solid var(--ink);
border-radius: 14px 14px 6px 6px;
display: grid; place-items: center;
}
.emblem {
font-style: normal; font-size: 2rem; color: var(--accent-2);
-webkit-text-stroke: 1.5px var(--ink);
}
.figure__arm {
position: absolute; top: 26%; width: 12%; height: 30%;
background: var(--accent-blue); border: 3px solid var(--ink); border-radius: 8px;
}
.figure__arm--l { left: 14%; transform: rotate(28deg); transform-origin: top center; }
.figure__arm--r { right: 14%; transform: rotate(-42deg); transform-origin: top center; }
.figure__leg {
position: absolute; top: 60%; width: 14%; height: 36%;
background: var(--ink-2); border: 3px solid var(--ink); border-radius: 8px;
}
.figure__leg--l { left: 32%; transform: rotate(8deg); }
.figure__leg--r { right: 32%; transform: rotate(-14deg); }
.burst {
position: absolute;
font-family: "Bangers", sans-serif;
letter-spacing: 1px;
color: var(--ink);
background: var(--accent-2);
padding: .4rem .9rem;
border: 3px solid var(--ink);
z-index: 4;
clip-path: polygon(50% 0, 63% 22%, 90% 12%, 80% 38%, 100% 50%, 80% 62%, 90% 88%, 63% 78%, 50% 100%, 37% 78%, 10% 88%, 20% 62%, 0 50%, 20% 38%, 10% 12%, 37% 22%);
padding: .9rem 1.4rem;
}
.burst--1 { top: 4%; right: -4%; font-size: 1.6rem; background: var(--accent); color: #fff; transform: rotate(8deg); }
.burst--2 { bottom: 8%; left: -8%; font-size: 1.4rem; transform: rotate(-10deg); }
.burst--3 { position: static; display: inline-block; font-size: 1.3rem; transform: rotate(-4deg); margin-bottom: .6rem; }
/* ===== Sections ===== */
.section { max-width: 1180px; margin: 0 auto; padding: clamp(2.5rem, 6vw, 4.5rem) 1.2rem; }
.section--dark {
max-width: none;
background: var(--ink);
background-image: var(--halftone-light);
background-size: 8px 8px;
border-top: 3px solid var(--ink);
border-bottom: 3px solid var(--ink);
}
.section--dark .section { padding-top: 0; padding-bottom: 0; }
.section__head { margin-bottom: 1.8rem; }
.section__head--row { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end; justify-content: space-between; max-width: 1180px; margin: 0 auto 1.8rem; padding: clamp(2.5rem,6vw,4.5rem) 1.2rem 0; }
.display {
font-family: "Bangers", sans-serif;
font-size: clamp(2.4rem, 6vw, 4rem);
letter-spacing: 2px;
color: var(--ink);
-webkit-text-stroke: 1px var(--ink);
text-shadow: 4px 4px 0 var(--accent-2);
}
.display--light { color: var(--paper); -webkit-text-stroke: 1px var(--ink); text-shadow: 4px 4px 0 var(--accent); }
.section__sub { color: var(--muted); margin-top: .6rem; font-size: 1.02rem; max-width: 48ch; }
.section__sub--light { color: rgba(255,255,255,.78); }
/* ===== Hero cards ===== */
.heroes { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1.2rem; }
.hero-card {
position: relative;
background: var(--panel);
border: 3px solid var(--ink);
border-radius: var(--r-lg);
box-shadow: var(--shadow);
overflow: hidden;
cursor: pointer;
transition: transform .14s ease, box-shadow .14s ease;
outline: none;
}
.hero-card:hover, .hero-card:focus-visible, .hero-card.is-active {
transform: translate(-3px, -3px) rotate(-.6deg);
box-shadow: 9px 9px 0 var(--ink);
}
.hero-card:focus-visible { outline: 3px solid var(--accent-blue); outline-offset: 3px; }
.hero-card__art {
height: 150px;
background: var(--c, var(--accent));
background-image: var(--halftone-light);
background-size: 9px 9px;
display: grid; place-items: center;
border-bottom: 3px solid var(--ink);
position: relative;
}
.hero-card__art::after {
content: attr(data-glyph);
font-size: 4.5rem; color: #fff;
text-shadow: 3px 3px 0 var(--ink);
transition: transform .25s ease;
}
.hero-card:hover .hero-card__art::after, .hero-card.is-active .hero-card__art::after { transform: scale(1.18) rotate(8deg); }
.hero-card__body { padding: 1rem 1.1rem 1.2rem; }
.hero-card__body h3 { font-family: "Bangers", sans-serif; font-size: 1.7rem; letter-spacing: 1px; }
.hero-card__alias { color: var(--accent-blue); font-weight: 700; font-size: .85rem; margin: .15rem 0 .5rem; }
.hero-card__power { color: var(--muted); font-size: .85rem; text-transform: uppercase; letter-spacing: .04em; font-weight: 600; }
/* ===== Issues carousel ===== */
.carousel { overflow: hidden; max-width: 1180px; margin: 0 auto; padding: 0 1.2rem; }
.carousel__nav { display: flex; gap: .6rem; }
.circ {
width: 46px; height: 46px; border-radius: 50%;
border: 3px solid var(--ink); background: var(--accent-2); color: var(--ink);
font-size: 1.5rem; font-weight: 800; line-height: 1; cursor: pointer;
box-shadow: var(--shadow-sm);
transition: transform .12s ease, box-shadow .12s ease;
}
.circ:hover { transform: translate(-2px,-2px); box-shadow: 5px 5px 0 var(--ink); }
.circ:active { transform: translate(2px,2px); box-shadow: 1px 1px 0 var(--ink); }
.circ:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.carousel__track {
list-style: none; margin: 0; padding: .4rem 0 1.4rem;
display: flex; gap: 1.2rem;
transition: transform .4s cubic-bezier(.2,.8,.2,1);
}
.issue {
flex: 0 0 calc((100% - 2.4rem) / 3);
background: var(--panel);
border: 3px solid var(--ink);
border-radius: var(--r-lg);
box-shadow: var(--shadow);
padding: 1rem;
cursor: pointer;
transition: transform .14s ease;
}
.issue:hover { transform: translateY(-4px); }
.issue__tag { display: inline-block; font-weight: 800; text-transform: uppercase; letter-spacing: .08em; font-size: .68rem; background: var(--ink); color: var(--accent-2); padding: .25rem .55rem; border-radius: 999px; }
.issue__cover {
margin: .8rem 0;
height: 180px; border-radius: var(--r-md);
border: 3px solid var(--ink);
background: var(--c, var(--accent));
background-image: var(--halftone-light);
background-size: 9px 9px;
display: grid; place-items: center;
}
.issue__no { font-family: "Bangers", sans-serif; font-size: 3rem; color: #fff; text-shadow: 4px 4px 0 var(--ink); letter-spacing: 1px; }
.issue h3 { font-family: "Bangers", sans-serif; font-size: 1.5rem; letter-spacing: .5px; }
.issue p { color: var(--muted); font-size: .9rem; margin: .3rem 0 .6rem; }
.issue__meta { font-size: .75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--accent-blue); }
.carousel__dots { display: flex; justify-content: center; gap: .5rem; padding: 1.4rem 0 clamp(2.5rem,6vw,4.5rem); }
.carousel__dots button {
width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--accent-2);
background: transparent; cursor: pointer; padding: 0;
}
.carousel__dots button[aria-selected="true"] { background: var(--accent-2); }
.carousel__dots button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
/* ===== Creators ===== */
.creators { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.1rem; }
.creator {
display: flex; align-items: center; gap: .9rem;
background: var(--panel);
border: 3px solid var(--ink); border-radius: var(--r-md);
box-shadow: var(--shadow-sm);
padding: .9rem 1rem;
transition: transform .12s ease, box-shadow .12s ease;
}
.creator:hover { transform: translate(-2px,-2px); box-shadow: 5px 5px 0 var(--ink); }
.creator__avatar {
flex: 0 0 auto;
width: 52px; height: 52px; display: grid; place-items: center;
font-family: "Bangers", sans-serif; font-size: 1.3rem; letter-spacing: 1px;
background: var(--accent-blue); color: #fff;
border: 3px solid var(--ink); border-radius: 50%;
}
.creator h3 { font-size: 1.05rem; font-weight: 800; }
.creator p { color: var(--muted); font-size: .85rem; }
/* ===== Subscribe footer ===== */
.subscribe {
background: var(--accent);
background-image: var(--halftone-light);
background-size: 8px 8px;
border-top: 3px solid var(--ink);
color: #fff;
}
.subscribe__inner {
max-width: 1180px; margin: 0 auto;
display: grid; grid-template-columns: 1.1fr .9fr; gap: 2rem; align-items: center;
padding: clamp(2.5rem, 6vw, 4rem) 1.2rem;
}
.subscribe__copy h2 { color: var(--accent-2); }
.subscribe__copy p { margin-top: .8rem; max-width: 40ch; font-size: 1.05rem; }
.subscribe__form { display: grid; grid-template-columns: 1fr auto; gap: .7rem; }
.subscribe__form input {
font: inherit; padding: .9rem 1rem;
border: 3px solid var(--ink); border-radius: var(--r-md);
background: #fff; color: var(--ink);
}
.subscribe__form input:focus-visible { outline: 3px solid var(--accent-2); outline-offset: 2px; }
.subscribe__error { grid-column: 1 / -1; font-weight: 700; color: var(--ink); background: var(--accent-2); border: 2px solid var(--ink); border-radius: var(--r-sm); padding: .4rem .7rem; font-size: .85rem; }
.subscribe__legal { text-align: center; font-size: .78rem; padding: 0 1.2rem 1.4rem; opacity: .9; }
/* ===== Toast ===== */
.toast {
position: fixed; left: 50%; bottom: 1.4rem; transform: translate(-50%, 150%);
z-index: 100;
font-weight: 800; text-transform: uppercase; letter-spacing: .04em; font-size: .9rem;
background: var(--ink); color: var(--accent-2);
border: 3px solid var(--accent-2); border-radius: var(--r-md);
padding: .8rem 1.2rem; box-shadow: var(--shadow-sm);
opacity: 0; transition: transform .3s cubic-bezier(.2,.9,.2,1.2), opacity .3s ease;
max-width: 90vw;
}
.toast.is-show { transform: translate(-50%, 0); opacity: 1; }
/* ===== Reveal animation ===== */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity .6s ease, transform .6s ease; }
.reveal.is-in { opacity: 1; transform: none; }
/* ===== Responsive ===== */
@media (max-width: 900px) {
.hero__grid, .subscribe__inner { grid-template-columns: 1fr; }
.hero__art { order: -1; }
.hero__title { text-shadow: 5px 5px 0 var(--accent), 6px 6px 0 var(--ink); }
.issue { flex-basis: calc((100% - 1.2rem) / 2); }
}
@media (max-width: 720px) {
.nav__links { display: none; }
.nav__links.is-open {
display: flex; flex-direction: column; align-items: flex-start; gap: .9rem;
position: absolute; top: 100%; left: 0; right: 0;
background: var(--paper); border-bottom: 3px solid var(--ink);
padding: 1rem 1.2rem;
}
.nav__burger { display: flex; }
.nav__cta { display: none; }
}
@media (max-width: 520px) {
body { background-size: 6px 6px; }
.hero__grid { padding: 2rem 1rem; }
.hero__stats { gap: 1.1rem; }
.issue { flex-basis: 100%; }
.subscribe__form { grid-template-columns: 1fr; }
.subscribe__form .btn { width: 100%; }
.figure { width: min(240px, 80vw); }
.section__head--row { padding-top: 2.2rem; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation: none !important; transition: none !important; }
.reveal { opacity: 1; transform: none; }
html { scroll-behavior: auto; }
}(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");
window.clearTimeout(toastTimer);
toastTimer = window.setTimeout(function () {
toastEl.classList.remove("is-show");
}, 2600);
}
/* ---------- Generic [data-toast] triggers ---------- */
document.querySelectorAll("[data-toast]").forEach(function (el) {
el.addEventListener("click", function () {
toast(el.getAttribute("data-toast"));
});
});
/* ---------- Sticky nav shadow ---------- */
var nav = document.getElementById("nav");
function onScroll() {
if (!nav) return;
nav.classList.toggle("is-stuck", window.scrollY > 8);
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- Mobile burger menu ---------- */
var burger = document.getElementById("burger");
var links = document.querySelector(".nav__links");
if (burger && links) {
burger.addEventListener("click", function () {
var open = links.classList.toggle("is-open");
burger.setAttribute("aria-expanded", String(open));
});
links.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
links.classList.remove("is-open");
burger.setAttribute("aria-expanded", "false");
});
});
}
/* ---------- Hero / scroll reveal entrance ---------- */
var revealEls = document.querySelectorAll("[data-reveal]");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("is-in");
io.unobserve(entry.target);
}
});
},
{ threshold: 0.2 }
);
revealEls.forEach(function (el, i) {
el.style.transitionDelay = i * 120 + "ms";
io.observe(el);
});
} else {
revealEls.forEach(function (el) {
el.classList.add("is-in");
});
}
/* ---------- Hero card active toggle (touch friendly) ---------- */
document.querySelectorAll(".hero-card").forEach(function (card) {
function activate() {
document.querySelectorAll(".hero-card.is-active").forEach(function (c) {
if (c !== card) c.classList.remove("is-active");
});
card.classList.toggle("is-active");
if (card.classList.contains("is-active")) {
var name = card.querySelector("h3");
toast("Recruited " + (name ? name.textContent : "hero") + " to your team!");
}
}
card.addEventListener("click", activate);
card.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
activate();
}
});
});
/* ---------- Issue carousel ---------- */
var track = document.getElementById("track");
var prevBtn = document.getElementById("prevBtn");
var nextBtn = document.getElementById("nextBtn");
var dotsWrap = document.getElementById("dots");
if (track && prevBtn && nextBtn) {
var items = Array.prototype.slice.call(track.children);
function perView() {
if (window.innerWidth <= 520) return 1;
if (window.innerWidth <= 900) return 2;
return 3;
}
var index = 0;
function pages() {
return Math.max(1, items.length - perView() + 1);
}
function clamp() {
index = Math.max(0, Math.min(index, pages() - 1));
}
function update() {
clamp();
var item = items[0];
var gap = parseFloat(getComputedStyle(track).columnGap || "0") || 19;
var step = item.getBoundingClientRect().width + gap;
track.style.transform = "translateX(" + -(index * step) + "px)";
buildDots();
prevBtn.disabled = index === 0;
nextBtn.disabled = index >= pages() - 1;
prevBtn.style.opacity = prevBtn.disabled ? ".4" : "1";
nextBtn.style.opacity = nextBtn.disabled ? ".4" : "1";
}
function buildDots() {
if (!dotsWrap) return;
var total = pages();
if (dotsWrap.childElementCount !== total) {
dotsWrap.innerHTML = "";
for (var i = 0; i < total; i++) {
var b = document.createElement("button");
b.type = "button";
b.setAttribute("role", "tab");
b.setAttribute("aria-label", "Go to issue group " + (i + 1));
(function (n) {
b.addEventListener("click", function () {
index = n;
update();
});
})(i);
dotsWrap.appendChild(b);
}
}
Array.prototype.forEach.call(dotsWrap.children, function (dot, i) {
dot.setAttribute("aria-selected", String(i === index));
});
}
nextBtn.addEventListener("click", function () {
index++;
update();
});
prevBtn.addEventListener("click", function () {
index--;
update();
});
var rt;
window.addEventListener("resize", function () {
window.clearTimeout(rt);
rt = window.setTimeout(update, 150);
});
update();
}
/* ---------- Subscribe form validation ---------- */
var form = document.getElementById("subForm");
var emailInput = document.getElementById("email");
var errEl = document.getElementById("subError");
if (form && emailInput) {
form.addEventListener("submit", function (e) {
e.preventDefault();
var ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailInput.value.trim());
if (!ok) {
if (errEl) errEl.hidden = false;
emailInput.focus();
return;
}
if (errEl) errEl.hidden = true;
toast("KAPOW! You're on the pull list — variant cover incoming.");
form.reset();
});
emailInput.addEventListener("input", function () {
if (errEl) errEl.hidden = true;
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Iron Vanguard — Comic Universe</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=Bangers&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- ===== Sticky nav ===== -->
<header class="nav" id="nav">
<div class="nav__inner">
<a class="brand" href="#top" aria-label="Iron Vanguard home">
<span class="brand__mark" aria-hidden="true">★</span>
<span class="brand__name">Iron Vanguard</span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#heroes">Heroes</a>
<a href="#issues">Issues</a>
<a href="#creators">Creators</a>
<a href="#subscribe">Subscribe</a>
</nav>
<button class="btn btn--ghost nav__cta" type="button" data-toast="Pull list updated! Issue #1 reserved.">Pull List</button>
<button class="nav__burger" type="button" aria-label="Toggle menu" aria-expanded="false" id="burger">
<span></span><span></span><span></span>
</button>
</div>
</header>
<main id="top">
<!-- ===== Hero ===== -->
<section class="hero" aria-labelledby="hero-title">
<div class="hero__sky" aria-hidden="true">
<span class="speed-line"></span>
<span class="speed-line"></span>
<span class="speed-line"></span>
<span class="speed-line"></span>
<span class="speed-line"></span>
</div>
<div class="hero__skyline" aria-hidden="true">
<span style="--h:62%;--w:9%"></span>
<span style="--h:88%;--w:7%"></span>
<span style="--h:50%;--w:11%"></span>
<span style="--h:100%;--w:8%"></span>
<span style="--h:72%;--w:6%"></span>
<span style="--h:94%;--w:10%"></span>
<span style="--h:58%;--w:7%"></span>
<span style="--h:80%;--w:9%"></span>
<span style="--h:46%;--w:8%"></span>
</div>
<div class="hero__grid">
<div class="hero__copy reveal" data-reveal>
<p class="kicker">The official universe · Earth-77</p>
<h1 class="hero__title" id="hero-title">Iron<br />Vanguard</h1>
<p class="hero__lead">
When the Gravity Syndicate cracks the sky over New Halcyon, only a
ragtag squad of misfit super-humans stands between the city and the
void. Bold ink. Big punches. Bigger consequences.
</p>
<div class="hero__cta">
<button class="btn btn--accent" type="button" data-toast="Loading Issue #1: Sky Breaker…">Read Issue #1</button>
<a class="btn btn--blue" href="#issues">Browse the Series</a>
</div>
<ul class="hero__stats">
<li><b>42</b><span>Issues</span></li>
<li><b>9</b><span>Heroes</span></li>
<li><b>3.1M</b><span>Readers</span></li>
</ul>
</div>
<!-- CSS-drawn hero pose -->
<div class="hero__art reveal" data-reveal aria-hidden="true">
<div class="figure">
<span class="burst burst--1">POW!</span>
<span class="burst burst--2">BOOM</span>
<div class="figure__cape"></div>
<div class="figure__body">
<span class="figure__head"></span>
<span class="figure__torso"><i class="emblem">★</i></span>
<span class="figure__arm figure__arm--l"></span>
<span class="figure__arm figure__arm--r"></span>
<span class="figure__leg figure__leg--l"></span>
<span class="figure__leg figure__leg--r"></span>
</div>
</div>
</div>
</div>
</section>
<!-- ===== Featured heroes strip ===== -->
<section class="section" id="heroes" aria-labelledby="heroes-title">
<div class="section__head">
<h2 class="display" id="heroes-title">The Vanguard</h2>
<p class="section__sub">Nine heroes. One fragile city. Tap a card to meet the roster.</p>
</div>
<div class="heroes" id="heroesGrid">
<article class="hero-card" tabindex="0" data-color="#e62329">
<div class="hero-card__art" data-glyph="⚡"></div>
<div class="hero-card__body">
<h3>Voltspur</h3>
<p class="hero-card__alias">Maya Okonkwo</p>
<p class="hero-card__power">Kinetic lightning · Speed</p>
</div>
</article>
<article class="hero-card" tabindex="0" data-color="#1b3fa0">
<div class="hero-card__art" data-glyph="❄"></div>
<div class="hero-card__body">
<h3>Coldfront</h3>
<p class="hero-card__alias">Dr. Ezra Vael</p>
<p class="hero-card__power">Cryo-fields · Strategy</p>
</div>
</article>
<article class="hero-card" tabindex="0" data-color="#ffd23f">
<div class="hero-card__art" data-glyph="★"></div>
<div class="hero-card__body">
<h3>Goldcrest</h3>
<p class="hero-card__alias">Captain Rae Soto</p>
<p class="hero-card__power">Solar armor · Flight</p>
</div>
</article>
<article class="hero-card" tabindex="0" data-color="#0e0e12">
<div class="hero-card__art" data-glyph="◑"></div>
<div class="hero-card__body">
<h3>Nightframe</h3>
<p class="hero-card__alias">Unknown</p>
<p class="hero-card__power">Shadow-step · Stealth</p>
</div>
</article>
<article class="hero-card" tabindex="0" data-color="#e62329">
<div class="hero-card__art" data-glyph="✦"></div>
<div class="hero-card__body">
<h3>Quasar Kid</h3>
<p class="hero-card__alias">Theo Park</p>
<p class="hero-card__power">Gravity wells · Genius</p>
</div>
</article>
<article class="hero-card" tabindex="0" data-color="#1b3fa0">
<div class="hero-card__art" data-glyph="≋"></div>
<div class="hero-card__body">
<h3>Tidewall</h3>
<p class="hero-card__alias">Imani Reyes</p>
<p class="hero-card__power">Hydro-kinesis · Healing</p>
</div>
</article>
</div>
</section>
<!-- ===== Issues carousel ===== -->
<section class="section section--dark" id="issues" aria-labelledby="issues-title">
<div class="section__head section__head--row">
<div>
<h2 class="display display--light" id="issues-title">Issues & Arcs</h2>
<p class="section__sub section__sub--light">Drawn weekly. Lettered loud. Start at #1 or jump into the latest arc.</p>
</div>
<div class="carousel__nav" aria-hidden="false">
<button class="circ" type="button" id="prevBtn" aria-label="Previous issues">‹</button>
<button class="circ" type="button" id="nextBtn" aria-label="Next issues">›</button>
</div>
</div>
<div class="carousel" aria-roledescription="carousel" aria-label="Comic issues">
<ul class="carousel__track" id="track">
<li class="issue" data-toast="Added Issue #1 to your pull list."><span class="issue__tag">Arc 1</span><div class="issue__cover" style="--c:#e62329"><span class="issue__no">#1</span></div><h3>Sky Breaker</h3><p>The first crack in the heavens.</p><span class="issue__meta">32 pp · New</span></li>
<li class="issue" data-toast="Added Issue #2 to your pull list."><span class="issue__tag">Arc 1</span><div class="issue__cover" style="--c:#1b3fa0"><span class="issue__no">#2</span></div><h3>Gravity Falls Up</h3><p>Voltspur meets the Syndicate.</p><span class="issue__meta">28 pp</span></li>
<li class="issue" data-toast="Added Issue #3 to your pull list."><span class="issue__tag">Arc 1</span><div class="issue__cover" style="--c:#ffd23f"><span class="issue__no">#3</span></div><h3>Goldcrest Rising</h3><p>A hero forged in solar fire.</p><span class="issue__meta">30 pp</span></li>
<li class="issue" data-toast="Added Issue #4 to your pull list."><span class="issue__tag">Arc 2</span><div class="issue__cover" style="--c:#0e0e12"><span class="issue__no">#4</span></div><h3>Into the Frame</h3><p>Nightframe's debut, in shadow.</p><span class="issue__meta">36 pp</span></li>
<li class="issue" data-toast="Added Issue #5 to your pull list."><span class="issue__tag">Arc 2</span><div class="issue__cover" style="--c:#e62329"><span class="issue__no">#5</span></div><h3>Quasar Protocol</h3><p>One genius. One impossible bomb.</p><span class="issue__meta">34 pp</span></li>
<li class="issue" data-toast="Added Issue #6 to your pull list."><span class="issue__tag">Arc 2</span><div class="issue__cover" style="--c:#1b3fa0"><span class="issue__no">#6</span></div><h3>Tidewall Holds</h3><p>The sea answers the call.</p><span class="issue__meta">29 pp</span></li>
<li class="issue" data-toast="Added Issue #7 to your pull list."><span class="issue__tag">Arc 3</span><div class="issue__cover" style="--c:#ffd23f"><span class="issue__no">#7</span></div><h3>Halcyon Burning</h3><p>The city falls. The Vanguard rises.</p><span class="issue__meta">40 pp · Finale</span></li>
</ul>
</div>
<div class="carousel__dots" id="dots" role="tablist" aria-label="Issue pages"></div>
</section>
<!-- ===== Creators band ===== -->
<section class="section" id="creators" aria-labelledby="creators-title">
<div class="section__head">
<h2 class="display" id="creators-title">The Bullpen</h2>
<p class="section__sub">The humans behind the heroes.</p>
</div>
<div class="creators">
<article class="creator"><span class="creator__avatar">JR</span><div><h3>Jules Reyna</h3><p>Writer & Co-Creator</p></div></article>
<article class="creator"><span class="creator__avatar">DK</span><div><h3>Devi Kapoor</h3><p>Lead Penciller</p></div></article>
<article class="creator"><span class="creator__avatar">MO</span><div><h3>Marco Oduya</h3><p>Inks & Colors</p></div></article>
<article class="creator"><span class="creator__avatar">SL</span><div><h3>Sam Liang</h3><p>Letterer & SFX</p></div></article>
</div>
</section>
</main>
<!-- ===== Subscribe footer ===== -->
<footer class="subscribe" id="subscribe">
<div class="subscribe__inner">
<div class="subscribe__copy">
<span class="burst burst--3" aria-hidden="true">NEW!</span>
<h2 class="display display--light">Never miss a drop</h2>
<p>New issues hit every Friday at 9AM. Get a first-look variant cover in your inbox.</p>
</div>
<form class="subscribe__form" id="subForm" novalidate>
<label class="sr-only" for="email">Email address</label>
<input id="email" type="email" name="email" placeholder="[email protected]" autocomplete="email" required />
<button class="btn btn--accent" type="submit">Subscribe</button>
<p class="subscribe__error" id="subError" role="alert" hidden>Enter a valid email to join the pull list.</p>
</form>
</div>
<p class="subscribe__legal">Iron Vanguard™ is a fictional comic universe. © Earth-77 Comics. Illustrative UI only.</p>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Western Superhero Comic Landing
A full marketing landing page for Iron Vanguard, a fictional western-style superhero universe. The hero section pairs a giant Bangers title with a fully CSS-drawn caped figure, SFX bursts (POW! / BOOM), white speed lines and a halftone city skyline rendered over a deep comic-blue sky. A red “Read Issue #1” button and a blue “Browse the Series” link anchor the call to action, with a quick stats row underneath.
Below the fold, a featured-heroes strip presents the roster as ink-bordered cards with Ben-Day-dot art tiles, hover lift, and a click/keyboard “recruit” toggle. An issues-and-arcs section runs on a dark halftone panel with a sliding carousel — previous/next circle buttons, auto-generated dot pagination, and per-issue covers — that adapts how many cards show across breakpoints. A creators “bullpen” band and a subscribe footer round it out.
Interactions are vanilla JS only: an IntersectionObserver staggers the hero entrance, the nav
gains a hard drop-shadow once you scroll, a burger menu drives the mobile nav, the carousel
clamps and re-measures on resize, the subscribe form validates the email and fires a toast, and
a shared toast() helper surfaces feedback throughout. The layout reflows cleanly down to ~360px
and respects prefers-reduced-motion.
Illustrative UI only — fictional series, characters, and data.