Game — Game Landing (trailer · wishlist CTA)
AAA game landing page for the fictional title Hollow Reign by Nullforge Studios: a full-bleed hero with a CSS-drawn key-art scene (moon, ridgelines, citadel, glowing warden, rising embers), Orbitron display title, trailer lightbox with focus trap, synced wishlist toggle with live count, platform badges, a four-pillar features grid, an auto-advancing screenshot carousel with dots and arrows, a three-tier editions band, and a newsletter signup — all neon-glow dark UI in HTML, CSS, and vanilla JS.
MCP
Code
:root {
--bg: #0a0b10;
--bg-2: #12131c;
--panel: #171926;
--panel-2: #1f2233;
--text: #e7e9f3;
--muted: #9aa0bf;
--line: rgba(231, 233, 243, 0.1);
--line-2: rgba(231, 233, 243, 0.18);
--accent: #00e5ff;
--accent-2: #7c4dff;
--accent-3: #ff3d71;
--success: #36e27a;
--warn: #ffc857;
--danger: #ff4d4d;
--glow: 0 0 18px rgba(0, 229, 255, 0.45);
--r-sm: 6px;
--r-md: 10px;
--r-lg: 16px;
--font-display: "Orbitron", sans-serif;
--font-body: "Inter", sans-serif;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: var(--font-body);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
img, svg { 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;
}
.wrap { max-width: 1120px; margin: 0 auto; padding: 0 24px; }
/* ===== Buttons ===== */
.btn {
display: inline-flex; align-items: center; gap: 9px;
font-family: var(--font-display);
font-weight: 700; font-size: 0.82rem; letter-spacing: 0.09em;
text-transform: uppercase; text-decoration: none;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
padding: 13px 24px;
cursor: pointer;
clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
transition: transform 0.15s ease, box-shadow 0.2s ease, background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn:focus-visible,
a:focus-visible,
button:focus-visible,
input:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
.btn--accent {
background: linear-gradient(135deg, var(--accent) 0%, #00b3d6 100%);
border-color: transparent;
color: #04141a;
box-shadow: var(--glow);
}
.btn--accent:hover { box-shadow: 0 0 28px rgba(0, 229, 255, 0.65); }
.btn--outline {
background: rgba(0, 229, 255, 0.06);
border-color: rgba(0, 229, 255, 0.45);
color: var(--accent);
}
.btn--outline:hover { background: rgba(0, 229, 255, 0.14); box-shadow: var(--glow); }
.btn--ghost {
background: transparent;
border-color: var(--line);
color: var(--muted);
}
.btn--ghost:hover { color: var(--text); border-color: var(--line-2); }
.btn--sm { padding: 9px 16px; font-size: 0.7rem; }
.btn--lg { padding: 16px 32px; font-size: 0.95rem; }
.btn--block { width: 100%; justify-content: center; }
.btn.is-wishlisted {
border-color: var(--accent-3);
color: var(--accent-3);
background: rgba(255, 61, 113, 0.1);
box-shadow: 0 0 18px rgba(255, 61, 113, 0.35);
}
.btn.is-wishlisted svg { fill: var(--accent-3); stroke: var(--accent-3); animation: heartPop 0.35s ease; }
@keyframes heartPop {
0% { transform: scale(1); }
45% { transform: scale(1.45); }
100% { transform: scale(1); }
}
/* ===== Nav ===== */
.nav {
position: fixed; inset: 0 0 auto 0; z-index: 60;
padding: 14px 0;
transition: background 0.3s ease, padding 0.3s ease, box-shadow 0.3s ease;
}
.nav.is-scrolled {
background: rgba(10, 11, 16, 0.88);
backdrop-filter: blur(12px);
padding: 8px 0;
box-shadow: 0 1px 0 var(--line), 0 14px 36px rgba(0, 0, 0, 0.5);
}
.nav__inner {
max-width: 1120px; margin: 0 auto; padding: 0 24px;
display: flex; align-items: center; gap: 28px;
}
.nav__brand {
display: inline-flex; align-items: center; gap: 10px;
text-decoration: none; color: var(--text);
}
.nav__sigil {
width: 26px; height: 26px;
background: conic-gradient(from 200deg, var(--accent), var(--accent-2), var(--accent));
clip-path: polygon(50% 0, 100% 28%, 82% 100%, 18% 100%, 0 28%);
box-shadow: var(--glow);
}
.nav__name {
font-family: var(--font-display); font-weight: 900;
font-size: 0.95rem; letter-spacing: 0.14em;
}
.nav__name i { font-style: normal; color: var(--accent); }
.nav__links { display: flex; gap: 22px; margin-left: auto; }
.nav__links a {
color: var(--muted); text-decoration: none;
font-size: 0.8rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
transition: color 0.2s ease, text-shadow 0.2s ease;
}
.nav__links a:hover { color: var(--accent); text-shadow: 0 0 12px rgba(0, 229, 255, 0.6); }
.nav__cta { display: flex; gap: 10px; align-items: center; }
.nav__count {
font-family: var(--font-body); font-weight: 700; font-size: 0.66rem;
background: rgba(0, 229, 255, 0.12); color: var(--accent);
padding: 2px 7px; border-radius: 999px;
}
/* ===== Hero ===== */
.hero {
position: relative; min-height: 100svh;
display: grid; place-items: center;
overflow: hidden; isolation: isolate;
}
.hero__art { position: absolute; inset: 0; z-index: -1; }
.hero__art > * { position: absolute; }
.sky {
inset: 0;
background:
radial-gradient(120% 70% at 70% 18%, rgba(124, 77, 255, 0.28), transparent 60%),
radial-gradient(90% 60% at 25% 80%, rgba(0, 229, 255, 0.12), transparent 65%),
linear-gradient(180deg, #0b0d1d 0%, #10122a 45%, #0a0b10 100%);
}
.stars {
inset: 0;
background-image:
radial-gradient(1.5px 1.5px at 12% 22%, #fff 50%, transparent 51%),
radial-gradient(1px 1px at 28% 12%, rgba(255,255,255,0.8) 50%, transparent 51%),
radial-gradient(1.5px 1.5px at 44% 30%, rgba(255,255,255,0.9) 50%, transparent 51%),
radial-gradient(1px 1px at 61% 9%, rgba(255,255,255,0.7) 50%, transparent 51%),
radial-gradient(2px 2px at 76% 24%, #fff 50%, transparent 51%),
radial-gradient(1px 1px at 88% 14%, rgba(255,255,255,0.85) 50%, transparent 51%),
radial-gradient(1.5px 1.5px at 93% 38%, rgba(255,255,255,0.7) 50%, transparent 51%),
radial-gradient(1px 1px at 7% 42%, rgba(255,255,255,0.6) 50%, transparent 51%);
animation: twinkle 5s ease-in-out infinite alternate;
}
@keyframes twinkle { from { opacity: 0.55; } to { opacity: 1; } }
.moon {
top: 9%; right: 14%; width: 130px; height: 130px; border-radius: 50%;
background: radial-gradient(circle at 35% 35%, #cfe7ff 0%, #7d9bd8 55%, #44528f 100%);
box-shadow: 0 0 70px 22px rgba(150, 180, 255, 0.28);
opacity: 0.9;
}
.ridge { left: 0; right: 0; bottom: 0; }
.ridge--far {
height: 42%;
background: #1a1c33;
clip-path: polygon(0 62%, 8% 48%, 17% 58%, 27% 36%, 38% 55%, 50% 30%, 60% 52%, 72% 38%, 84% 56%, 93% 44%, 100% 58%, 100% 100%, 0 100%);
opacity: 0.8;
}
.ridge--mid {
height: 34%;
background: #13152a;
clip-path: polygon(0 55%, 11% 38%, 22% 56%, 35% 30%, 47% 54%, 58% 40%, 70% 58%, 81% 34%, 92% 52%, 100% 42%, 100% 100%, 0 100%);
}
.ridge--near {
height: 22%;
background: #0a0b13;
clip-path: polygon(0 45%, 14% 62%, 28% 40%, 44% 64%, 57% 46%, 73% 66%, 86% 48%, 100% 60%, 100% 100%, 0 100%);
}
.citadel { left: 50%; bottom: 18%; transform: translateX(-50%); width: 260px; height: 300px; }
.citadel i { position: absolute; bottom: 0; }
.spire { background: linear-gradient(180deg, #2a2d4d 0%, #15172b 100%); }
.spire--1 { left: 28px; width: 56px; height: 180px; clip-path: polygon(50% 0, 100% 14%, 100% 100%, 0 100%, 0 14%); }
.spire--2 { left: 96px; width: 70px; height: 280px; clip-path: polygon(50% 0, 100% 10%, 100% 100%, 0 100%, 0 10%); }
.spire--3 { left: 180px; width: 52px; height: 210px; clip-path: polygon(50% 0, 100% 14%, 100% 100%, 0 100%, 0 14%); }
.beacon {
left: 124px; bottom: 272px; width: 14px; height: 14px; border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 24px 8px rgba(0, 229, 255, 0.7);
animation: beaconPulse 2.4s ease-in-out infinite;
}
@keyframes beaconPulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.35); opacity: 0.65; }
}
.fog {
left: 0; right: 0; bottom: 0; height: 30%;
background: linear-gradient(180deg, transparent, rgba(124, 77, 255, 0.1) 40%, rgba(10, 11, 16, 0.9));
}
.warden { left: 12%; bottom: 7%; width: 120px; height: 230px; opacity: 0.92; }
.warden i { position: absolute; }
.warden__cloak {
left: 18px; bottom: 0; width: 84px; height: 180px;
background: linear-gradient(180deg, #1c1f38 0%, #0c0d18 100%);
clip-path: polygon(38% 0, 62% 0, 86% 30%, 100% 100%, 0 100%, 14% 30%);
}
.warden__head {
left: 47px; bottom: 168px; width: 26px; height: 30px;
background: #232746;
clip-path: polygon(50% 0, 100% 35%, 84% 100%, 16% 100%, 0 35%);
box-shadow: inset 0 -7px 0 rgba(0, 229, 255, 0.8);
}
.warden__blade {
left: 99px; bottom: 24px; width: 7px; height: 175px;
background: linear-gradient(180deg, var(--accent) 0%, rgba(0, 229, 255, 0.15) 90%);
clip-path: polygon(50% 0, 100% 6%, 100% 100%, 0 100%, 0 6%);
box-shadow: 0 0 18px rgba(0, 229, 255, 0.65);
animation: bladeHum 3.2s ease-in-out infinite;
}
@keyframes bladeHum {
0%, 100% { box-shadow: 0 0 14px rgba(0, 229, 255, 0.5); }
50% { box-shadow: 0 0 30px rgba(0, 229, 255, 0.9); }
}
.embers { inset: 0; pointer-events: none; }
.embers i {
position: absolute; bottom: -10px;
width: 4px; height: 4px; border-radius: 50%;
background: var(--accent-3);
box-shadow: 0 0 8px rgba(255, 61, 113, 0.8);
animation: emberRise 9s linear infinite;
opacity: 0;
}
.embers i:nth-child(1) { left: 8%; animation-delay: 0s; }
.embers i:nth-child(2) { left: 18%; animation-delay: 1.4s; animation-duration: 11s; }
.embers i:nth-child(3) { left: 31%; animation-delay: 3s; }
.embers i:nth-child(4) { left: 42%; animation-delay: 0.7s; animation-duration: 8s; }
.embers i:nth-child(5) { left: 55%; animation-delay: 2.2s; }
.embers i:nth-child(6) { left: 63%; animation-delay: 4.5s; animation-duration: 12s; }
.embers i:nth-child(7) { left: 72%; animation-delay: 1s; }
.embers i:nth-child(8) { left: 81%; animation-delay: 3.6s; animation-duration: 10s; }
.embers i:nth-child(9) { left: 90%; animation-delay: 0.3s; }
.embers i:nth-child(10) { left: 96%; animation-delay: 5s; animation-duration: 9s; }
@keyframes emberRise {
0% { transform: translateY(0) translateX(0); opacity: 0; }
8% { opacity: 0.9; }
60% { opacity: 0.7; }
100% { transform: translateY(-92vh) translateX(36px); opacity: 0; }
}
.hero__vignette {
inset: 0;
background: radial-gradient(95% 80% at 50% 45%, transparent 45%, rgba(5, 6, 10, 0.78) 100%);
}
.hero__content {
position: relative; z-index: 1;
text-align: center; padding: 130px 24px 100px;
max-width: 880px;
}
.hero__studio {
font-family: var(--font-display); font-weight: 500; font-size: 0.78rem;
letter-spacing: 0.5em; color: var(--muted); margin: 0 0 18px;
}
.hero__title {
font-family: var(--font-display); font-weight: 900;
font-size: clamp(2.8rem, 9vw, 5.6rem);
letter-spacing: 0.06em; line-height: 1.04; margin: 0;
text-shadow: 0 0 40px rgba(0, 229, 255, 0.25), 0 6px 30px rgba(0, 0, 0, 0.7);
}
.hero__title span {
background: linear-gradient(100deg, var(--accent) 10%, var(--accent-2) 90%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
filter: drop-shadow(0 0 22px rgba(0, 229, 255, 0.4));
}
.hero__tag {
color: var(--muted); font-size: 1.06rem; font-weight: 500;
max-width: 560px; margin: 20px auto 32px;
}
.hero__actions {
display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;
}
.hero__meta {
margin-top: 38px;
display: flex; align-items: center; justify-content: center; gap: 26px; flex-wrap: wrap;
}
.hero__date {
font-family: var(--font-display); font-size: 0.8rem; letter-spacing: 0.22em; color: var(--muted);
}
.hero__date strong { color: var(--text); }
.platforms { display: flex; gap: 8px; list-style: none; margin: 0; padding: 0; }
.chip {
display: inline-block;
font-family: var(--font-display); font-size: 0.62rem; font-weight: 700; letter-spacing: 0.12em;
color: var(--text);
border: 1px solid var(--line-2);
background: rgba(231, 233, 243, 0.05);
padding: 6px 11px;
clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
li:hover > .chip { border-color: var(--accent); box-shadow: var(--glow); }
.hero__scroll {
position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%);
width: 26px; height: 44px;
border: 2px solid var(--line-2); border-radius: 14px;
display: grid; justify-content: center; padding-top: 8px;
}
.hero__scroll span {
width: 4px; height: 9px; border-radius: 2px;
background: var(--accent);
box-shadow: var(--glow);
animation: scrollNudge 1.8s ease-in-out infinite;
}
@keyframes scrollNudge {
0%, 100% { transform: translateY(0); opacity: 1; }
60% { transform: translateY(12px); opacity: 0.2; }
}
/* ===== Sections ===== */
.section { padding: 96px 0; }
.section__head { margin-bottom: 44px; }
.kicker {
font-family: var(--font-display); font-weight: 700; font-size: 0.72rem;
letter-spacing: 0.3em; color: var(--accent); margin: 0 0 10px;
}
.section__title {
font-family: var(--font-display); font-weight: 700;
font-size: clamp(1.5rem, 4vw, 2.3rem); letter-spacing: 0.05em; margin: 0;
}
/* ===== Features ===== */
.features { background: linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%); }
.features__grid {
display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 18px;
}
.feature {
position: relative;
background: linear-gradient(160deg, var(--panel) 0%, var(--bg-2) 100%);
border: 1px solid var(--line);
padding: 26px 22px 30px;
clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 14px), calc(100% - 14px) 100%, 0 100%, 0 14px);
transition: transform 0.2s ease, border-color 0.25s ease, box-shadow 0.25s ease;
overflow: hidden;
}
.feature:hover {
transform: translateY(-5px);
border-color: rgba(0, 229, 255, 0.5);
box-shadow: 0 0 0 1px rgba(0, 229, 255, 0.2), var(--glow);
}
.feature__icon {
width: 52px; height: 52px;
display: grid; place-items: center;
color: var(--accent);
background: rgba(0, 229, 255, 0.09);
border: 1px solid rgba(0, 229, 255, 0.35);
clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
margin-bottom: 18px;
}
.feature__icon--violet { color: var(--accent-2); background: rgba(124, 77, 255, 0.12); border-color: rgba(124, 77, 255, 0.4); }
.feature__icon--rose { color: var(--accent-3); background: rgba(255, 61, 113, 0.1); border-color: rgba(255, 61, 113, 0.38); }
.feature__icon--gold { color: var(--warn); background: rgba(255, 200, 87, 0.1); border-color: rgba(255, 200, 87, 0.38); }
.feature h3 {
font-family: var(--font-display); font-weight: 700; font-size: 1.02rem;
letter-spacing: 0.06em; margin: 0 0 10px;
}
.feature p { color: var(--muted); font-size: 0.9rem; margin: 0; }
.feature__num {
position: absolute; top: 12px; right: 16px;
font-family: var(--font-display); font-weight: 900; font-size: 1.7rem;
color: rgba(231, 233, 243, 0.07);
}
/* ===== Carousel ===== */
.carousel { position: relative; overflow: hidden; border: 1px solid var(--line); border-radius: var(--r-lg); }
.carousel__track {
display: flex;
transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
.shot { position: relative; flex: 0 0 100%; margin: 0; aspect-ratio: 16 / 8; min-height: 240px; overflow: hidden; }
.shot__scene { position: absolute; inset: 0; }
.shot__scene i { position: absolute; }
.shot--throne .shot__scene { background: radial-gradient(80% 90% at 50% 20%, rgba(124, 77, 255, 0.4), transparent 65%), linear-gradient(180deg, #181a32, #0b0c16); }
.shot--throne .s-a { left: 50%; bottom: 10%; transform: translateX(-50%); width: 120px; height: 60%; background: linear-gradient(180deg, #2c2f55, #14152a); clip-path: polygon(50% 0, 80% 22%, 100% 100%, 0 100%, 20% 22%); }
.shot--throne .s-b { left: 0; right: 0; bottom: 0; height: 18%; background: linear-gradient(180deg, transparent, #07080f); }
.shot--throne .s-c { left: 50%; bottom: 55%; transform: translateX(-50%); width: 22px; height: 22px; border-radius: 50%; background: var(--accent-2); box-shadow: 0 0 36px 14px rgba(124, 77, 255, 0.55); }
.shot--drift .shot__scene { background: radial-gradient(70% 70% at 25% 70%, rgba(255, 61, 113, 0.32), transparent 60%), linear-gradient(180deg, #221224, #0b0c16); }
.shot--drift .s-a { left: 0; right: 0; bottom: 0; height: 44%; background: #120a14; clip-path: polygon(0 55%, 18% 30%, 36% 58%, 55% 22%, 74% 52%, 90% 34%, 100% 50%, 100% 100%, 0 100%); }
.shot--drift .s-b { left: 60%; top: 14%; width: 90px; height: 90px; border-radius: 50%; background: radial-gradient(circle at 38% 38%, #ffd9e4, #ff3d71 70%); opacity: 0.85; box-shadow: 0 0 60px 20px rgba(255, 61, 113, 0.4); }
.shot--drift .s-c { left: 14%; bottom: 16%; width: 60px; height: 100px; background: #1d0f1f; clip-path: polygon(50% 0, 100% 30%, 88% 100%, 12% 100%, 0 30%); }
.shot--depths .shot__scene { background: radial-gradient(80% 90% at 50% 100%, rgba(0, 229, 255, 0.3), transparent 65%), linear-gradient(180deg, #0a1626, #070a12); }
.shot--depths .s-a { left: 12%; top: 18%; width: 50px; height: 64%; background: linear-gradient(180deg, #11263b, #0a1320); clip-path: polygon(50% 0, 100% 8%, 90% 100%, 10% 100%, 0 8%); }
.shot--depths .s-b { right: 16%; top: 26%; width: 44px; height: 56%; background: linear-gradient(180deg, #11263b, #0a1320); clip-path: polygon(50% 0, 100% 8%, 90% 100%, 10% 100%, 0 8%); }
.shot--depths .s-c { left: 50%; bottom: 18%; transform: translateX(-50%); width: 70px; height: 110px; background: linear-gradient(180deg, rgba(0, 229, 255, 0.85), rgba(0, 229, 255, 0.05)); clip-path: polygon(40% 0, 60% 0, 85% 35%, 100% 100%, 0 100%, 15% 35%); box-shadow: 0 0 50px rgba(0, 229, 255, 0.5); }
.shot--storm .shot__scene { background: radial-gradient(90% 60% at 75% 12%, rgba(255, 200, 87, 0.22), transparent 60%), linear-gradient(180deg, #15182e, #0a0b13); }
.shot--storm .s-a { left: 0; right: 0; bottom: 0; height: 38%; background: #0c0e1a; clip-path: polygon(0 40%, 22% 65%, 40% 35%, 62% 60%, 80% 38%, 100% 55%, 100% 100%, 0 100%); }
.shot--storm .s-b { left: 68%; top: 8%; width: 5px; height: 56%; background: linear-gradient(180deg, var(--warn), transparent); clip-path: polygon(0 0, 100% 0, 60% 30%, 100% 32%, 20% 100%, 50% 45%, 0 42%); box-shadow: 0 0 26px rgba(255, 200, 87, 0.6); }
.shot--storm .s-c { left: 22%; bottom: 24%; width: 70px; height: 90px; background: #141730; clip-path: polygon(50% 0, 100% 36%, 84% 100%, 16% 100%, 0 36%); }
.shot figcaption {
position: absolute; left: 0; right: 0; bottom: 0;
padding: 18px 22px;
background: linear-gradient(180deg, transparent, rgba(5, 6, 10, 0.92));
color: var(--muted); font-size: 0.82rem; font-weight: 500;
}
.shot figcaption span {
display: block;
font-family: var(--font-display); font-weight: 700; font-size: 0.85rem;
letter-spacing: 0.14em; color: var(--text); margin-bottom: 2px;
}
.carousel__arrow {
position: absolute; top: 50%; transform: translateY(-50%);
width: 44px; height: 44px;
display: grid; place-items: center;
background: rgba(10, 11, 16, 0.7);
border: 1px solid var(--line-2);
color: var(--text); font-size: 1rem; cursor: pointer;
clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
transition: background 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.carousel__arrow:hover { background: rgba(0, 229, 255, 0.18); border-color: var(--accent); box-shadow: var(--glow); }
.carousel__arrow--prev { left: 14px; }
.carousel__arrow--next { right: 14px; }
.carousel__dots {
position: absolute; left: 50%; bottom: 70px; transform: translateX(-50%);
display: flex; gap: 8px;
}
.carousel__dots button {
width: 26px; height: 5px;
border: 0; padding: 0; cursor: pointer;
background: rgba(231, 233, 243, 0.25);
clip-path: polygon(3px 0, 100% 0, calc(100% - 3px) 100%, 0 100%);
transition: background 0.25s ease, box-shadow 0.25s ease;
}
.carousel__dots button[aria-selected="true"] {
background: var(--accent);
box-shadow: var(--glow);
}
/* ===== Editions ===== */
.editions { background: var(--bg-2); }
.editions__grid {
display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px;
align-items: stretch;
}
.edition {
position: relative;
display: flex; flex-direction: column;
background: linear-gradient(165deg, var(--panel) 0%, var(--bg-2) 100%);
border: 1px solid var(--line);
padding: 30px 26px;
clip-path: polygon(16px 0, 100% 0, 100% calc(100% - 16px), calc(100% - 16px) 100%, 0 100%, 0 16px);
transition: transform 0.2s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}
.edition:hover { transform: translateY(-5px); border-color: var(--line-2); }
.edition--featured {
border-color: rgba(0, 229, 255, 0.55);
background: linear-gradient(165deg, var(--panel-2) 0%, var(--panel) 100%);
box-shadow: 0 0 0 1px rgba(0, 229, 255, 0.25), 0 0 40px rgba(0, 229, 255, 0.16);
}
.edition--featured:hover { box-shadow: 0 0 0 1px rgba(0, 229, 255, 0.4), 0 0 56px rgba(0, 229, 255, 0.26); }
.edition__flag {
position: absolute; top: 0; right: 16px;
font-family: var(--font-display); font-size: 0.58rem; font-weight: 700; letter-spacing: 0.18em;
color: #04141a;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
padding: 5px 12px;
clip-path: polygon(0 0, 100% 0, calc(100% - 8px) 100%, 8px 100%);
}
.edition__name {
font-family: var(--font-display); font-weight: 700; font-size: 1.1rem;
letter-spacing: 0.1em; text-transform: uppercase; margin: 0 0 6px;
}
.edition__price {
font-family: var(--font-display); font-weight: 900; font-size: 2rem;
color: var(--accent); margin: 0 0 18px;
text-shadow: 0 0 18px rgba(0, 229, 255, 0.4);
}
.edition__list {
list-style: none; margin: 0 0 26px; padding: 0;
color: var(--muted); font-size: 0.88rem;
flex: 1;
}
.edition__list li {
padding: 8px 0 8px 24px;
border-bottom: 1px solid var(--line);
position: relative;
}
.edition__list li::before {
content: "▸";
position: absolute; left: 4px;
color: var(--accent);
}
.edition__list li:last-child { border-bottom: 0; }
/* ===== Newsletter ===== */
.newsletter {
background:
radial-gradient(60% 120% at 80% 0%, rgba(124, 77, 255, 0.14), transparent 60%),
var(--bg);
border-top: 1px solid var(--line);
}
.newsletter__inner {
display: grid; grid-template-columns: 1.2fr 1fr; gap: 40px; align-items: center;
}
.newsletter__copy { color: var(--muted); margin: 14px 0 0; max-width: 420px; }
.newsletter__form { display: flex; gap: 12px; }
.newsletter__form input {
flex: 1; min-width: 0;
font: inherit; font-size: 0.92rem;
color: var(--text);
background: var(--panel);
border: 1px solid var(--line-2);
padding: 13px 16px;
clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.newsletter__form input::placeholder { color: var(--muted); opacity: 0.7; }
.newsletter__form input:focus { border-color: var(--accent); box-shadow: var(--glow); outline: none; }
.newsletter__form input.is-invalid { border-color: var(--danger); box-shadow: 0 0 14px rgba(255, 77, 77, 0.35); }
/* ===== Footer ===== */
.footer { border-top: 1px solid var(--line); padding: 34px 0; background: #07080d; }
.footer__inner { display: flex; justify-content: space-between; align-items: center; gap: 20px; flex-wrap: wrap; }
.footer__brand { font-family: var(--font-display); font-weight: 900; letter-spacing: 0.18em; font-size: 0.9rem; margin: 0; }
.footer__brand span { color: var(--accent); }
.footer__legal { color: var(--muted); font-size: 0.76rem; margin: 0; max-width: 560px; }
/* ===== Lightbox ===== */
.lightbox { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center; padding: 24px; }
.lightbox[hidden] { display: none; }
.lightbox__backdrop {
position: absolute; inset: 0;
background: rgba(5, 6, 10, 0.86);
backdrop-filter: blur(6px);
}
.lightbox__panel {
position: relative; width: min(860px, 100%);
background: var(--panel);
border: 1px solid rgba(0, 229, 255, 0.4);
box-shadow: 0 0 60px rgba(0, 229, 255, 0.22);
padding: 14px;
clip-path: polygon(18px 0, 100% 0, 100% calc(100% - 18px), calc(100% - 18px) 100%, 0 100%, 0 18px);
animation: lightboxIn 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes lightboxIn {
from { transform: translateY(24px) scale(0.96); opacity: 0; }
to { transform: none; opacity: 1; }
}
.lightbox__close {
position: absolute; top: 8px; right: 12px; z-index: 2;
width: 38px; height: 38px;
background: rgba(10, 11, 16, 0.8);
border: 1px solid var(--line-2);
color: var(--text); font-size: 1.3rem; line-height: 1; cursor: pointer;
clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
transition: color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
.lightbox__close:hover { color: var(--accent-3); border-color: var(--accent-3); box-shadow: 0 0 14px rgba(255, 61, 113, 0.4); }
.lightbox__video {
position: relative; aspect-ratio: 16 / 9;
display: grid; place-items: center;
background:
radial-gradient(70% 90% at 50% 30%, rgba(124, 77, 255, 0.25), transparent 65%),
linear-gradient(180deg, #11132a, #07080f);
overflow: hidden;
}
.lightbox__scan {
position: absolute; inset: 0;
background: repeating-linear-gradient(180deg, transparent 0 3px, rgba(0, 229, 255, 0.04) 3px 4px);
pointer-events: none;
}
.lightbox__play {
width: 86px; height: 86px;
display: grid; place-items: center;
color: #04141a;
background: linear-gradient(135deg, var(--accent), #00b3d6);
border: 0; cursor: pointer; border-radius: 50%;
box-shadow: var(--glow);
animation: playPulse 2.2s ease-in-out infinite;
transition: transform 0.15s ease;
}
.lightbox__play:hover { transform: scale(1.07); }
@keyframes playPulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(0, 229, 255, 0.45), var(--glow); }
50% { box-shadow: 0 0 0 20px rgba(0, 229, 255, 0), var(--glow); }
}
.lightbox__label {
position: absolute; bottom: 14px; left: 18px;
font-family: var(--font-display); font-size: 0.7rem; letter-spacing: 0.2em;
color: var(--muted); margin: 0;
}
.lightbox__note { color: var(--muted); font-size: 0.78rem; text-align: center; margin: 12px 0 4px; }
body.lightbox-open { overflow: hidden; }
/* ===== Toast ===== */
.toast {
position: fixed; left: 50%; bottom: 28px; z-index: 120;
transform: translate(-50%, 16px);
background: var(--panel-2);
border: 1px solid rgba(0, 229, 255, 0.5);
box-shadow: var(--glow);
color: var(--text);
font-size: 0.86rem; font-weight: 600;
padding: 12px 22px;
clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
opacity: 0; pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
}
.toast.is-visible { opacity: 1; transform: translate(-50%, 0); }
/* ===== Scroll reveal ===== */
.reveal {
opacity: 0;
transform: translateY(26px);
transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.is-revealed { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
html { scroll-behavior: auto; }
.reveal { opacity: 1; transform: none; }
}
/* ===== Responsive ===== */
@media (max-width: 860px) {
.nav__links { display: none; }
.newsletter__inner { grid-template-columns: 1fr; gap: 26px; }
.moon { width: 90px; height: 90px; right: 8%; }
.warden { left: 4%; transform: scale(0.85); transform-origin: bottom left; }
}
@media (max-width: 520px) {
.section { padding: 64px 0; }
.nav__inner { gap: 12px; padding: 0 14px; }
.nav__count { display: none; }
.nav__cta .btn--ghost span[data-wishlist-label] { display: none; }
.hero__content { padding: 110px 16px 90px; }
.hero__studio { letter-spacing: 0.3em; font-size: 0.66rem; }
.hero__tag { font-size: 0.95rem; }
.hero__actions { flex-direction: column; align-items: stretch; }
.btn--lg { justify-content: center; padding: 15px 20px; }
.hero__meta { gap: 14px; }
.citadel { transform: translateX(-50%) scale(0.7); transform-origin: bottom center; }
.shot { aspect-ratio: 4 / 3; }
.carousel__dots { bottom: 64px; }
.carousel__arrow { width: 36px; height: 36px; }
.newsletter__form { flex-direction: column; }
.footer__inner { flex-direction: column; align-items: flex-start; }
}/* Hollow Reign — landing page interactions (vanilla JS) */
(() => {
"use strict";
const $ = (sel, ctx = document) => ctx.querySelector(sel);
const $$ = (sel, ctx = document) => Array.from(ctx.querySelectorAll(sel));
/* ---------- Toast ---------- */
const toastEl = $("#toast");
let toastTimer = null;
function toast(msg) {
toastEl.textContent = msg;
toastEl.classList.add("is-visible");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => toastEl.classList.remove("is-visible"), 2600);
}
/* ---------- Sticky nav scroll state ---------- */
const nav = $("#siteNav");
const onScroll = () => nav.classList.toggle("is-scrolled", window.scrollY > 40);
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- Wishlist toggle (synced buttons + count) ---------- */
const wishlistButtons = [$("#navWishlist"), $("#heroWishlist")].filter(Boolean);
const countEl = $("#wishlistCount");
const baseCount = 128407;
let wishlisted = false;
function renderWishlist() {
const count = baseCount + (wishlisted ? 1 : 0);
countEl.textContent = count.toLocaleString("en-US");
wishlistButtons.forEach((btn) => {
btn.classList.toggle("is-wishlisted", wishlisted);
btn.setAttribute("aria-pressed", String(wishlisted));
const label = btn.querySelector("[data-wishlist-label]");
if (label) {
const isHero = btn.id === "heroWishlist";
label.textContent = wishlisted
? "Wishlisted"
: isHero
? "Add to Wishlist"
: "Wishlist";
}
});
}
wishlistButtons.forEach((btn) =>
btn.addEventListener("click", () => {
wishlisted = !wishlisted;
renderWishlist();
toast(
wishlisted
? "Hollow Reign added to your wishlist."
: "Removed from your wishlist."
);
})
);
renderWishlist();
/* ---------- Trailer lightbox ---------- */
const lightbox = $("#lightbox");
const trailerBtn = $("#trailerBtn");
const closeBtn = $("#lightboxClose");
let lastFocused = null;
function openLightbox() {
lastFocused = document.activeElement;
lightbox.hidden = false;
document.body.classList.add("lightbox-open");
closeBtn.focus();
}
function closeLightbox() {
lightbox.hidden = true;
document.body.classList.remove("lightbox-open");
if (lastFocused) lastFocused.focus();
}
trailerBtn.addEventListener("click", openLightbox);
closeBtn.addEventListener("click", closeLightbox);
$("[data-close-lightbox]").addEventListener("click", closeLightbox);
document.addEventListener("keydown", (e) => {
if (e.key === "Escape" && !lightbox.hidden) closeLightbox();
});
// Basic focus trap inside the dialog
lightbox.addEventListener("keydown", (e) => {
if (e.key !== "Tab") return;
const focusables = $$("button", lightbox);
const first = focusables[0];
const last = focusables[focusables.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
});
$("#fakePlay").addEventListener("click", () =>
toast("Trailer placeholder — embed your video player here.")
);
/* ---------- Screenshot carousel (auto + manual) ---------- */
const track = $("#carouselTrack");
const slides = $$(".shot", track);
const dotsWrap = $("#carouselDots");
let index = 0;
let autoTimer = null;
slides.forEach((_, i) => {
const dot = document.createElement("button");
dot.type = "button";
dot.setAttribute("role", "tab");
dot.setAttribute("aria-label", `Screenshot ${i + 1}`);
dot.addEventListener("click", () => {
goTo(i);
restartAuto();
});
dotsWrap.appendChild(dot);
});
const dots = $$("button", dotsWrap);
function goTo(i) {
index = (i + slides.length) % slides.length;
track.style.transform = `translateX(-${index * 100}%)`;
dots.forEach((d, di) =>
d.setAttribute("aria-selected", String(di === index))
);
}
function restartAuto() {
clearInterval(autoTimer);
autoTimer = setInterval(() => goTo(index + 1), 5000);
}
$("#prevShot").addEventListener("click", () => {
goTo(index - 1);
restartAuto();
});
$("#nextShot").addEventListener("click", () => {
goTo(index + 1);
restartAuto();
});
// Pause auto-advance while hovering or focused inside the carousel
const carousel = $("#carousel");
carousel.addEventListener("mouseenter", () => clearInterval(autoTimer));
carousel.addEventListener("mouseleave", restartAuto);
carousel.addEventListener("focusin", () => clearInterval(autoTimer));
carousel.addEventListener("focusout", restartAuto);
goTo(0);
restartAuto();
/* ---------- Edition pre-order buttons ---------- */
$$("[data-edition]").forEach((btn) =>
btn.addEventListener("click", () =>
toast(`${btn.dataset.edition} Edition added to cart — see you 11.09.26!`)
)
);
/* ---------- Newsletter form ---------- */
const form = $("#newsForm");
const emailInput = $("#newsEmail");
form.addEventListener("submit", (e) => {
e.preventDefault();
const value = emailInput.value.trim();
const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
emailInput.classList.toggle("is-invalid", !valid);
if (!valid) {
toast("Enter a valid email address to enlist.");
emailInput.focus();
return;
}
form.reset();
toast("Enlisted! First war dispatch inbound.");
});
emailInput.addEventListener("input", () =>
emailInput.classList.remove("is-invalid")
);
/* ---------- Scroll-reveal sections ---------- */
const revealEls = $$(".reveal");
if ("IntersectionObserver" in window) {
const io = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("is-revealed");
io.unobserve(entry.target);
}
});
},
{ threshold: 0.15, rootMargin: "0px 0px -40px 0px" }
);
revealEls.forEach((el) => io.observe(el));
} else {
revealEls.forEach((el) => el.classList.add("is-revealed"));
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hollow Reign — Nullforge Studios</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=Orbitron:wght@500;700;900&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="siteNav">
<div class="nav__inner">
<a class="nav__brand" href="#top" aria-label="Hollow Reign home">
<span class="nav__sigil" aria-hidden="true"></span>
<span class="nav__name">HOLLOW<i>REIGN</i></span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#features">Features</a>
<a href="#media">Media</a>
<a href="#editions">Editions</a>
<a href="#newsletter">News</a>
</nav>
<div class="nav__cta">
<button class="btn btn--ghost btn--sm" id="navWishlist" type="button" aria-pressed="false">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M12 21s-7.5-4.7-10-9.3C.5 8 2.3 4.5 5.9 4.1c2-.2 3.9.8 6.1 3.2 2.2-2.4 4.1-3.4 6.1-3.2 3.6.4 5.4 3.9 3.9 7.6C19.5 16.3 12 21 12 21z"/></svg>
<span data-wishlist-label>Wishlist</span>
<span class="nav__count" id="wishlistCount">128,407</span>
</button>
<a class="btn btn--accent btn--sm" href="#editions">Pre-order</a>
</div>
</div>
</header>
<main id="top">
<!-- ===== Hero ===== -->
<section class="hero" aria-label="Hollow Reign — key art">
<div class="hero__art" aria-hidden="true">
<div class="sky"></div>
<div class="stars"></div>
<div class="moon"></div>
<div class="ridge ridge--far"></div>
<div class="ridge ridge--mid"></div>
<div class="citadel">
<i class="spire spire--1"></i><i class="spire spire--2"></i><i class="spire spire--3"></i>
<i class="beacon"></i>
</div>
<div class="ridge ridge--near"></div>
<div class="fog"></div>
<div class="warden">
<i class="warden__cloak"></i>
<i class="warden__head"></i>
<i class="warden__blade"></i>
</div>
<div class="embers">
<i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i>
</div>
<div class="hero__vignette"></div>
</div>
<div class="hero__content reveal">
<p class="hero__studio">A NULLFORGE STUDIOS GAME</p>
<h1 class="hero__title">HOLLOW <span>REIGN</span></h1>
<p class="hero__tag">The crown is dead. The throne still hungers. Carve your legend through a kingdom that remembers every choice you make.</p>
<div class="hero__actions">
<button class="btn btn--accent btn--lg" id="trailerBtn" type="button">
<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor" aria-hidden="true"><path d="M8 5.5v13l11-6.5-11-6.5z"/></svg>
Watch Trailer
</button>
<button class="btn btn--outline btn--lg wishlist-btn" id="heroWishlist" type="button" aria-pressed="false">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M12 21s-7.5-4.7-10-9.3C.5 8 2.3 4.5 5.9 4.1c2-.2 3.9.8 6.1 3.2 2.2-2.4 4.1-3.4 6.1-3.2 3.6.4 5.4 3.9 3.9 7.6C19.5 16.3 12 21 12 21z"/></svg>
<span data-wishlist-label>Add to Wishlist</span>
</button>
</div>
<div class="hero__meta">
<span class="hero__date">COMING <strong>11.09.2026</strong></span>
<ul class="platforms" aria-label="Available platforms">
<li><span class="chip">PC</span></li>
<li><span class="chip">PS5</span></li>
<li><span class="chip">XSX</span></li>
<li><span class="chip">SWITCH 2</span></li>
</ul>
</div>
</div>
<a class="hero__scroll" href="#features" aria-label="Scroll to features">
<span></span>
</a>
</section>
<!-- ===== Features ===== -->
<section class="section features" id="features">
<div class="wrap">
<header class="section__head reveal">
<p class="kicker">// CORE SYSTEMS</p>
<h2 class="section__title">Forge Your Own Reign</h2>
</header>
<div class="features__grid">
<article class="feature reveal">
<div class="feature__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 2l2.4 5.3L20 8l-4 4 1 5.7L12 15l-5 2.7L8 12 4 8l5.6-.7L12 2z"/></svg>
</div>
<h3>Sigil Combat</h3>
<p>Chain runic sigils into devastating combos. Every weapon remembers its kills and evolves a unique moveset over your campaign.</p>
<span class="feature__num" aria-hidden="true">01</span>
</article>
<article class="feature reveal">
<div class="feature__icon feature__icon--violet" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9"/><path d="M12 3v18M3 12h18M5.5 5.5l13 13M18.5 5.5l-13 13"/></svg>
</div>
<h3>Living Kingdom</h3>
<p>Eight provinces shift allegiance based on your verdicts. Burn a granary in Act I and famine riots reshape Act III.</p>
<span class="feature__num" aria-hidden="true">02</span>
</article>
<article class="feature reveal">
<div class="feature__icon feature__icon--rose" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M4 20c2-7 4-10 8-14 4 4 6 7 8 14-3-2-5-3-8-3s-5 1-8 3z"/><circle cx="12" cy="10" r="1.6"/></svg>
</div>
<h3>Hollow Bond</h3>
<p>Bind fallen bosses as spectral allies. Summon the Ash Warden mid-fight — or consume the bond for one cataclysmic strike.</p>
<span class="feature__num" aria-hidden="true">03</span>
</article>
<article class="feature reveal">
<div class="feature__icon feature__icon--gold" aria-hidden="true">
<svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 7h18M3 12h18M3 17h12"/><circle cx="19" cy="17" r="2"/></svg>
</div>
<h3>Co-op Sieges</h3>
<p>Drop-in 3-player sieges with shared war-table strategy. Breach walls, hold chokepoints, and split the spoils of the crown.</p>
<span class="feature__num" aria-hidden="true">04</span>
</article>
</div>
</div>
</section>
<!-- ===== Media / screenshots ===== -->
<section class="section media" id="media">
<div class="wrap">
<header class="section__head reveal">
<p class="kicker">// MEDIA</p>
<h2 class="section__title">From the Frontlines</h2>
</header>
<div class="carousel reveal" id="carousel" aria-roledescription="carousel" aria-label="Screenshot gallery">
<div class="carousel__track" id="carouselTrack">
<figure class="shot shot--throne" role="group" aria-label="Screenshot 1 of 4">
<div class="shot__scene" aria-hidden="true"><i class="s-a"></i><i class="s-b"></i><i class="s-c"></i></div>
<figcaption><span>THE EMPTY THRONE</span> Act I — Vael Citadel</figcaption>
</figure>
<figure class="shot shot--drift" role="group" aria-label="Screenshot 2 of 4">
<div class="shot__scene" aria-hidden="true"><i class="s-a"></i><i class="s-b"></i><i class="s-c"></i></div>
<figcaption><span>EMBERFALL PASS</span> Co-op siege, 3 players</figcaption>
</figure>
<figure class="shot shot--depths" role="group" aria-label="Screenshot 3 of 4">
<div class="shot__scene" aria-hidden="true"><i class="s-a"></i><i class="s-b"></i><i class="s-c"></i></div>
<figcaption><span>THE SUNKEN COURT</span> Hollow Bond summon</figcaption>
</figure>
<figure class="shot shot--storm" role="group" aria-label="Screenshot 4 of 4">
<div class="shot__scene" aria-hidden="true"><i class="s-a"></i><i class="s-b"></i><i class="s-c"></i></div>
<figcaption><span>STORMCROWN REACH</span> Sigil combat, late game</figcaption>
</figure>
</div>
<button class="carousel__arrow carousel__arrow--prev" id="prevShot" type="button" aria-label="Previous screenshot">❮</button>
<button class="carousel__arrow carousel__arrow--next" id="nextShot" type="button" aria-label="Next screenshot">❯</button>
<div class="carousel__dots" id="carouselDots" role="tablist" aria-label="Choose screenshot"></div>
</div>
</div>
</section>
<!-- ===== Editions ===== -->
<section class="section editions" id="editions">
<div class="wrap">
<header class="section__head reveal">
<p class="kicker">// PRE-ORDER</p>
<h2 class="section__title">Choose Your Edition</h2>
</header>
<div class="editions__grid">
<article class="edition reveal">
<h3 class="edition__name">Standard</h3>
<p class="edition__price">$59.99</p>
<ul class="edition__list">
<li>Base game</li>
<li>Pre-order bonus: Gravewrought sigil set</li>
<li>Digital soundtrack sampler</li>
</ul>
<button class="btn btn--outline btn--block" type="button" data-edition="Standard">Pre-order Standard</button>
</article>
<article class="edition edition--featured reveal">
<span class="edition__flag">MOST POPULAR</span>
<h3 class="edition__name">Sovereign</h3>
<p class="edition__price">$89.99</p>
<ul class="edition__list">
<li>Everything in Standard</li>
<li>72-hour early access</li>
<li>Season pass: 2 story chapters</li>
<li>Exclusive Ash Warden armor dye</li>
</ul>
<button class="btn btn--accent btn--block" type="button" data-edition="Sovereign">Pre-order Sovereign</button>
</article>
<article class="edition reveal">
<h3 class="edition__name">Hollow Crown</h3>
<p class="edition__price">$129.99</p>
<ul class="edition__list">
<li>Everything in Sovereign</li>
<li>Digital artbook + full OST</li>
<li>Animated crown profile frame</li>
<li>Name in the Founders' Hall credits</li>
</ul>
<button class="btn btn--outline btn--block" type="button" data-edition="Hollow Crown">Pre-order Hollow Crown</button>
</article>
</div>
</div>
</section>
<!-- ===== Newsletter ===== -->
<section class="section newsletter" id="newsletter">
<div class="wrap newsletter__inner reveal">
<div>
<p class="kicker">// WAR DISPATCHES</p>
<h2 class="section__title">Enlist for Updates</h2>
<p class="newsletter__copy">Beta invites, dev diaries, and lore drops from Nullforge — straight to your inbox. No spam, ever.</p>
</div>
<form class="newsletter__form" id="newsForm" novalidate>
<label class="sr-only" for="newsEmail">Email address</label>
<input type="email" id="newsEmail" name="email" placeholder="commander@example.com" autocomplete="email" required />
<button class="btn btn--accent" type="submit">Enlist</button>
</form>
</div>
</section>
</main>
<footer class="footer">
<div class="wrap footer__inner">
<p class="footer__brand">NULLFORGE <span>STUDIOS</span></p>
<p class="footer__legal">© 2026 Nullforge Studios. Hollow Reign is a fictional game shown for demo purposes. ESRB rating pending.</p>
</div>
</footer>
<!-- ===== Trailer lightbox ===== -->
<div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-label="Hollow Reign announce trailer" hidden>
<div class="lightbox__backdrop" data-close-lightbox></div>
<div class="lightbox__panel">
<button class="lightbox__close" id="lightboxClose" type="button" aria-label="Close trailer">×</button>
<div class="lightbox__video" aria-hidden="true">
<div class="lightbox__scan"></div>
<button class="lightbox__play" type="button" aria-label="Play trailer placeholder" id="fakePlay">
<svg viewBox="0 0 24 24" width="30" height="30" fill="currentColor"><path d="M8 5.5v13l11-6.5-11-6.5z"/></svg>
</button>
<p class="lightbox__label">ANNOUNCE TRAILER — 02:14</p>
</div>
<p class="lightbox__note">Video placeholder — wire your player or embed here.</p>
</div>
</div>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Game Landing (trailer · wishlist CTA)
A full AAA-style marketing page for the fictional action RPG Hollow Reign. The hero is a layered, pure-CSS key-art scene — twinkling stars, a glowing moon, clip-path mountain ridges, a beacon-lit citadel, a cloaked warden with a humming neon blade, and embers drifting upward — topped with a gradient Orbitron title, release date, platform chips, and big angled CTAs for Watch Trailer and Add to Wishlist.
The script wires every control: the sticky nav gains a blurred, shadowed state on scroll; the trailer button opens an accessible lightbox (ESC/backdrop close, basic focus trap, pulsing play placeholder); the wishlist toggle syncs the nav and hero buttons and bumps the live counter; the screenshot carousel auto-advances every five seconds, pauses on hover/focus, and supports arrows plus generated dot tabs.
Below the fold, a four-card features grid highlights core systems with per-card accent colors, three pre-order edition cards (with a featured Sovereign tier) fire toast confirmations, and the newsletter form validates email input inline. Sections fade in via an IntersectionObserver scroll-reveal, with a prefers-reduced-motion fallback.
Illustrative UI only — fictional games, studios, characters, and data. Not engine integrations.