LMS — Coding Bootcamp Landing
A high-energy, career-focused coding bootcamp landing page built with semantic HTML, CSS variables, and vanilla JavaScript. Features a bold technical-mono hero with animated outcome counters, a four-phase curriculum timeline, a filterable tech-stack grid, mentor cards, hiring-partner logos, three financing options, and an interactive cohort-date picker with toast feedback. The dark neon-green theme, conic-gradient progress rings, scroll reveal, sticky nav, and responsive mobile menu make it feel like a real bootcamp site down to 360px screens.
MCP
Code
:root {
/* Coding bootcamp palette */
--bg: #0d0d12;
--bg-2: #121219;
--surface: #16161f;
--surface-2: #1c1c28;
--neon: #2bff88;
--neon-d: #1fcf6c;
--neon-50: rgba(43, 255, 136, 0.1);
--brand: #5b5bd6;
--amber: #f59e0b;
--danger: #e05656;
--ink: #f4f5fb;
--ink-2: #c4c6d6;
--muted: #8a8da4;
--line: rgba(255, 255, 255, 0.08);
--line-2: rgba(255, 255, 255, 0.14);
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--shadow: 0 18px 50px -20px rgba(0, 0, 0, 0.7);
--glow: 0 0 0 1px rgba(43, 255, 136, 0.3), 0 0 40px -8px rgba(43, 255, 136, 0.4);
--mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
--sans: "Inter", system-ui, -apple-system, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; scroll-padding-top: 84px; }
body {
font-family: var(--sans);
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
.wrap { width: min(1140px, 92vw); margin-inline: auto; }
a { color: inherit; text-decoration: none; }
.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: 8px;
font-family: var(--sans); font-weight: 600; font-size: 14px;
padding: 10px 18px; border-radius: var(--r-sm);
border: 1px solid transparent; cursor: pointer;
transition: transform .15s ease, box-shadow .2s ease, background .2s ease, border-color .2s ease;
white-space: nowrap;
}
.btn:active { transform: translateY(1px) scale(.99); }
.btn-primary { background: var(--neon); color: #06210f; box-shadow: 0 8px 24px -10px rgba(43,255,136,.6); }
.btn-primary:hover { background: var(--neon-d); box-shadow: var(--glow); transform: translateY(-1px); }
.btn-ghost { color: var(--ink-2); background: transparent; }
.btn-ghost:hover { color: var(--ink); background: var(--surface-2); }
.btn-outline { background: transparent; border-color: var(--line-2); color: var(--ink); }
.btn-outline:hover { border-color: var(--neon); color: var(--neon); }
.btn-lg { padding: 14px 26px; font-size: 15px; }
.btn-block { width: 100%; margin-top: auto; }
.kicker {
font-family: var(--mono); font-size: 13px; font-weight: 600;
color: var(--neon); letter-spacing: .04em; text-transform: lowercase;
}
/* NAV */
.nav {
position: sticky; top: 0; z-index: 50;
background: rgba(13,13,18,.72); backdrop-filter: blur(14px);
border-bottom: 1px solid var(--line);
transition: box-shadow .3s ease, background .3s ease;
}
.nav.scrolled { box-shadow: 0 8px 30px -18px rgba(0,0,0,.8); background: rgba(13,13,18,.92); }
.nav-inner { display: flex; align-items: center; gap: 24px; height: 68px; }
.brand { display: inline-flex; align-items: center; gap: 9px; font-family: var(--mono); font-weight: 800; font-size: 18px; }
.brand-mark {
display: inline-grid; place-items: center; width: 30px; height: 30px;
background: var(--neon); color: #06210f; border-radius: 7px; font-size: 14px;
box-shadow: 0 0 18px -4px rgba(43,255,136,.7);
}
.brand-accent { color: var(--neon); }
.nav-links { display: flex; gap: 26px; margin-left: 12px; }
.nav-links a { font-size: 14px; color: var(--ink-2); font-weight: 500; position: relative; transition: color .2s; }
.nav-links a::after {
content: ""; position: absolute; left: 0; bottom: -6px; height: 2px; width: 0;
background: var(--neon); transition: width .2s ease;
}
.nav-links a:hover { color: var(--ink); }
.nav-links a:hover::after { width: 100%; }
.nav-cta { display: flex; gap: 10px; margin-left: auto; }
.nav-toggle {
display: none; flex-direction: column; gap: 5px; background: none; border: 0;
cursor: pointer; padding: 8px; margin-left: auto;
}
.nav-toggle span { width: 24px; height: 2px; background: var(--ink); border-radius: 2px; transition: .25s; }
.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); }
.mobile-menu {
display: flex; flex-direction: column; gap: 6px; padding: 16px 4vw 22px;
border-top: 1px solid var(--line); background: var(--bg-2);
}
.mobile-menu a { padding: 10px 6px; font-size: 15px; color: var(--ink-2); border-radius: var(--r-sm); }
.mobile-menu a:not(.btn):hover { background: var(--surface-2); color: var(--ink); }
.mobile-menu .btn { justify-content: center; margin-top: 4px; }
/* HERO */
.hero { position: relative; padding: 72px 0 60px; overflow: hidden; }
.grid-bg {
position: absolute; inset: -2px; z-index: 0;
background-image:
linear-gradient(rgba(43,255,136,.06) 1px, transparent 1px),
linear-gradient(90deg, rgba(43,255,136,.06) 1px, transparent 1px);
background-size: 44px 44px;
mask-image: radial-gradient(ellipse 80% 60% at 50% 30%, #000 40%, transparent 100%);
}
.hero-inner { position: relative; z-index: 1; text-align: center; }
.eyebrow {
display: inline-flex; align-items: center; gap: 8px;
font-family: var(--mono); font-size: 13px; font-weight: 500; color: var(--neon);
background: var(--neon-50); border: 1px solid rgba(43,255,136,.25);
padding: 7px 14px; border-radius: 100px; margin-bottom: 22px;
}
.pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--neon); box-shadow: 0 0 0 0 rgba(43,255,136,.6); animation: pulse 2s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(43,255,136,.6); } 70% { box-shadow: 0 0 0 9px rgba(43,255,136,0); } 100% { box-shadow: 0 0 0 0 rgba(43,255,136,0); } }
.hero-title {
font-family: var(--mono); font-weight: 800; letter-spacing: -.02em;
font-size: clamp(2.1rem, 6vw, 4rem); line-height: 1.06; margin-bottom: 22px;
}
.glitch { color: var(--neon); position: relative; }
.glitch::before, .glitch::after {
content: attr(data-text); position: absolute; left: 0; top: 0; width: 100%;
clip-path: inset(0 0 0 0); opacity: .65;
}
.glitch::before { color: var(--brand); animation: glitch 3.4s infinite; }
.glitch::after { color: var(--amber); animation: glitch 3.4s infinite reverse; }
@keyframes glitch {
0%, 92%, 100% { transform: translate(0,0); opacity: 0; }
93% { transform: translate(-2px,1px); opacity: .55; }
95% { transform: translate(2px,-1px); opacity: .55; }
97% { transform: translate(-1px,0); opacity: .4; }
}
.hero-sub { max-width: 620px; margin: 0 auto 30px; color: var(--ink-2); font-size: clamp(1rem, 2.2vw, 1.15rem); }
.hero-actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; margin-bottom: 52px; }
.hero-stats {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
max-width: 880px; margin: 0 auto;
}
.stat {
background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-md); padding: 22px 16px; text-align: left;
transition: border-color .2s, transform .2s;
}
.stat:hover { border-color: rgba(43,255,136,.4); transform: translateY(-3px); }
.stat-num { font-family: var(--mono); font-weight: 800; font-size: clamp(1.5rem, 4vw, 2.1rem); color: var(--neon); line-height: 1; }
.stat-label { font-size: 12.5px; color: var(--muted); margin-top: 10px; line-height: 1.35; }
/* PARTNERS */
.partners { padding: 8px 0 44px; border-bottom: 1px solid var(--line); }
.partners-label { text-align: center; font-family: var(--mono); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin-bottom: 20px; }
.partner-row { display: flex; flex-wrap: wrap; gap: 14px 34px; justify-content: center; align-items: center; }
.partner-row .logo {
font-family: var(--mono); font-weight: 700; font-size: 17px; color: var(--ink-2);
opacity: .65; letter-spacing: -.01em; transition: opacity .2s, color .2s, transform .2s; cursor: default;
}
.partner-row .logo:hover { opacity: 1; color: var(--neon); transform: translateY(-2px); }
/* SECTION */
.section { padding: 84px 0; }
.section-dark { background: var(--bg-2); border-block: 1px solid var(--line); }
.section-head { max-width: 640px; margin: 0 auto 48px; text-align: center; }
.section-head h2 { font-size: clamp(1.6rem, 4vw, 2.4rem); font-weight: 800; letter-spacing: -.02em; margin: 12px 0; }
.section-head p { color: var(--ink-2); font-size: 1.02rem; }
/* OUTCOMES */
.outcome-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.o-card {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
padding: 32px 26px; text-align: center; transition: border-color .25s, transform .25s;
}
.o-card:hover { border-color: rgba(43,255,136,.4); transform: translateY(-4px); }
.ring {
--p: 0; width: 116px; height: 116px; border-radius: 50%; margin: 0 auto 18px;
display: grid; place-items: center; position: relative;
background: conic-gradient(var(--neon) calc(var(--p) * 1%), var(--surface-2) 0);
transition: background .1s linear;
}
.ring::before { content: ""; position: absolute; inset: 9px; border-radius: 50%; background: var(--surface); }
.ring span { position: relative; font-family: var(--mono); font-weight: 800; font-size: 1.5rem; color: var(--neon); }
.o-card h3 { font-size: 1.15rem; margin-bottom: 8px; }
.o-card p { color: var(--muted); font-size: .92rem; }
/* TIMELINE */
.timeline { list-style: none; position: relative; max-width: 760px; margin: 0 auto; }
.timeline::before {
content: ""; position: absolute; left: 23px; top: 14px; bottom: 14px; width: 2px;
background: linear-gradient(var(--neon), rgba(43,255,136,.12));
}
.t-item { display: flex; gap: 22px; padding-bottom: 30px; position: relative; }
.t-item:last-child { padding-bottom: 0; }
.t-marker {
flex: 0 0 48px; width: 48px; height: 48px; border-radius: 12px;
background: var(--surface); border: 1px solid var(--line-2);
display: grid; place-items: center; font-family: var(--mono); font-weight: 800; color: var(--neon);
z-index: 1; position: relative;
}
.t-marker-final { background: var(--neon); color: #06210f; border-color: var(--neon); box-shadow: var(--glow); }
.t-body {
flex: 1; background: var(--surface); border: 1px solid var(--line);
border-radius: var(--r-md); padding: 20px 22px; transition: border-color .2s, transform .2s;
}
.t-body:hover { border-color: rgba(43,255,136,.35); transform: translateX(4px); }
.t-top { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 8px; }
.t-top h3 { font-size: 1.15rem; }
.pill {
font-family: var(--mono); font-size: 11.5px; font-weight: 600; padding: 4px 10px;
border-radius: 100px; white-space: nowrap;
}
.pill-week { background: var(--neon-50); color: var(--neon); border: 1px solid rgba(43,255,136,.25); }
.t-body > p { color: var(--ink-2); font-size: .94rem; margin-bottom: 12px; }
.t-tags { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 12px; }
.t-tags span {
font-family: var(--mono); font-size: 11.5px; color: var(--ink-2);
background: var(--surface-2); border: 1px solid var(--line); padding: 4px 9px; border-radius: var(--r-sm);
}
.t-project { font-size: .88rem; color: var(--muted); padding-top: 10px; border-top: 1px dashed var(--line-2); }
.t-project strong { color: var(--neon); font-family: var(--mono); font-weight: 600; }
/* STACK */
.stack-filter { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-bottom: 32px; }
.chip {
font-family: var(--sans); font-size: 13.5px; font-weight: 600; color: var(--ink-2);
background: var(--surface); border: 1px solid var(--line-2); padding: 8px 18px;
border-radius: 100px; cursor: pointer; transition: .2s;
}
.chip:hover { border-color: var(--neon); color: var(--ink); }
.chip.is-active { background: var(--neon); color: #06210f; border-color: var(--neon); }
.stack-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.tech {
display: flex; align-items: center; gap: 12px; padding: 16px 18px;
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
font-weight: 600; font-size: .95rem; transition: border-color .2s, transform .2s, opacity .25s, filter .25s;
}
.tech:hover { border-color: rgba(43,255,136,.4); transform: translateY(-3px); }
.tech.dim { opacity: .25; filter: grayscale(1); }
.tech-glyph {
display: grid; place-items: center; width: 36px; height: 36px; flex: 0 0 36px;
background: var(--surface-2); border-radius: var(--r-sm); font-family: var(--mono);
font-weight: 800; font-size: 14px; color: var(--neon);
}
/* MENTORS */
.mentor-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.mentor {
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
padding: 28px 24px; transition: border-color .25s, transform .25s;
}
.mentor:hover { border-color: rgba(43,255,136,.35); transform: translateY(-4px); }
.m-avatar {
width: 56px; height: 56px; border-radius: 14px; margin-bottom: 16px;
display: grid; place-items: center; font-family: var(--mono); font-weight: 800; font-size: 18px;
color: #06210f; background: var(--m, var(--neon));
box-shadow: 0 8px 20px -8px var(--m, var(--neon));
}
.m-avatar::after { content: attr(data-initials); }
.mentor h3 { font-size: 1.12rem; }
.m-role { font-family: var(--mono); font-size: 12.5px; color: var(--neon); margin: 4px 0 12px; }
.m-bio { color: var(--ink-2); font-size: .92rem; margin-bottom: 14px; }
.m-tags { display: flex; gap: 7px; flex-wrap: wrap; }
.m-tags span {
font-family: var(--mono); font-size: 11px; color: var(--ink-2);
background: var(--surface-2); border: 1px solid var(--line); padding: 3px 9px; border-radius: var(--r-sm);
}
/* FINANCING */
.finance-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; align-items: stretch; }
.fin {
display: flex; flex-direction: column; position: relative;
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
padding: 30px 26px; transition: border-color .25s, transform .25s;
}
.fin:hover { border-color: rgba(43,255,136,.35); transform: translateY(-4px); }
.fin-featured { border-color: var(--neon); box-shadow: var(--glow); }
.fin-badge {
position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
font-family: var(--mono); font-size: 11px; font-weight: 700; color: #06210f;
background: var(--neon); padding: 5px 14px; border-radius: 100px; white-space: nowrap;
}
.fin h3 { font-size: 1.2rem; margin-bottom: 10px; }
.fin-price { font-family: var(--mono); font-weight: 800; font-size: 2rem; color: var(--ink); line-height: 1; }
.fin-price span { display: block; font-size: 12px; font-weight: 500; color: var(--muted); margin-top: 6px; }
.fin-save { color: var(--neon); font-size: .85rem; font-weight: 600; margin: 14px 0; }
.fin ul { list-style: none; margin-bottom: 22px; display: grid; gap: 10px; }
.fin li { position: relative; padding-left: 24px; color: var(--ink-2); font-size: .92rem; }
.fin li::before { content: "✓"; position: absolute; left: 0; color: var(--neon); font-weight: 800; }
/* COHORTS */
.cohorts { padding: 84px 0; background: linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%); }
.cohorts-inner { display: grid; grid-template-columns: 1fr 1.1fr; gap: 40px; align-items: center; }
.cohorts-copy h2 { font-size: clamp(1.6rem, 4vw, 2.3rem); font-weight: 800; letter-spacing: -.02em; margin: 12px 0; }
.cohorts-copy p { color: var(--ink-2); }
.cohort-list { display: grid; gap: 12px; }
.cohort {
display: flex; align-items: center; gap: 18px; text-align: left; width: 100%;
background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
padding: 16px 18px; cursor: pointer; font-family: var(--sans); color: var(--ink);
transition: border-color .2s, transform .2s, background .2s;
}
.cohort:hover { border-color: rgba(43,255,136,.4); transform: translateX(4px); }
.cohort.is-selected { border-color: var(--neon); background: var(--neon-50); box-shadow: var(--glow); }
.c-date {
flex: 0 0 56px; width: 56px; height: 56px; border-radius: 12px; background: var(--surface-2);
display: grid; place-items: center; line-height: 1; border: 1px solid var(--line);
}
.cohort.is-selected .c-date { background: var(--neon); border-color: var(--neon); }
.c-day { font-family: var(--mono); font-weight: 800; font-size: 1.4rem; }
.cohort.is-selected .c-day, .cohort.is-selected .c-mon { color: #06210f; }
.c-mon { font-family: var(--mono); font-size: 10px; letter-spacing: .1em; color: var(--muted); }
.c-info { flex: 1; display: flex; flex-direction: column; gap: 3px; }
.c-info strong { font-size: 1rem; }
.c-info span { font-size: 12.5px; color: var(--muted); }
.c-seats {
font-family: var(--mono); font-size: 12px; font-weight: 600; color: var(--ink-2);
background: var(--surface-2); padding: 5px 11px; border-radius: 100px; white-space: nowrap;
}
.c-seats-low { color: var(--amber); background: rgba(245,158,11,.12); }
/* APPLY */
.apply { padding: 80px 0; }
.apply-inner {
text-align: center; max-width: 620px; background: var(--surface);
border: 1px solid var(--line-2); border-radius: var(--r-lg); padding: 46px 32px;
box-shadow: var(--shadow); position: relative; overflow: hidden;
}
.apply-inner::before {
content: ""; position: absolute; inset: 0; pointer-events: none;
background: radial-gradient(circle at 50% -20%, rgba(43,255,136,.14), transparent 60%);
}
.apply-inner h2 { font-size: clamp(1.5rem, 4vw, 2.1rem); font-weight: 800; letter-spacing: -.02em; position: relative; }
.apply-inner > p { color: var(--ink-2); margin: 12px auto 26px; max-width: 460px; position: relative; }
.apply-form { display: flex; gap: 10px; max-width: 480px; margin: 0 auto; position: relative; }
.apply-form input {
flex: 1; background: var(--bg); border: 1px solid var(--line-2); border-radius: var(--r-sm);
padding: 14px 16px; color: var(--ink); font-family: var(--sans); font-size: 15px;
transition: border-color .2s, box-shadow .2s;
}
.apply-form input::placeholder { color: var(--muted); }
.apply-form input:focus { outline: none; border-color: var(--neon); box-shadow: 0 0 0 3px rgba(43,255,136,.18); }
.apply-form input.invalid { border-color: var(--danger); box-shadow: 0 0 0 3px rgba(224,86,86,.18); }
.apply-note { font-size: 12.5px; color: var(--muted); margin-top: 16px; position: relative; }
.apply-note #selectedCohort { color: var(--neon); font-family: var(--mono); }
/* FOOTER */
.footer { background: var(--bg-2); border-top: 1px solid var(--line); padding: 56px 0 28px; }
.footer-inner { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 36px; margin-bottom: 40px; }
.footer-brand p { color: var(--muted); font-size: .9rem; margin-top: 14px; max-width: 280px; }
.footer-col h4 { font-family: var(--mono); font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 14px; }
.footer-col a { display: block; color: var(--ink-2); font-size: .92rem; padding: 5px 0; transition: color .2s; }
.footer-col a:hover { color: var(--neon); }
.footer-bottom {
display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap;
padding-top: 22px; border-top: 1px solid var(--line); color: var(--muted); font-size: 12.5px;
}
.footer-mono { font-family: var(--mono); color: var(--neon); opacity: .7; }
/* TOAST */
.toast {
position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 24px);
background: var(--surface-2); color: var(--ink); border: 1px solid var(--neon);
font-family: var(--mono); font-size: 13.5px; padding: 12px 20px; border-radius: var(--r-sm);
box-shadow: var(--glow); opacity: 0; pointer-events: none; z-index: 100;
transition: opacity .3s ease, transform .3s ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
/* REVEAL */
.reveal { opacity: 0; transform: translateY(22px); transition: opacity .6s ease, transform .6s ease; }
.reveal.in { opacity: 1; transform: none; }
/* RESPONSIVE */
@media (max-width: 920px) {
.nav-links, .nav-cta { display: none; }
.nav-toggle { display: flex; }
.hero-stats { grid-template-columns: repeat(2, 1fr); }
.outcome-grid, .mentor-grid, .finance-grid { grid-template-columns: 1fr; }
.stack-grid { grid-template-columns: repeat(3, 1fr); }
.cohorts-inner { grid-template-columns: 1fr; }
.footer-inner { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
.hero { padding: 48px 0 40px; }
.section { padding: 60px 0; }
.hero-actions .btn { width: 100%; }
.hero-stats { grid-template-columns: 1fr 1fr; gap: 10px; }
.stack-grid { grid-template-columns: 1fr 1fr; }
.apply-form { flex-direction: column; }
.apply-form .btn { width: 100%; }
.footer-inner { grid-template-columns: 1fr; }
.t-item { gap: 14px; }
.footer-bottom { flex-direction: column; align-items: flex-start; }
}
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; scroll-behavior: auto; }
.reveal { opacity: 1; transform: none; }
}(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);
}
/* ---------- Sticky nav shadow ---------- */
var nav = document.getElementById("nav");
function onScroll() {
if (!nav) return;
nav.classList.toggle("scrolled", window.scrollY > 12);
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- Mobile menu ---------- */
var toggle = document.getElementById("navToggle");
var menu = document.getElementById("mobileMenu");
if (toggle && menu) {
toggle.addEventListener("click", function () {
var open = toggle.getAttribute("aria-expanded") === "true";
toggle.setAttribute("aria-expanded", String(!open));
menu.hidden = open;
});
menu.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
toggle.setAttribute("aria-expanded", "false");
menu.hidden = true;
});
});
}
/* ---------- Animated counters ---------- */
function animateCount(el) {
var target = parseFloat(el.getAttribute("data-count")) || 0;
var prefix = el.getAttribute("data-prefix") || "";
var suffix = el.getAttribute("data-suffix") || "";
var dur = 1500;
var start = null;
function step(ts) {
if (start === null) start = ts;
var p = Math.min((ts - start) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3); // easeOutCubic
var val = Math.round(target * eased);
el.textContent = prefix + val.toLocaleString() + suffix;
if (p < 1) requestAnimationFrame(step);
else el.textContent = prefix + target.toLocaleString() + suffix;
}
requestAnimationFrame(step);
}
/* ---------- Progress rings ---------- */
function animateRing(el) {
var target = parseFloat(el.getAttribute("data-ring")) || 0;
var dur = 1400;
var start = null;
function step(ts) {
if (start === null) start = ts;
var p = Math.min((ts - start) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3);
el.style.setProperty("--p", (target * eased).toFixed(1));
if (p < 1) requestAnimationFrame(step);
else el.style.setProperty("--p", target);
}
requestAnimationFrame(step);
}
/* ---------- IntersectionObserver: reveal + trigger animations ---------- */
var countersDone = false;
if ("IntersectionObserver" in window) {
var revealObs = new IntersectionObserver(
function (entries, obs) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("in");
obs.unobserve(entry.target);
}
});
},
{ threshold: 0.14 }
);
document.querySelectorAll(".reveal").forEach(function (el) {
revealObs.observe(el);
});
var statsBlock = document.getElementById("heroStats");
if (statsBlock) {
var statsObs = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting && !countersDone) {
countersDone = true;
statsBlock.querySelectorAll(".stat-num").forEach(animateCount);
}
});
},
{ threshold: 0.4 }
);
statsObs.observe(statsBlock);
}
var ringObs = new IntersectionObserver(
function (entries, obs) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
animateRing(entry.target);
obs.unobserve(entry.target);
}
});
},
{ threshold: 0.5 }
);
document.querySelectorAll(".ring").forEach(function (el) {
ringObs.observe(el);
});
} else {
document.querySelectorAll(".reveal").forEach(function (el) { el.classList.add("in"); });
document.querySelectorAll(".stat-num").forEach(animateCount);
document.querySelectorAll(".ring").forEach(animateRing);
}
/* ---------- Stack filter ---------- */
var chips = document.querySelectorAll(".stack-filter .chip");
var techCards = document.querySelectorAll("#stackGrid .tech");
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
chips.forEach(function (c) {
c.classList.remove("is-active");
c.setAttribute("aria-selected", "false");
});
chip.classList.add("is-active");
chip.setAttribute("aria-selected", "true");
var filter = chip.getAttribute("data-filter");
techCards.forEach(function (card) {
var match = filter === "all" || card.getAttribute("data-cat") === filter;
card.classList.toggle("dim", !match);
});
});
});
/* ---------- Cohort selection ---------- */
var cohorts = document.querySelectorAll(".cohort");
var selectedLabel = document.getElementById("selectedCohort");
var chosenCohort = "Cohort 24 · Jul 15";
// pre-select the first cohort
if (cohorts[0]) cohorts[0].classList.add("is-selected");
cohorts.forEach(function (btn) {
btn.addEventListener("click", function () {
cohorts.forEach(function (c) { c.classList.remove("is-selected"); });
btn.classList.add("is-selected");
chosenCohort = btn.getAttribute("data-cohort");
var seats = btn.getAttribute("data-seats");
if (selectedLabel) selectedLabel.textContent = chosenCohort;
toast("Reserved a spot in " + chosenCohort + " — " + seats + " seats left");
});
});
/* ---------- Apply form ---------- */
var form = document.getElementById("applyForm");
var input = document.getElementById("applyEmail");
if (form && input) {
form.addEventListener("submit", function (e) {
e.preventDefault();
var val = input.value.trim();
var ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
if (!ok) {
input.classList.add("invalid");
input.focus();
toast("Please enter a valid email address");
return;
}
input.classList.remove("invalid");
input.value = "";
toast("Syllabus sent! Check your inbox for " + chosenCohort);
});
input.addEventListener("input", function () {
input.classList.remove("invalid");
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Forge Academy — Coding Bootcamp</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- NAV -->
<header class="nav" id="nav">
<div class="wrap nav-inner">
<a class="brand" href="#top" aria-label="Forge Academy home">
<span class="brand-mark" aria-hidden="true">>_</span>
<span class="brand-name">forge<span class="brand-accent">.academy</span></span>
</a>
<nav class="nav-links" aria-label="Primary">
<a href="#outcomes">Outcomes</a>
<a href="#curriculum">Curriculum</a>
<a href="#stack">Stack</a>
<a href="#mentors">Mentors</a>
<a href="#financing">Financing</a>
</nav>
<div class="nav-cta">
<a href="#cohorts" class="btn btn-ghost">Cohort dates</a>
<a href="#apply" class="btn btn-primary">Apply now</a>
</div>
<button class="nav-toggle" id="navToggle" aria-label="Toggle menu" aria-expanded="false" aria-controls="mobileMenu">
<span></span><span></span><span></span>
</button>
</div>
<div class="mobile-menu" id="mobileMenu" hidden>
<a href="#outcomes">Outcomes</a>
<a href="#curriculum">Curriculum</a>
<a href="#stack">Stack</a>
<a href="#mentors">Mentors</a>
<a href="#financing">Financing</a>
<a href="#cohorts" class="btn btn-ghost">Cohort dates</a>
<a href="#apply" class="btn btn-primary">Apply now</a>
</div>
</header>
<main id="top">
<!-- HERO -->
<section class="hero">
<div class="grid-bg" aria-hidden="true"></div>
<div class="wrap hero-inner">
<span class="eyebrow"><span class="pulse" aria-hidden="true"></span> Cohort 24 enrolling — 9 seats left</span>
<h1 class="hero-title">
Become a <span class="glitch" data-text="full-stack engineer">full-stack engineer</span><br />in 16 weeks. Get hired.
</h1>
<p class="hero-sub">
An intensive, project-driven coding bootcamp built for career switchers and self-taught devs.
Ship real products, pair with senior mentors, and graduate job-ready — or your tuition is on us.
</p>
<div class="hero-actions">
<a href="#apply" class="btn btn-primary btn-lg">Apply for Cohort 24</a>
<a href="#curriculum" class="btn btn-outline btn-lg">View curriculum →</a>
</div>
<div class="hero-stats" id="heroStats">
<div class="stat">
<div class="stat-num" data-count="94" data-suffix="%">0%</div>
<div class="stat-label">Job placement<br />within 6 months</div>
</div>
<div class="stat">
<div class="stat-num" data-count="92" data-prefix="$" data-suffix="k">$0k</div>
<div class="stat-label">Median starting<br />salary</div>
</div>
<div class="stat">
<div class="stat-num" data-count="1480" data-suffix="+">0+</div>
<div class="stat-label">Graduates<br />hired since 2019</div>
</div>
<div class="stat">
<div class="stat-num" data-count="38" data-suffix=" days">0</div>
<div class="stat-label">Average time<br />to first offer</div>
</div>
</div>
</div>
</section>
<!-- HIRING PARTNERS -->
<section class="partners" aria-label="Hiring partners">
<div class="wrap">
<p class="partners-label">Graduates now build at</p>
<div class="partner-row" id="partnerRow">
<span class="logo">Northwind</span>
<span class="logo">Pixelware</span>
<span class="logo">Datacrest</span>
<span class="logo">Lumen&Co</span>
<span class="logo">Bytefall</span>
<span class="logo">Corewave</span>
<span class="logo">Stratus</span>
<span class="logo">Helix Labs</span>
</div>
</div>
</section>
<!-- OUTCOMES -->
<section class="section" id="outcomes">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">// outcomes</span>
<h2>We measure success by where you land.</h2>
<p>Transparent, third-party-audited outcomes. No vanity metrics — just offers.</p>
</div>
<div class="outcome-grid">
<article class="o-card reveal">
<div class="ring" data-ring="94"><span>94%</span></div>
<h3>Hired in 6 months</h3>
<p>Of job-seeking grads accepted a full-time engineering role within six months of finishing.</p>
</article>
<article class="o-card reveal">
<div class="ring" data-ring="88"><span>88%</span></div>
<h3>Completion rate</h3>
<p>Of enrolled students complete the full 16-week program with a deployed capstone.</p>
</article>
<article class="o-card reveal">
<div class="ring" data-ring="76"><span>76%</span></div>
<h3>Career switchers</h3>
<p>Came from non-tech backgrounds — nursing, retail, design, the military, and more.</p>
</article>
</div>
</div>
</section>
<!-- CURRICULUM TIMELINE -->
<section class="section section-dark" id="curriculum">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">// curriculum</span>
<h2>16 weeks, four phases, one portfolio.</h2>
<p>Each phase ends with a shipped, deployed project. You graduate with proof, not promises.</p>
</div>
<ol class="timeline">
<li class="t-item reveal">
<div class="t-marker"><span>01</span></div>
<div class="t-body">
<div class="t-top">
<h3>Foundations</h3>
<span class="pill pill-week">Weeks 1–4</span>
</div>
<p>HTML, CSS, modern JavaScript, the DOM, Git, and the command line. Daily kata and code reviews.</p>
<div class="t-tags"><span>JavaScript</span><span>Git</span><span>CSS Grid</span><span>Algorithms</span></div>
<div class="t-project"><strong>Ship:</strong> A responsive, accessible static portfolio site.</div>
</div>
</li>
<li class="t-item reveal">
<div class="t-marker"><span>02</span></div>
<div class="t-body">
<div class="t-top">
<h3>Frontend Engineering</h3>
<span class="pill pill-week">Weeks 5–8</span>
</div>
<p>React, component architecture, state management, testing, and real API integration.</p>
<div class="t-tags"><span>React</span><span>TypeScript</span><span>Vitest</span><span>REST</span></div>
<div class="t-project"><strong>Ship:</strong> A live data dashboard with auth and tests.</div>
</div>
</li>
<li class="t-item reveal">
<div class="t-marker"><span>03</span></div>
<div class="t-body">
<div class="t-top">
<h3>Backend & Databases</h3>
<span class="pill pill-week">Weeks 9–12</span>
</div>
<p>Node, Express, SQL & Postgres, REST and auth, deployment pipelines, and observability.</p>
<div class="t-tags"><span>Node.js</span><span>PostgreSQL</span><span>Docker</span><span>CI/CD</span></div>
<div class="t-project"><strong>Ship:</strong> A full REST API powering a real product.</div>
</div>
</li>
<li class="t-item reveal">
<div class="t-marker t-marker-final"><span>04</span></div>
<div class="t-body">
<div class="t-top">
<h3>Capstone & Career</h3>
<span class="pill pill-week">Weeks 13–16</span>
</div>
<p>Build and deploy a production app with a team. Mock interviews, system design, and offer negotiation.</p>
<div class="t-tags"><span>Team build</span><span>System design</span><span>Interview prep</span></div>
<div class="t-project"><strong>Ship:</strong> A team capstone deployed to production for Demo Day.</div>
</div>
</li>
</ol>
</div>
</section>
<!-- TECH STACK -->
<section class="section" id="stack">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">// the stack</span>
<h2>You'll go deep on the tools real teams ship with.</h2>
<p>No toy frameworks. Filter the stack to see what each track covers.</p>
</div>
<div class="stack-filter" role="tablist" aria-label="Stack filter">
<button class="chip is-active" role="tab" aria-selected="true" data-filter="all">All</button>
<button class="chip" role="tab" aria-selected="false" data-filter="frontend">Frontend</button>
<button class="chip" role="tab" aria-selected="false" data-filter="backend">Backend</button>
<button class="chip" role="tab" aria-selected="false" data-filter="devops">DevOps</button>
</div>
<div class="stack-grid" id="stackGrid">
<div class="tech" data-cat="frontend"><span class="tech-glyph">JS</span><span>JavaScript</span></div>
<div class="tech" data-cat="frontend"><span class="tech-glyph">TS</span><span>TypeScript</span></div>
<div class="tech" data-cat="frontend"><span class="tech-glyph">⚛</span><span>React</span></div>
<div class="tech" data-cat="frontend"><span class="tech-glyph">#</span><span>Tailwind</span></div>
<div class="tech" data-cat="backend"><span class="tech-glyph">⬢</span><span>Node.js</span></div>
<div class="tech" data-cat="backend"><span class="tech-glyph">ex</span><span>Express</span></div>
<div class="tech" data-cat="backend"><span class="tech-glyph">▦</span><span>PostgreSQL</span></div>
<div class="tech" data-cat="backend"><span class="tech-glyph">{}</span><span>GraphQL</span></div>
<div class="tech" data-cat="devops"><span class="tech-glyph">🐳</span><span>Docker</span></div>
<div class="tech" data-cat="devops"><span class="tech-glyph">git</span><span>Git & GitHub</span></div>
<div class="tech" data-cat="devops"><span class="tech-glyph">▲</span><span>Vercel</span></div>
<div class="tech" data-cat="devops"><span class="tech-glyph">∞</span><span>CI/CD</span></div>
</div>
</div>
</section>
<!-- MENTORS -->
<section class="section section-dark" id="mentors">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">// mentors</span>
<h2>Learn from engineers who've shipped at scale.</h2>
<p>Every student gets 1:1 mentorship and a 6:1 student-to-instructor ratio.</p>
</div>
<div class="mentor-grid">
<article class="mentor reveal">
<div class="m-avatar" data-initials="MR" style="--m:#2bff88"></div>
<h3>Maya Reyes</h3>
<p class="m-role">Lead Instructor · ex-Staff Eng, Datacrest</p>
<p class="m-bio">Spent 9 years building payment infra. Obsessed with clean abstractions and patient debugging.</p>
<div class="m-tags"><span>React</span><span>System design</span></div>
</article>
<article class="mentor reveal">
<div class="m-avatar" data-initials="JO" style="--m:#5b5bd6"></div>
<h3>Jonah Okafor</h3>
<p class="m-role">Backend Mentor · Senior Eng, Corewave</p>
<p class="m-bio">Scales Postgres for a living. Teaches the "why" behind every query plan and index.</p>
<div class="m-tags"><span>Node.js</span><span>Databases</span></div>
</article>
<article class="mentor reveal">
<div class="m-avatar" data-initials="SV" style="--m:#f59e0b"></div>
<h3>Sara Volkov</h3>
<p class="m-role">Career Coach · ex-Recruiter, Northwind</p>
<p class="m-bio">Reviewed 12,000+ resumes. Turns blank LinkedIn pages into interview magnets.</p>
<div class="m-tags"><span>Interview prep</span><span>Negotiation</span></div>
</article>
</div>
</div>
</section>
<!-- FINANCING -->
<section class="section" id="financing">
<div class="wrap">
<div class="section-head reveal">
<span class="kicker">// financing</span>
<h2>Pay in a way that works for you.</h2>
<p>Flexible options so cost is never the blocker between you and a new career.</p>
</div>
<div class="finance-grid">
<article class="fin reveal">
<h3>Upfront</h3>
<div class="fin-price">$11,900<span>once</span></div>
<p class="fin-save">Save $1,600 vs. monthly</p>
<ul>
<li>Full program access</li>
<li>Lifetime alumni network</li>
<li>Priority capstone slots</li>
</ul>
<a href="#apply" class="btn btn-outline btn-block">Choose upfront</a>
</article>
<article class="fin fin-featured reveal">
<span class="fin-badge">Most popular</span>
<h3>Deferred (ISA)</h3>
<div class="fin-price">$0<span>until hired</span></div>
<p class="fin-save">Pay 9% of salary for 24 months once you earn $60k+</p>
<ul>
<li>$0 due during the program</li>
<li>Capped total repayment</li>
<li>Owe nothing if never hired</li>
</ul>
<a href="#apply" class="btn btn-primary btn-block">Choose deferred</a>
</article>
<article class="fin reveal">
<h3>Monthly</h3>
<div class="fin-price">$1,125<span>/ mo · 12</span></div>
<p class="fin-save">0% interest financing</p>
<ul>
<li>Low monthly payments</li>
<li>No credit check required</li>
<li>Pause options available</li>
</ul>
<a href="#apply" class="btn btn-outline btn-block">Choose monthly</a>
</article>
</div>
</div>
</section>
<!-- COHORTS CTA -->
<section class="cohorts" id="cohorts">
<div class="wrap cohorts-inner">
<div class="cohorts-copy reveal">
<span class="kicker">// upcoming cohorts</span>
<h2>Pick a start date. Reserve your seat.</h2>
<p>Cohorts are capped at 24 students. A seat is held with a fully refundable $250 deposit.</p>
</div>
<div class="cohort-list reveal">
<button class="cohort" data-cohort="Cohort 24 · Jul 15" data-seats="9">
<div class="c-date"><span class="c-day">15</span><span class="c-mon">JUL</span></div>
<div class="c-info">
<strong>Cohort 24</strong>
<span>Full-time · 16 weeks · Remote</span>
</div>
<span class="c-seats c-seats-low">9 seats left</span>
</button>
<button class="cohort" data-cohort="Cohort 25 · Sep 09" data-seats="18">
<div class="c-date"><span class="c-day">09</span><span class="c-mon">SEP</span></div>
<div class="c-info">
<strong>Cohort 25</strong>
<span>Full-time · 16 weeks · Remote</span>
</div>
<span class="c-seats">18 seats left</span>
</button>
<button class="cohort" data-cohort="Cohort 26 · Nov 04" data-seats="24">
<div class="c-date"><span class="c-day">04</span><span class="c-mon">NOV</span></div>
<div class="c-info">
<strong>Cohort 26</strong>
<span>Part-time · 28 weeks · Remote</span>
</div>
<span class="c-seats">24 seats left</span>
</button>
</div>
</div>
</section>
<!-- APPLY -->
<section class="apply" id="apply">
<div class="wrap apply-inner reveal">
<h2>Ready to forge your career?</h2>
<p>Drop your email — we'll send the syllabus, sample lessons, and an invite to a live info session.</p>
<form class="apply-form" id="applyForm" novalidate>
<label class="sr-only" for="applyEmail">Email address</label>
<input type="email" id="applyEmail" name="email" placeholder="[email protected]" required autocomplete="email" />
<button type="submit" class="btn btn-primary btn-lg">Get the syllabus</button>
</form>
<p class="apply-note">No spam. Unsubscribe anytime. <span id="selectedCohort">Cohort 24 · Jul 15</span> selected.</p>
</div>
</section>
</main>
<!-- FOOTER -->
<footer class="footer">
<div class="wrap footer-inner">
<div class="footer-brand">
<a class="brand" href="#top">
<span class="brand-mark" aria-hidden="true">>_</span>
<span class="brand-name">forge<span class="brand-accent">.academy</span></span>
</a>
<p>An intensive software engineering bootcamp. Built by engineers, for future engineers.</p>
</div>
<nav class="footer-col" aria-label="Program">
<h4>Program</h4>
<a href="#curriculum">Curriculum</a>
<a href="#stack">Tech stack</a>
<a href="#mentors">Mentors</a>
<a href="#cohorts">Cohort dates</a>
</nav>
<nav class="footer-col" aria-label="Company">
<h4>Company</h4>
<a href="#outcomes">Outcomes report</a>
<a href="#financing">Financing</a>
<a href="#apply">Apply</a>
<a href="#top">Info sessions</a>
</nav>
<nav class="footer-col" aria-label="Connect">
<h4>Connect</h4>
<a href="#top">GitHub</a>
<a href="#top">Discord</a>
<a href="#top">LinkedIn</a>
<a href="#top">YouTube</a>
</nav>
</div>
<div class="wrap footer-bottom">
<span>© 2026 Forge Academy. A fictional bootcamp.</span>
<span class="footer-mono">// built with HTML, CSS & vanilla JS</span>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Coding Bootcamp Landing
A full marketing landing page for a fictional software engineering bootcamp, styled in an intense, career-focused dark theme — black canvas, neon-green accents, a JetBrains Mono headline paired with Inter body text. The page opens with a glitch-animated hero, a “seats left” pulse badge, and four outcome statistics that count up the moment they scroll into view. Below it sit a hiring-partner logo row, audited outcome cards with animated conic-gradient progress rings, and a four-phase curriculum timeline where every phase ends in a shipped project.
The interactions are all vanilla JavaScript. The tech-stack section is filterable by track (Frontend, Backend, DevOps) with the non-matching cards dimming out. The cohort picker lets you select a start date — the choice highlights, fires a toast, and updates the email capture form’s “selected cohort” note. The apply form validates the email inline and confirms with a toast. A sticky nav gains a shadow on scroll and collapses into an animated hamburger menu on mobile, while an IntersectionObserver reveals each section as you scroll.
Everything is self-contained, responsive from desktop down to roughly 360px, keyboard-usable, and respects prefers-reduced-motion. The data — mentors, partners, salaries, cohort dates — is realistic but clearly fictional.
Illustrative UI only — fictional courses, not a real learning platform.