Creator — Streamer / Gamer Landing
A dark, electric personal-brand landing page for a variety streamer, built with semantic HTML, CSS, and vanilla JavaScript. Features a neon-on-black hero with a live-now pulse badge and drifting viewer count, a tabbed weekly stream schedule, a clip gallery with an accessible lightbox, membership sub tiers, sponsors and gear, a Discord community block, a validated newsletter form, scroll reveals, a mobile nav toggle, and toast feedback on every call to action.
MCP
Code
/* ========== TOKENS ========== */
:root {
--bg: #0a0710;
--bg-2: #110b1c;
--panel: #160f24;
--panel-2: #1d1430;
--line: #2a1f44;
--ink: #f4eefe;
--muted: #b6a9d6;
--faint: #7c6fa0;
--purple: #8b5cf6;
--purple-bright: #a78bfa;
--neon: #5cf28a;
--neon-dim: #34c46a;
--danger: #ff4d6d;
--radius: 16px;
--radius-sm: 10px;
--maxw: 1180px;
--shadow: 0 24px 60px -20px rgba(0, 0, 0, .7);
--glow-purple: 0 0 0 1px rgba(139, 92, 246, .4), 0 0 40px -8px rgba(139, 92, 246, .55);
--glow-neon: 0 0 0 1px rgba(92, 242, 138, .5), 0 0 38px -8px rgba(92, 242, 138, .5);
--display: "Chakra Petch", system-ui, sans-serif;
--body: "Inter", system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; }
* { margin: 0; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
background: radial-gradient(1100px 700px at 80% -10%, #1a1030 0%, transparent 60%),
radial-gradient(900px 600px at -10% 10%, #0f1a14 0%, transparent 55%),
var(--bg);
color: var(--ink);
font-family: var(--body);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
overflow-x: hidden;
}
h1, h2, h3 { font-family: var(--display); line-height: 1.05; letter-spacing: -.01em; }
a { color: inherit; text-decoration: none; }
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;
}
.skip-link {
position: absolute; left: 12px; top: -50px; z-index: 200;
background: var(--neon); color: #04140a; padding: 10px 16px; border-radius: 8px;
font-weight: 700; transition: top .2s;
}
.skip-link:focus { top: 12px; }
:focus-visible { outline: 3px solid var(--neon); outline-offset: 2px; border-radius: 6px; }
/* ========== BUTTONS ========== */
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: .5em;
font-family: var(--display); font-weight: 700; font-size: .95rem;
padding: .82em 1.5em; border-radius: 999px; cursor: pointer; border: 0;
letter-spacing: .02em; transition: transform .15s ease, box-shadow .2s ease, background .2s;
text-transform: uppercase;
}
.btn:active { transform: translateY(1px) scale(.99); }
.btn-watch {
background: linear-gradient(135deg, var(--neon), var(--neon-dim));
color: #04140a; box-shadow: var(--glow-neon);
}
.btn-watch:hover { transform: translateY(-2px); box-shadow: 0 0 0 1px rgba(92,242,138,.6), 0 0 50px -6px rgba(92,242,138,.7); }
.btn-ghost {
background: rgba(139, 92, 246, .12); color: var(--purple-bright);
border: 1px solid rgba(139, 92, 246, .45);
}
.btn-ghost:hover { background: rgba(139, 92, 246, .22); transform: translateY(-2px); box-shadow: var(--glow-purple); }
/* ========== NAV ========== */
.nav {
position: sticky; top: 0; z-index: 100;
backdrop-filter: blur(14px);
background: rgba(10, 7, 16, .72);
border-bottom: 1px solid var(--line);
}
.nav-inner {
max-width: var(--maxw); margin: 0 auto; padding: 14px 22px;
display: flex; align-items: center; justify-content: space-between; gap: 18px;
}
.logo { display: inline-flex; align-items: center; gap: .5rem; font-family: var(--display); font-weight: 700; font-size: 1.25rem; }
.logo-mark { color: var(--neon); font-size: 1.3rem; filter: drop-shadow(0 0 8px rgba(92,242,138,.7)); }
.logo-accent { color: var(--purple-bright); }
.nav-links { display: flex; align-items: center; gap: 6px; }
.nav-links a {
padding: .55em .85em; border-radius: 8px; font-weight: 600; font-size: .92rem; color: var(--muted);
transition: color .15s, background .15s;
}
.nav-links a:hover { color: var(--ink); background: rgba(139,92,246,.12); }
.nav-cta { color: #04140a !important; margin-left: 6px; }
.nav-toggle {
display: none; flex-direction: column; gap: 5px; background: none; border: 0; cursor: pointer; padding: 8px;
}
.nav-toggle span { width: 24px; height: 2px; background: var(--ink); border-radius: 2px; transition: transform .25s, opacity .2s; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* ========== LAYOUT ========== */
.section { max-width: var(--maxw); margin: 0 auto; padding: 92px 22px; }
.section-head { max-width: 640px; margin-bottom: 44px; }
.eyebrow {
display: inline-block; font-family: var(--display); font-weight: 700; font-size: .8rem;
letter-spacing: .18em; text-transform: uppercase; color: var(--neon); margin-bottom: 14px;
}
.section-head h2 { font-size: clamp(1.9rem, 4vw, 2.8rem); margin-bottom: 12px; }
.lede { color: var(--muted); font-size: 1.05rem; }
.lede strong { color: var(--neon); }
/* ========== HERO ========== */
.hero { position: relative; overflow: hidden; padding: 64px 0 84px; }
.hero-grid-bg {
position: absolute; inset: 0;
background-image: linear-gradient(rgba(139,92,246,.07) 1px, transparent 1px),
linear-gradient(90deg, rgba(139,92,246,.07) 1px, transparent 1px);
background-size: 46px 46px;
mask-image: radial-gradient(700px 500px at 60% 30%, #000 0%, transparent 80%);
}
.hero-glow {
position: absolute; width: 520px; height: 520px; right: -80px; top: -120px;
background: radial-gradient(circle, rgba(139,92,246,.5), transparent 65%);
filter: blur(20px); z-index: 0;
}
.hero-inner {
position: relative; z-index: 1; max-width: var(--maxw); margin: 0 auto; padding: 0 22px;
display: grid; grid-template-columns: 1.1fr .9fr; gap: 56px; align-items: center;
}
.live-badge {
display: inline-flex; align-items: center; gap: 8px;
background: rgba(255, 77, 109, .12); border: 1px solid rgba(255,77,109,.45);
color: #ffd2db; padding: 7px 14px; border-radius: 999px; font-size: .85rem; font-weight: 600;
margin-bottom: 22px;
}
.live-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--danger); box-shadow: 0 0 0 0 rgba(255,77,109,.7); }
.live-badge.is-live .live-dot { animation: pulse 1.6s infinite; }
.live-text { font-family: var(--display); font-weight: 700; letter-spacing: .08em; color: #ff7d92; }
.live-viewers { font-variant-numeric: tabular-nums; color: var(--neon); font-weight: 700; }
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(255,77,109,.6); }
70% { box-shadow: 0 0 0 12px rgba(255,77,109,0); }
100% { box-shadow: 0 0 0 0 rgba(255,77,109,0); }
}
.hero-title { font-size: clamp(2.6rem, 7vw, 4.6rem); margin-bottom: 18px; }
.handle {
background: linear-gradient(110deg, var(--purple-bright), var(--neon));
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero-tag { font-size: 1.18rem; color: var(--muted); max-width: 520px; margin-bottom: 30px; }
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 38px; }
.hero-stats { display: flex; gap: 34px; list-style: none; padding: 0; flex-wrap: wrap; }
.hero-stats li { display: flex; flex-direction: column; }
.hero-stats strong { font-family: var(--display); font-size: 1.7rem; color: var(--ink); }
.hero-stats span { color: var(--faint); font-size: .85rem; text-transform: uppercase; letter-spacing: .06em; }
.stream-card {
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
overflow: hidden; box-shadow: var(--shadow);
transform: rotate(1.4deg); transition: transform .3s;
}
.stream-card:hover { transform: rotate(0deg) scale(1.01); }
.stream-thumb {
position: relative; aspect-ratio: 16/10;
background: radial-gradient(120% 120% at 30% 20%, #3a1d6e, #120a22 70%);
display: flex; align-items: center; justify-content: center;
}
.stream-thumb::after {
content: ""; position: absolute; inset: 0;
background-image: linear-gradient(rgba(92,242,138,.05) 2px, transparent 2px);
background-size: 100% 5px; pointer-events: none; opacity: .6;
}
.stream-game {
font-family: var(--display); font-weight: 700; font-size: clamp(1.3rem, 3vw, 2rem);
letter-spacing: .14em; color: rgba(167,139,250,.55);
}
.stream-play {
position: absolute; width: 64px; height: 64px; border-radius: 50%; border: 0; cursor: pointer;
background: rgba(92,242,138,.92); color: #04140a; font-size: 1.4rem;
display: grid; place-items: center; box-shadow: var(--glow-neon); transition: transform .2s;
}
.stream-play:hover { transform: scale(1.08); }
.stream-live-tag {
position: absolute; top: 12px; left: 12px; background: rgba(255,77,109,.9); color: #fff;
font-weight: 700; font-size: .72rem; padding: 4px 9px; border-radius: 6px; letter-spacing: .05em;
}
.stream-meta { padding: 16px 18px; }
.stream-title { font-weight: 600; font-size: 1.05rem; }
.stream-sub { color: var(--faint); font-size: .88rem; margin-top: 4px; }
/* ========== SCHEDULE ========== */
.day-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 26px; }
.day-tab {
font-family: var(--display); font-weight: 600; font-size: .95rem;
background: var(--panel); border: 1px solid var(--line); color: var(--muted);
padding: .65em 1.2em; border-radius: 999px; cursor: pointer; transition: all .18s;
}
.day-tab:hover { color: var(--ink); border-color: rgba(139,92,246,.5); }
.day-tab.is-active { background: var(--purple); color: #fff; border-color: var(--purple); box-shadow: var(--glow-purple); }
.day-tab.is-off { opacity: .55; }
.day-panel {
background: linear-gradient(180deg, var(--panel), var(--bg-2));
border: 1px solid var(--line); border-radius: var(--radius); padding: 8px;
min-height: 140px;
}
.slot {
display: grid; grid-template-columns: 130px 1fr auto; gap: 18px; align-items: center;
padding: 18px 20px; border-radius: var(--radius-sm); transition: background .15s;
}
.slot + .slot { border-top: 1px solid var(--line); }
.slot:hover { background: rgba(139,92,246,.08); }
.slot-time { font-family: var(--display); font-weight: 700; color: var(--neon); font-variant-numeric: tabular-nums; }
.slot-title { font-weight: 600; }
.slot-title small { display: block; color: var(--faint); font-weight: 400; font-size: .85rem; margin-top: 2px; }
.slot-tag {
font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
padding: 4px 10px; border-radius: 999px; white-space: nowrap;
background: rgba(139,92,246,.18); color: var(--purple-bright); border: 1px solid rgba(139,92,246,.4);
}
.day-empty { padding: 44px 20px; text-align: center; color: var(--faint); font-family: var(--display); }
.day-empty span { display: block; font-size: 2rem; margin-bottom: 8px; }
/* ========== CLIPS ========== */
.clip-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.clip {
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
overflow: hidden; cursor: pointer; transition: transform .2s, border-color .2s, box-shadow .2s;
}
.clip:hover, .clip:focus-visible { transform: translateY(-5px); border-color: rgba(92,242,138,.5); box-shadow: var(--glow-neon); }
.clip-thumb { position: relative; aspect-ratio: 16/9; }
.clip-thumb::before {
content: "▶"; position: absolute; inset: 0; display: grid; place-items: center;
font-size: 1.6rem; color: rgba(255,255,255,.85); opacity: 0; transition: opacity .2s;
text-shadow: 0 2px 12px rgba(0,0,0,.6);
}
.clip:hover .clip-thumb::before, .clip:focus-visible .clip-thumb::before { opacity: 1; }
.clip-a { background: linear-gradient(135deg, #6d28d9, #2dd4bf); }
.clip-b { background: linear-gradient(135deg, #1e1b4b, #be123c); }
.clip-c { background: linear-gradient(135deg, #047857, #0ea5e9); }
.clip-d { background: linear-gradient(135deg, #7c3aed, #db2777); }
.clip-e { background: linear-gradient(135deg, #f59e0b, #b91c1c); }
.clip-f { background: linear-gradient(135deg, #312e81, #16a34a); }
.clip-dur {
position: absolute; bottom: 10px; right: 10px; background: rgba(0,0,0,.7); color: #fff;
font-size: .76rem; font-weight: 600; padding: 3px 8px; border-radius: 6px; font-variant-numeric: tabular-nums;
}
.clip-info { padding: 14px 16px; display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.clip-info h3 { font-size: 1rem; font-family: var(--body); font-weight: 600; }
.clip-info span { color: var(--faint); font-size: .82rem; white-space: nowrap; }
/* ========== ABOUT ========== */
.about-inner {
display: grid; grid-template-columns: .8fr 1.2fr; gap: 56px; align-items: center;
}
.about-portrait {
position: relative; aspect-ratio: 1; max-width: 320px; border-radius: 24px; justify-self: center;
width: 100%;
background: radial-gradient(120% 120% at 30% 20%, #4c1d95, #0e0a1a 75%);
display: grid; place-items: center; border: 1px solid var(--line); box-shadow: var(--shadow);
}
.about-emoji { font-size: 6rem; filter: drop-shadow(0 8px 20px rgba(0,0,0,.5)); }
.about-ring {
position: absolute; inset: -2px; border-radius: 26px;
background: conic-gradient(from 0deg, var(--purple), var(--neon), var(--purple));
z-index: -1; filter: blur(6px); opacity: .55;
}
.about-copy p { color: var(--muted); margin-bottom: 16px; max-width: 56ch; }
.about-copy h2 { font-size: clamp(1.8rem, 4vw, 2.6rem); margin-bottom: 16px; }
.about-tags { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; padding: 0; margin-top: 8px; }
.about-tags li {
font-size: .82rem; font-weight: 600; padding: 6px 12px; border-radius: 999px;
background: rgba(92,242,138,.1); color: var(--neon); border: 1px solid rgba(92,242,138,.3);
}
/* ========== TIERS ========== */
.tier-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; align-items: stretch; }
.tier {
position: relative; background: var(--panel); border: 1px solid var(--line);
border-radius: var(--radius); padding: 30px 26px; display: flex; flex-direction: column;
transition: transform .2s, border-color .2s;
}
.tier:hover { transform: translateY(-5px); border-color: rgba(139,92,246,.5); }
.tier-featured {
border-color: var(--purple); background: linear-gradient(180deg, var(--panel-2), var(--panel));
box-shadow: var(--glow-purple);
}
.tier-flag {
position: absolute; top: -12px; left: 26px; background: var(--neon); color: #04140a;
font-family: var(--display); font-weight: 700; font-size: .72rem; letter-spacing: .06em;
padding: 5px 12px; border-radius: 999px; text-transform: uppercase;
}
.tier h3 { font-size: 1.3rem; margin-bottom: 6px; }
.tier-price { font-family: var(--display); font-weight: 700; font-size: 2.4rem; margin-bottom: 20px; }
.tier-price span { font-size: .95rem; color: var(--faint); font-weight: 500; }
.tier ul { list-style: none; padding: 0; margin: 0 0 26px; flex: 1; }
.tier li { position: relative; padding: 8px 0 8px 26px; color: var(--muted); font-size: .94rem; border-bottom: 1px solid rgba(42,31,68,.5); }
.tier li::before { content: "▸"; position: absolute; left: 0; color: var(--neon); }
.tier-btn { width: 100%; }
/* ========== PRESS ========== */
.quote-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.quote {
background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 28px;
transition: transform .2s, border-color .2s;
}
.quote:hover { transform: translateY(-4px); border-color: rgba(139,92,246,.4); }
.quote blockquote { font-size: 1.05rem; line-height: 1.55; margin-bottom: 16px; }
.quote blockquote::before { content: "“"; font-family: var(--display); color: var(--purple-bright); font-size: 2.4rem; line-height: 0; vertical-align: -.4em; margin-right: 4px; }
.quote figcaption { color: var(--faint); font-size: .88rem; }
.q-name { color: var(--neon); font-weight: 700; }
/* ========== GEAR ========== */
.gear-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 16px; }
.gear-logo {
display: grid; place-items: center; padding: 26px 10px; border-radius: var(--radius-sm);
background: var(--panel); border: 1px solid var(--line);
font-family: var(--display); font-weight: 700; letter-spacing: .08em; color: var(--faint);
transition: color .2s, border-color .2s, transform .2s;
}
.gear-logo:hover { color: var(--purple-bright); border-color: rgba(139,92,246,.5); transform: translateY(-3px); }
/* ========== COMMUNITY ========== */
.community-inner {
display: grid; grid-template-columns: 1.1fr .9fr; gap: 48px; align-items: center;
background: linear-gradient(135deg, rgba(139,92,246,.12), rgba(92,242,138,.06));
border: 1px solid var(--line); border-radius: 24px; padding: 48px;
}
.community-copy h2 { font-size: clamp(1.8rem, 4vw, 2.6rem); margin-bottom: 14px; }
.community-copy p { color: var(--muted); margin-bottom: 24px; max-width: 46ch; }
.community-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 26px; }
.socials { display: flex; flex-wrap: wrap; gap: 10px; }
.socials a {
font-size: .85rem; font-weight: 600; padding: 8px 14px; border-radius: 999px;
background: rgba(255,255,255,.04); border: 1px solid var(--line); color: var(--muted);
transition: all .15s;
}
.socials a:hover { color: var(--neon); border-color: rgba(92,242,138,.5); }
.newsletter {
background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 30px;
}
.newsletter h3 { font-size: 1.25rem; margin-bottom: 8px; }
.newsletter > p { color: var(--muted); font-size: .92rem; margin-bottom: 18px; }
.news-row { display: flex; gap: 10px; }
.news-row input {
flex: 1; background: var(--panel); border: 1px solid var(--line); border-radius: 999px;
padding: .8em 1.2em; color: var(--ink); font-size: .95rem; font-family: var(--body);
}
.news-row input::placeholder { color: var(--faint); }
.news-row input:focus { outline: none; border-color: var(--neon); box-shadow: 0 0 0 3px rgba(92,242,138,.2); }
.news-status { margin-top: 12px; font-size: .9rem; min-height: 1.2em; }
.news-status.ok { color: var(--neon); }
.news-status.err { color: var(--danger); }
/* ========== FOOTER ========== */
.footer { border-top: 1px solid var(--line); background: var(--bg-2); margin-top: 40px; }
.footer-inner {
max-width: var(--maxw); margin: 0 auto; padding: 48px 22px 28px;
display: flex; justify-content: space-between; gap: 30px; flex-wrap: wrap;
}
.footer-brand { max-width: 280px; }
.footer-brand p { color: var(--faint); margin-top: 10px; font-size: .9rem; }
.footer-links { display: flex; flex-wrap: wrap; gap: 18px; align-content: flex-start; }
.footer-links a { color: var(--muted); font-weight: 600; font-size: .92rem; transition: color .15s; }
.footer-links a:hover { color: var(--neon); }
.footer-legal {
max-width: var(--maxw); margin: 0 auto; padding: 0 22px 36px; color: var(--faint); font-size: .84rem;
border-top: 1px solid var(--line); padding-top: 22px;
}
.footer-legal a { color: var(--purple-bright); }
/* ========== TOAST ========== */
.toast {
position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 120%);
background: var(--panel-2); border: 1px solid rgba(92,242,138,.5); color: var(--ink);
padding: 13px 22px; border-radius: 999px; font-weight: 600; font-size: .92rem;
box-shadow: var(--shadow); z-index: 300; opacity: 0; transition: transform .3s ease, opacity .3s;
max-width: 90vw;
}
.toast.show { transform: translate(-50%, 0); opacity: 1; }
/* ========== LIGHTBOX ========== */
.lightbox {
position: fixed; inset: 0; z-index: 250; display: grid; place-items: center; padding: 20px;
background: rgba(5, 3, 10, .85); backdrop-filter: blur(8px);
opacity: 0; transition: opacity .25s;
}
.lightbox.show { opacity: 1; }
.lightbox[hidden] { display: none; }
.lightbox-body { max-width: 720px; width: 100%; text-align: center; }
.lightbox-screen {
aspect-ratio: 16/9; border-radius: var(--radius); display: grid; place-items: center;
background: radial-gradient(120% 120% at 30% 20%, #4c1d95, #0e0a1a 75%);
border: 1px solid var(--line); margin-bottom: 18px;
}
.lightbox-play { font-size: 3rem; color: var(--neon); filter: drop-shadow(0 0 12px rgba(92,242,138,.6)); }
.lightbox-body h3 { font-size: 1.4rem; margin-bottom: 6px; }
.lightbox-body p { color: var(--muted); }
.lightbox-close {
position: absolute; top: 20px; right: 24px; width: 44px; height: 44px; border-radius: 50%;
background: var(--panel); border: 1px solid var(--line); color: var(--ink); font-size: 1.1rem; cursor: pointer;
transition: background .15s;
}
.lightbox-close:hover { background: var(--danger); }
/* ========== REVEAL ========== */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity .6s ease, transform .6s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
.reveal { opacity: 1; transform: none; transition: none; }
.live-badge.is-live .live-dot { animation: none; }
}
/* ========== RESPONSIVE ========== */
@media (max-width: 980px) {
.gear-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 860px) {
.hero-inner, .about-inner, .community-inner { grid-template-columns: 1fr; }
.community-inner { padding: 32px; }
.clip-grid, .tier-grid, .quote-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
.nav-toggle { display: flex; }
.nav-links {
position: absolute; top: 100%; left: 0; right: 0; flex-direction: column; align-items: stretch;
gap: 4px; padding: 14px 16px 20px; background: rgba(13, 9, 22, .98); border-bottom: 1px solid var(--line);
transform: translateY(-12px); opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
}
.nav-links.open { transform: none; opacity: 1; pointer-events: auto; }
.nav-links a { padding: .8em 1em; }
.nav-cta { text-align: center; margin-top: 6px; }
.section { padding: 64px 18px; }
.hero { padding: 40px 0 60px; }
.stream-card { transform: none; margin-top: 8px; }
.slot { grid-template-columns: 1fr; gap: 6px; }
.slot-tag { justify-self: start; }
.clip-grid, .tier-grid, .quote-grid { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
.hero-stats { gap: 22px; }
.hero-stats strong { font-size: 1.4rem; }
.gear-grid { grid-template-columns: repeat(2, 1fr); }
.news-row { flex-direction: column; }
.news-row .btn { width: 100%; }
.footer-inner { flex-direction: column; }
.btn { width: 100%; }
.hero-actions, .community-actions { flex-direction: column; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
/* Wire any element with data-toast */
document.addEventListener("click", function (e) {
var t = e.target.closest("[data-toast]");
if (t) toast(t.getAttribute("data-toast"));
});
/* ---------- Mobile nav ---------- */
var toggle = document.getElementById("nav-toggle");
var links = document.getElementById("nav-links");
if (toggle && links) {
toggle.addEventListener("click", function () {
var open = links.classList.toggle("open");
toggle.setAttribute("aria-expanded", open ? "true" : "false");
});
links.addEventListener("click", function (e) {
if (e.target.tagName === "A") {
links.classList.remove("open");
toggle.setAttribute("aria-expanded", "false");
}
});
}
/* ---------- Live badge: pulse + drifting viewer count ---------- */
var badge = document.getElementById("live-badge");
var viewers = document.getElementById("live-viewers");
if (badge) badge.classList.add("is-live");
if (viewers) {
var count = 4218;
setInterval(function () {
count += Math.floor(Math.random() * 61) - 26; // drift up/down
if (count < 3600) count = 3600 + Math.floor(Math.random() * 40);
viewers.textContent = count.toLocaleString("en-US");
}, 2400);
}
/* Hero attempt counter easter egg */
var play = document.getElementById("stream-play");
var attempt = document.getElementById("attempt-count");
if (play && attempt) {
play.addEventListener("click", function () {
var n = parseInt(attempt.textContent, 10) + 1;
attempt.textContent = n;
toast("Boss attempt #" + n + " — copium engaged. Stream loading…");
});
}
/* ---------- Schedule tabs ---------- */
var SCHEDULE = {
mon: [
{ time: "6:00 PM", title: "Ranked grind", note: "Climbing to Masters, no excuses", tag: "Competitive" },
{ time: "9:00 PM", title: "Viewer co-op", note: "Squad up with Co-Op members", tag: "Members" }
],
tue: [
{ time: "7:00 PM", title: "Blind horror night", note: "New release, lights off, chat screaming", tag: "Horror" }
],
wed: [
{ time: "5:30 PM", title: "Roguelike runs", note: "One more run (a lie)", tag: "Roguelike" },
{ time: "10:00 PM", title: "Late-night chill", note: "Cozy indie + Q&A", tag: "Just Chatting" }
],
thu: [
{ time: "6:00 PM", title: "Speedrun practice", note: "Splits, resets, and rage", tag: "Speedrun" }
],
fri: [
{ time: "8:00 PM", title: "Fan Friday", note: "Polls pick the game, chat picks my pain", tag: "Variety" },
{ time: "11:00 PM", title: "Subathon stretch", note: "Goes til the timer dies", tag: "Special" }
],
sat: [
{ time: "2:00 PM", title: "Marathon stream", note: "6+ hours, snacks encouraged", tag: "Marathon" }
],
sun: [] // day off
};
var panel = document.getElementById("day-panel");
var tabs = Array.prototype.slice.call(document.querySelectorAll(".day-tab"));
function renderDay(day) {
if (!panel) return;
var slots = SCHEDULE[day] || [];
if (!slots.length) {
panel.innerHTML =
'<div class="day-empty"><span aria-hidden="true">😴</span>Day off — recovering HP. Catch the VODs in the clips section!</div>';
return;
}
panel.innerHTML = slots
.map(function (s) {
return (
'<div class="slot">' +
'<div class="slot-time">' + s.time + "</div>" +
'<div class="slot-title">' + s.title + "<small>" + s.note + "</small></div>" +
'<div class="slot-tag">' + s.tag + "</div>" +
"</div>"
);
})
.join("");
}
tabs.forEach(function (tab) {
tab.addEventListener("click", function () {
tabs.forEach(function (t) {
t.classList.remove("is-active");
t.setAttribute("aria-selected", "false");
});
tab.classList.add("is-active");
tab.setAttribute("aria-selected", "true");
renderDay(tab.getAttribute("data-day"));
});
});
// default to today (fallback Mon)
var dayKeys = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
var todayKey = dayKeys[new Date().getDay()];
var todayTab = tabs.filter(function (t) { return t.getAttribute("data-day") === todayKey; })[0] || tabs[0];
if (todayTab) {
tabs.forEach(function (t) { t.classList.remove("is-active"); t.setAttribute("aria-selected", "false"); });
todayTab.classList.add("is-active");
todayTab.setAttribute("aria-selected", "true");
renderDay(todayTab.getAttribute("data-day"));
}
/* ---------- Clip lightbox ---------- */
var CLIPS = [
{ title: "1 HP clutch in ranked finals", meta: "184K views · clipped by @pixel_remy" },
{ title: "Jumpscare ruins my whole life", meta: "921K views · clipped by @toastedmage" },
{ title: "Speedrun WR, live on stream", meta: "1.4M views · clipped by @gg_harlow" },
{ title: "Chat picks my entire loadout", meta: "67K views · clipped by @byte_sized" },
{ title: "200 IQ play I'll never repeat", meta: "302K views · clipped by @noscope_jin" },
{ title: "The rage that started it all", meta: "2.1M views · the origin clip" }
];
var lb = document.getElementById("lightbox");
var lbTitle = document.getElementById("lightbox-title");
var lbMeta = document.getElementById("lightbox-meta");
var lbClose = document.getElementById("lightbox-close");
var lastFocused = null;
function openClip(i) {
var c = CLIPS[i];
if (!c || !lb) return;
lastFocused = document.activeElement;
lbTitle.textContent = c.title;
lbMeta.textContent = c.meta;
lb.hidden = false;
requestAnimationFrame(function () { lb.classList.add("show"); });
lbClose.focus();
document.body.style.overflow = "hidden";
}
function closeClip() {
if (!lb) return;
lb.classList.remove("show");
document.body.style.overflow = "";
setTimeout(function () { lb.hidden = true; }, 250);
if (lastFocused) lastFocused.focus();
}
document.querySelectorAll(".clip").forEach(function (clip) {
function go() { openClip(parseInt(clip.getAttribute("data-clip"), 10)); }
clip.addEventListener("click", go);
clip.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); go(); }
});
});
if (lbClose) lbClose.addEventListener("click", closeClip);
if (lb) lb.addEventListener("click", function (e) { if (e.target === lb) closeClip(); });
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && lb && !lb.hidden) closeClip();
});
/* ---------- Newsletter ---------- */
var form = document.getElementById("newsletter");
var emailIn = document.getElementById("news-email");
var status = document.getElementById("news-status");
if (form) {
form.addEventListener("submit", function (e) {
e.preventDefault();
var val = (emailIn.value || "").trim();
var ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
if (!ok) {
status.textContent = "Hmm, that email looks invalid — try again.";
status.className = "news-status err";
emailIn.focus();
return;
}
status.textContent = "You're in! Stream alerts incoming. GLHF 🎮";
status.className = "news-status ok";
emailIn.value = "";
toast("Subscribed — see you in the next stream!");
});
}
/* ---------- Scroll reveal ---------- */
var revealEls = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(
function (entries) {
entries.forEach(function (en) {
if (en.isIntersecting) {
en.target.classList.add("in");
io.unobserve(en.target);
}
});
},
{ threshold: 0.12, rootMargin: "0px 0px -8% 0px" }
);
revealEls.forEach(function (el) { io.observe(el); });
} else {
revealEls.forEach(function (el) { el.classList.add("in"); });
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>NOVA_BYTE — Streamer & Variety Gamer</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=Chakra+Petch:wght@500;600;700&family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<!-- ===== NAV ===== -->
<header class="nav" id="top">
<div class="nav-inner">
<a href="#top" class="logo" aria-label="NOVA_BYTE home">
<span class="logo-mark" aria-hidden="true">◈</span>
<span class="logo-text">NOVA<span class="logo-accent">_BYTE</span></span>
</a>
<nav class="nav-links" id="nav-links" aria-label="Primary">
<a href="#schedule">Schedule</a>
<a href="#clips">Clips</a>
<a href="#tiers">Membership</a>
<a href="#gear">Gear</a>
<a href="#community">Community</a>
<a class="btn btn-watch nav-cta" href="#hero" data-toast="Opening the live channel…">▶ Watch Live</a>
</nav>
<button class="nav-toggle" id="nav-toggle" aria-expanded="false" aria-controls="nav-links" aria-label="Toggle navigation menu">
<span></span><span></span><span></span>
</button>
</div>
</header>
<main id="main">
<!-- ===== HERO ===== -->
<section class="hero" id="hero">
<div class="hero-grid-bg" aria-hidden="true"></div>
<div class="hero-glow" aria-hidden="true"></div>
<div class="hero-inner">
<div class="hero-copy reveal">
<span class="live-badge" id="live-badge">
<span class="live-dot" aria-hidden="true"></span>
<span class="live-text">LIVE NOW</span>
<span class="live-viewers" id="live-viewers">4,218</span> watching
</span>
<h1 class="hero-title">Hey, I'm <span class="handle">@NOVA_BYTE</span></h1>
<p class="hero-tag">Variety streamer, ranked grinder, and your chaotic-good co-op buddy. Roguelikes by day, horror with chat by night — six nights a week.</p>
<div class="hero-actions">
<a class="btn btn-watch" href="#clips" data-toast="Launching the live stream… GLHF!">▶ Watch Live</a>
<a class="btn btn-ghost" href="#tiers">Become a member</a>
</div>
<ul class="hero-stats" aria-label="Channel stats">
<li><strong>312K</strong><span>Followers</span></li>
<li><strong>1,940</strong><span>Members</span></li>
<li><strong>6 nights</strong><span>Every week</span></li>
</ul>
</div>
<div class="hero-visual reveal">
<div class="stream-card">
<div class="stream-thumb" id="stream-thumb" role="img" aria-label="Current stream preview: Hollow Embers — boss run">
<span class="stream-game">HOLLOW EMBERS</span>
<button class="stream-play" id="stream-play" aria-label="Play stream preview">▶</button>
<span class="stream-live-tag">● LIVE</span>
</div>
<div class="stream-meta">
<div class="stream-title">No-hit boss run (attempt <span id="attempt-count">47</span>)</div>
<div class="stream-sub">Souls-like · ranked rage · cozy chat</div>
</div>
</div>
</div>
</div>
</section>
<!-- ===== SCHEDULE ===== -->
<section class="section schedule" id="schedule">
<div class="section-head reveal">
<span class="eyebrow">Stream schedule</span>
<h2>When to catch me live</h2>
<p class="lede">All times Pacific (PT). Notifications on = you never miss a meltdown.</p>
</div>
<div class="day-tabs reveal" role="tablist" aria-label="Weekly schedule">
<button class="day-tab is-active" role="tab" aria-selected="true" data-day="mon">Mon</button>
<button class="day-tab" role="tab" aria-selected="false" data-day="tue">Tue</button>
<button class="day-tab" role="tab" aria-selected="false" data-day="wed">Wed</button>
<button class="day-tab" role="tab" aria-selected="false" data-day="thu">Thu</button>
<button class="day-tab" role="tab" aria-selected="false" data-day="fri">Fri</button>
<button class="day-tab" role="tab" aria-selected="false" data-day="sat">Sat</button>
<button class="day-tab is-off" role="tab" aria-selected="false" data-day="sun">Sun</button>
</div>
<div class="day-panel reveal" id="day-panel" role="tabpanel" aria-live="polite">
<!-- filled by JS -->
</div>
</section>
<!-- ===== CLIPS ===== -->
<section class="section clips" id="clips">
<div class="section-head reveal">
<span class="eyebrow">Best of the stream</span>
<h2>Latest clips & VODs</h2>
<p class="lede">The funniest fails and cleanest plays, clipped by chat.</p>
</div>
<div class="clip-grid">
<article class="clip reveal" data-clip="0" tabindex="0" role="button" aria-label="Play clip: One HP clutch in ranked finals">
<div class="clip-thumb clip-a"><span class="clip-dur">0:42</span></div>
<div class="clip-info"><h3>1 HP clutch in ranked finals</h3><span>184K views</span></div>
</article>
<article class="clip reveal" data-clip="1" tabindex="0" role="button" aria-label="Play clip: Jumpscare ruins my whole life">
<div class="clip-thumb clip-b"><span class="clip-dur">1:08</span></div>
<div class="clip-info"><h3>Jumpscare ruins my whole life</h3><span>921K views</span></div>
</article>
<article class="clip reveal" data-clip="2" tabindex="0" role="button" aria-label="Play clip: Speedrun world record, live on stream">
<div class="clip-thumb clip-c"><span class="clip-dur">2:15</span></div>
<div class="clip-info"><h3>Speedrun WR, live on stream</h3><span>1.4M views</span></div>
</article>
<article class="clip reveal" data-clip="3" tabindex="0" role="button" aria-label="Play clip: Chat picks my entire loadout">
<div class="clip-thumb clip-d"><span class="clip-dur">0:56</span></div>
<div class="clip-info"><h3>Chat picks my entire loadout</h3><span>67K views</span></div>
</article>
<article class="clip reveal" data-clip="4" tabindex="0" role="button" aria-label="Play clip: 200 IQ play I will never repeat">
<div class="clip-thumb clip-e"><span class="clip-dur">0:33</span></div>
<div class="clip-info"><h3>200 IQ play I'll never repeat</h3><span>302K views</span></div>
</article>
<article class="clip reveal" data-clip="5" tabindex="0" role="button" aria-label="Play clip: The rage that started it all">
<div class="clip-thumb clip-f"><span class="clip-dur">1:41</span></div>
<div class="clip-info"><h3>The rage that started it all</h3><span>2.1M views</span></div>
</article>
</div>
</section>
<!-- ===== ABOUT ===== -->
<section class="section about" id="about">
<div class="about-inner">
<div class="about-portrait reveal" role="img" aria-label="Stylized portrait of NOVA_BYTE">
<span class="about-emoji" aria-hidden="true">🎮</span>
<span class="about-ring" aria-hidden="true"></span>
</div>
<div class="about-copy reveal">
<span class="eyebrow">About</span>
<h2>Just a gremlin with good ping</h2>
<p>I'm Nova — full-time variety streamer based in the PNW. Five years ago I was speedrunning in my closet at 3am; now we've built one of the warmest, weirdest little corners of the internet. We do ranked grinds, blind horror playthroughs, indie gem nights, and the occasional 24-hour charity marathon.</p>
<p>This page is fan-first: the schedule, the clips, the Discord, the perks. No algorithm gatekeeping — just bookmark it and pull up whenever the LIVE dot turns green.</p>
<ul class="about-tags">
<li>Souls-likes</li><li>Roguelikes</li><li>Horror</li><li>Speedrunning</li><li>Cozy indie</li>
</ul>
</div>
</div>
</section>
<!-- ===== TIERS ===== -->
<section class="section tiers" id="tiers">
<div class="section-head reveal">
<span class="eyebrow">Support the channel</span>
<h2>Membership tiers</h2>
<p class="lede">Every sub keeps the lights (and the RGB) on. Cancel anytime.</p>
</div>
<div class="tier-grid">
<article class="tier reveal">
<h3>Sidekick</h3>
<div class="tier-price">$4.99<span>/mo</span></div>
<ul>
<li>Ad-free streams</li>
<li>2 custom emotes</li>
<li>Member-only chat badge</li>
<li>Discord member role</li>
</ul>
<button class="btn btn-ghost tier-btn" data-toast="Subscribed to Sidekick — welcome aboard!">Join Sidekick</button>
</article>
<article class="tier tier-featured reveal">
<span class="tier-flag">Most popular</span>
<h3>Co-Op</h3>
<div class="tier-price">$9.99<span>/mo</span></div>
<ul>
<li>Everything in Sidekick</li>
<li>10 emotes + animated set</li>
<li>Monthly members-only stream</li>
<li>Vote on next-game polls</li>
<li>Priority in viewer game nights</li>
</ul>
<button class="btn btn-watch tier-btn" data-toast="Subscribed to Co-Op — see you in viewer games!">Join Co-Op</button>
</article>
<article class="tier reveal">
<h3>Final Boss</h3>
<div class="tier-price">$24.99<span>/mo</span></div>
<ul>
<li>Everything in Co-Op</li>
<li>Name in every stream credits</li>
<li>Quarterly 1:1 gaming session</li>
<li>Limited-run member merch drop</li>
</ul>
<button class="btn btn-ghost tier-btn" data-toast="Subscribed to Final Boss — you legend!">Join Final Boss</button>
</article>
</div>
</section>
<!-- ===== PRESS / TESTIMONIALS ===== -->
<section class="section press" id="press">
<div class="section-head reveal">
<span class="eyebrow">The chat speaks</span>
<h2>What the community says</h2>
</div>
<div class="quote-grid">
<figure class="quote reveal">
<blockquote>"Found Nova during a 3am horror stream and now my entire sleep schedule is ruined. Worth it."</blockquote>
<figcaption><span class="q-name">@pixel_remy</span> · Co-Op member, 2 yrs</figcaption>
</figure>
<figure class="quote reveal">
<blockquote>"The only streamer who reads chat AND remembers your username. The community feels like a tiny weird family."</blockquote>
<figcaption><span class="q-name">@gg_harlow</span> · Final Boss member</figcaption>
</figure>
<figure class="quote reveal">
<blockquote>"Watched the 24h charity marathon. Cried twice, laughed forty times, donated my whole allowance."</blockquote>
<figcaption><span class="q-name">@toastedmage</span> · Discord mod</figcaption>
</figure>
</div>
</section>
<!-- ===== GEAR / SPONSORS ===== -->
<section class="section gear" id="gear">
<div class="section-head reveal">
<span class="eyebrow">Powered by</span>
<h2>Sponsors & gear</h2>
<p class="lede">Code <strong>NOVA</strong> at checkout for a fan discount (and to throw me a few coins).</p>
</div>
<div class="gear-grid reveal">
<div class="gear-logo">HEXKEY</div>
<div class="gear-logo">VOLTCHAIR</div>
<div class="gear-logo">AURACAST</div>
<div class="gear-logo">FRAGFUEL</div>
<div class="gear-logo">NEONNET</div>
<div class="gear-logo">PIXLPAD</div>
</div>
</section>
<!-- ===== COMMUNITY ===== -->
<section class="section community" id="community">
<div class="community-inner reveal">
<div class="community-copy">
<span class="eyebrow">Don't lurk alone</span>
<h2>Join the Discord</h2>
<p>14,000+ goblins sharing clips, LFG pings, meme threads, and patch-night watch parties. It's the real hub between streams.</p>
<div class="community-actions">
<a class="btn btn-watch" href="#community" data-toast="Opening the Discord invite…">Join the Discord</a>
<a class="btn btn-ghost" href="#newsletter">Get the newsletter</a>
</div>
<div class="socials" aria-label="Social links">
<a href="#community" data-toast="Follow on Twitch">Twitch</a>
<a href="#community" data-toast="Follow on YouTube">YouTube</a>
<a href="#community" data-toast="Follow on TikTok">TikTok</a>
<a href="#community" data-toast="Follow on X">X / Twitter</a>
<a href="#community" data-toast="Follow on Instagram">Instagram</a>
</div>
</div>
<form class="newsletter" id="newsletter" novalidate>
<h3>Stream alerts in your inbox</h3>
<p>Schedule changes, special streams, and member drops. No spam, unsub anytime.</p>
<div class="news-row">
<label class="sr-only" for="news-email">Email address</label>
<input id="news-email" type="email" placeholder="you@example.com" required />
<button class="btn btn-watch" type="submit">Notify me</button>
</div>
<p class="news-status" id="news-status" role="status" aria-live="polite"></p>
</form>
</div>
</section>
</main>
<!-- ===== FOOTER ===== -->
<footer class="footer">
<div class="footer-inner">
<div class="footer-brand">
<span class="logo-mark" aria-hidden="true">◈</span>
<span class="logo-text">NOVA<span class="logo-accent">_BYTE</span></span>
<p>Variety streaming, six nights a week. GG & GLHF.</p>
</div>
<nav class="footer-links" aria-label="Footer">
<a href="#schedule">Schedule</a>
<a href="#clips">Clips</a>
<a href="#tiers">Membership</a>
<a href="#gear">Gear</a>
<a href="#community">Community</a>
</nav>
</div>
<p class="footer-legal">© 2026 NOVA_BYTE. Fictional creator — for demo purposes only. <a href="#top">Back to top ↑</a></p>
</footer>
<!-- toast -->
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<!-- lightbox -->
<div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-label="Clip preview" hidden>
<button class="lightbox-close" id="lightbox-close" aria-label="Close clip">✕</button>
<div class="lightbox-body">
<div class="lightbox-screen" id="lightbox-screen"><span class="lightbox-play">▶</span></div>
<h3 id="lightbox-title">Clip</h3>
<p id="lightbox-meta"></p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>Streamer / Gamer Landing
A fan-first, one-page personal-brand site for a fictional variety streamer, @NOVA_BYTE. The identity is electric and energetic: a near-black background, a violet (#8b5cf6) accent, and a neon-green call-to-action color, paired with the Chakra Petch display face for that gamer-overlay feel. The hero leads with the handle, a pulsing “LIVE NOW” badge whose viewer count drifts in real time, a glowing watch CTA, and a tilted stream-preview card with a clickable boss-attempt counter.
Below the hero, the page flows through the sections a streamer audience actually wants: a tabbed weekly schedule that auto-selects today’s day and shows a rest-day state on Sundays, a clip gallery whose cards open an accessible, keyboard- and Escape-dismissable lightbox, an about block, three membership sub tiers with a highlighted “most popular” plan, community testimonials, a sponsors-and-gear strip, a Discord community panel with socials, and a validated newsletter form. A footer rounds it out.
Everything runs on vanilla JavaScript with no dependencies: the mobile nav toggle, smooth in-page scrolling, IntersectionObserver scroll reveals, the schedule tab switching, the clip lightbox with focus management, email validation, and a reusable toast(msg) helper wired to every CTA via data-toast. It is fully responsive down to ~360px and respects prefers-reduced-motion.
Illustrative UI only — fictional creator, not a real person or brand.