Gym — Martial Arts / Boxing Landing
A disciplined martial arts and boxing gym landing page on a charcoal-and-crimson theme with slab-serif headings. Features a strong hero with a free trial CTA and a live intro-class card, a filterable disciplines grid for Boxing, Muay Thai, BJJ and Kickboxing, a ranked coaches row with credentials, a belt-style progression path, a weekly schedule teaser, member stories, and a CTA band with an inline trial-booking form. Vanilla JS drives the mobile nav, scroll reveals, animated stat counters and filter.
MCP
Código
:root {
--bg: #16161a;
--surface: #1f1f24;
--surface-2: #26262d;
--elevated: #2d2d35;
--ink: #f3efe7;
--ink-2: #c4bdb0;
--muted: #8a8479;
--crimson: #b3122b;
--crimson-d: #8e0e22;
--crimson-soft: rgba(179, 18, 43, 0.14);
--cream: #efe7d6;
--line: rgba(255, 255, 255, 0.1);
--line-2: rgba(255, 255, 255, 0.18);
--ok: #34d399;
--warn: #fbbf24;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--shadow: 0 1px 0 rgba(255, 255, 255, 0.04), 0 14px 40px -18px rgba(0, 0, 0, 0.8);
--shadow-lg: 0 30px 70px -30px rgba(0, 0, 0, 0.9);
--serif: "Roboto Slab", Georgia, serif;
--sans: "Inter", system-ui, -apple-system, sans-serif;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
scroll-padding-top: 84px;
}
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: var(--sans);
font-size: 16px;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
}
h1, h2, h3 {
font-family: var(--serif);
font-weight: 800;
letter-spacing: -0.01em;
margin: 0;
line-height: 1.08;
}
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
.container {
width: min(1140px, 100% - 40px);
margin-inline: auto;
}
.skip-link {
position: absolute;
left: -999px;
top: 0;
background: var(--crimson);
color: #fff;
padding: 10px 16px;
border-radius: var(--r-sm);
z-index: 200;
}
.skip-link:focus { left: 12px; top: 12px; }
:focus-visible {
outline: 2px solid var(--crimson);
outline-offset: 3px;
border-radius: 4px;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--crimson);
}
.eyebrow--light { color: var(--cream); opacity: 0.85; }
.eyebrow__dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--crimson);
box-shadow: 0 0 0 4px var(--crimson-soft);
}
/* ===== BUTTONS ===== */
.btn {
--pad-y: 11px;
--pad-x: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: var(--pad-y) var(--pad-x);
font-family: var(--sans);
font-weight: 700;
font-size: 0.9rem;
letter-spacing: 0.02em;
border: 1px solid transparent;
border-radius: var(--r-sm);
cursor: pointer;
transition: transform 0.12s ease, background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
white-space: nowrap;
}
.btn:active { transform: translateY(1px); }
.btn--lg { --pad-y: 15px; --pad-x: 26px; font-size: 0.98rem; }
.btn--block { width: 100%; }
.btn--primary {
background: var(--crimson);
color: #fff;
box-shadow: 0 10px 24px -12px var(--crimson);
}
.btn--primary:hover { background: var(--crimson-d); box-shadow: 0 14px 30px -12px var(--crimson); }
.btn--ghost {
background: transparent;
color: var(--ink-2);
}
.btn--ghost:hover { color: var(--ink); background: var(--surface-2); }
.btn--outline {
background: transparent;
color: var(--ink);
border-color: var(--line-2);
}
.btn--outline:hover { border-color: var(--cream); background: rgba(239, 231, 214, 0.06); }
.tag {
display: inline-flex;
align-items: center;
font-size: 0.68rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--ink-2);
background: var(--surface-2);
border: 1px solid var(--line);
padding: 4px 10px;
border-radius: 999px;
}
.tag--live {
color: #fff;
background: var(--crimson);
border-color: transparent;
}
.tag--live::before {
content: "";
width: 7px; height: 7px;
border-radius: 50%;
background: #fff;
margin-right: 7px;
animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }
/* ===== NAV ===== */
.nav {
position: sticky;
top: 0;
z-index: 100;
background: rgba(22, 22, 26, 0.72);
backdrop-filter: blur(14px);
border-bottom: 1px solid transparent;
transition: border-color 0.2s ease, background 0.2s ease;
}
.nav.is-scrolled {
border-bottom-color: var(--line);
background: rgba(22, 22, 26, 0.92);
}
.nav__inner {
display: flex;
align-items: center;
gap: 18px;
height: 72px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 10px;
font-family: var(--serif);
font-weight: 800;
font-size: 1.18rem;
letter-spacing: 0.01em;
}
.brand__mark {
display: grid;
place-items: center;
width: 36px;
height: 36px;
border-radius: 9px;
background: var(--crimson);
color: var(--cream);
font-size: 1.1rem;
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.15);
}
.brand__name span { color: var(--crimson); }
.nav__links {
display: flex;
gap: 26px;
margin-left: auto;
font-size: 0.92rem;
font-weight: 600;
color: var(--ink-2);
}
.nav__links a { position: relative; transition: color 0.18s ease; }
.nav__links a::after {
content: "";
position: absolute;
left: 0; bottom: -6px;
width: 0; height: 2px;
background: var(--crimson);
transition: width 0.22s ease;
}
.nav__links a:hover { color: var(--ink); }
.nav__links a:hover::after { width: 100%; }
.nav__cta {
display: flex;
align-items: center;
gap: 10px;
}
.nav__toggle {
display: none;
flex-direction: column;
justify-content: center;
gap: 5px;
width: 44px;
height: 44px;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-sm);
cursor: pointer;
margin-left: auto;
}
.nav__toggle span {
display: block;
width: 20px;
height: 2px;
margin-inline: auto;
background: var(--ink);
transition: transform 0.2s ease, opacity 0.2s ease;
}
.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); }
.nav__mobile {
display: flex;
flex-direction: column;
gap: 4px;
padding: 12px 20px 20px;
border-top: 1px solid var(--line);
background: var(--surface);
}
.nav__mobile[hidden] {
display: none;
}
.nav__mobile a {
padding: 12px 10px;
font-weight: 600;
color: var(--ink-2);
border-radius: var(--r-sm);
}
.nav__mobile a:hover { background: var(--surface-2); color: var(--ink); }
.nav__mobile .btn { margin-top: 8px; }
/* ===== HERO ===== */
.hero {
position: relative;
padding: clamp(48px, 8vw, 96px) 0 clamp(56px, 8vw, 104px);
background:
radial-gradient(120% 90% at 85% -10%, var(--crimson-soft), transparent 55%),
radial-gradient(90% 70% at -10% 110%, rgba(239,231,214,0.05), transparent 60%),
var(--bg);
overflow: hidden;
}
.hero__grain {
position: absolute;
inset: 0;
background-image: repeating-linear-gradient(
115deg,
rgba(255,255,255,0.02) 0 2px,
transparent 2px 8px
);
opacity: 0.6;
pointer-events: none;
}
.hero__inner {
position: relative;
display: grid;
grid-template-columns: 1.25fr 0.85fr;
gap: clamp(28px, 4vw, 56px);
align-items: center;
}
.hero__title {
font-size: clamp(2.5rem, 6vw, 4.4rem);
font-weight: 900;
margin: 16px 0 18px;
}
.hero__title em {
font-style: normal;
color: var(--crimson);
-webkit-text-stroke: 1px var(--crimson);
}
.hero__lead {
color: var(--ink-2);
font-size: 1.06rem;
max-width: 52ch;
}
.hero__actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin: 26px 0 34px;
}
.hero__stats {
display: flex;
flex-wrap: wrap;
gap: clamp(20px, 4vw, 46px);
padding-top: 26px;
border-top: 1px solid var(--line);
}
.hero__stats strong {
display: block;
font-family: var(--serif);
font-size: 2.1rem;
font-weight: 800;
color: var(--ink);
}
.hero__stats span {
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--muted);
}
.hero__card {
background: linear-gradient(180deg, var(--surface) 0%, var(--surface-2) 100%);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 24px;
box-shadow: var(--shadow-lg);
position: relative;
}
.hero__card::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(160deg, rgba(179,18,43,0.6), transparent 40%);
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
.hero__card-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.hero__card-time {
font-family: var(--serif);
font-weight: 700;
font-size: 1.1rem;
color: var(--cream);
}
.hero__card-title { font-size: 1.5rem; margin-bottom: 4px; }
.hero__card-sub { color: var(--muted); font-size: 0.9rem; }
.hero__card-meta {
display: grid;
gap: 10px;
margin: 18px 0;
padding: 16px 0;
border-block: 1px solid var(--line);
}
.hero__card-meta > div {
display: flex;
justify-content: space-between;
align-items: baseline;
}
.hero__card-meta .k { color: var(--muted); font-size: 0.85rem; }
.hero__card-meta .v { font-weight: 600; font-size: 0.92rem; }
.hero__spots { color: var(--warn); }
.hero__card-fine {
margin-top: 12px;
font-size: 0.78rem;
color: var(--muted);
text-align: center;
}
/* ===== SECTIONS ===== */
.section {
padding: clamp(56px, 8vw, 100px) 0;
border-top: 1px solid var(--line);
}
.section__head {
max-width: 640px;
margin-bottom: 40px;
}
.section__title {
font-size: clamp(1.9rem, 4vw, 2.8rem);
margin: 14px 0 14px;
}
.section__lead {
color: var(--ink-2);
font-size: 1.02rem;
}
/* ===== FILTERS / CHIPS ===== */
.filters {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 28px;
}
.chip {
font-family: var(--sans);
font-size: 0.84rem;
font-weight: 600;
letter-spacing: 0.03em;
color: var(--ink-2);
background: var(--surface);
border: 1px solid var(--line);
border-radius: 999px;
padding: 9px 18px;
cursor: pointer;
transition: all 0.16s ease;
}
.chip:hover { color: var(--ink); border-color: var(--line-2); }
.chip.is-active {
color: #fff;
background: var(--crimson);
border-color: var(--crimson);
}
/* ===== DISCIPLINE CARDS ===== */
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 18px;
}
.d-card {
position: relative;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 24px 22px 22px;
display: flex;
flex-direction: column;
gap: 10px;
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
overflow: hidden;
}
.d-card::after {
content: "";
position: absolute;
left: 0; top: 0;
width: 100%; height: 3px;
background: var(--crimson);
transform: scaleX(0);
transform-origin: left;
transition: transform 0.25s ease;
}
.d-card:hover {
transform: translateY(-4px);
border-color: var(--line-2);
box-shadow: var(--shadow);
}
.d-card:hover::after { transform: scaleX(1); }
.d-card.is-hidden { display: none; }
.d-card__badge {
position: absolute;
top: 18px;
right: 18px;
font-family: var(--serif);
font-size: 2.4rem;
font-weight: 800;
color: rgba(239, 231, 214, 0.08);
line-height: 1;
}
.d-card .tag { align-self: flex-start; }
.d-card h3 { font-size: 1.45rem; }
.d-card p { color: var(--ink-2); font-size: 0.94rem; }
.d-card__list {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 4px;
padding-top: 14px;
border-top: 1px solid var(--line);
}
.d-card__list li {
position: relative;
padding-left: 20px;
font-size: 0.86rem;
color: var(--ink-2);
}
.d-card__list li::before {
content: "›";
position: absolute;
left: 2px;
color: var(--crimson);
font-weight: 700;
}
.d-card__cta {
margin-top: 12px;
align-self: flex-start;
background: transparent;
border: none;
color: var(--cream);
font-family: var(--sans);
font-weight: 700;
font-size: 0.88rem;
letter-spacing: 0.03em;
cursor: pointer;
padding: 6px 0;
}
.d-card__cta::after { content: " →"; transition: margin 0.18s ease; }
.d-card__cta:hover { color: var(--crimson); }
.d-card__cta:hover::after { margin-left: 4px; }
/* ===== COACHES ===== */
.coach-row {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 18px;
}
.coach {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 24px 22px;
text-align: center;
transition: transform 0.2s ease, border-color 0.2s ease;
}
.coach:hover { transform: translateY(-4px); border-color: var(--line-2); }
.coach__avatar {
width: 78px;
height: 78px;
margin: 0 auto 16px;
border-radius: 50%;
display: grid;
place-items: center;
background:
radial-gradient(circle at 30% 30%, var(--surface-2), var(--bg));
border: 1px solid var(--line-2);
position: relative;
}
.coach__avatar::after {
content: attr(data-initials);
font-family: var(--serif);
font-weight: 800;
font-size: 1.5rem;
color: var(--cream);
}
.coach__avatar::before {
content: "";
position: absolute;
inset: -4px;
border-radius: 50%;
border: 1px dashed rgba(179, 18, 43, 0.5);
}
.coach__name { font-size: 1.1rem; }
.coach__role {
color: var(--crimson);
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
margin: 4px 0 14px;
}
.coach__creds {
display: flex;
flex-direction: column;
gap: 6px;
padding-top: 14px;
border-top: 1px solid var(--line);
}
.coach__creds li { font-size: 0.84rem; color: var(--ink-2); }
/* ===== PATH ===== */
.path-list {
display: grid;
gap: 0;
}
.path-step {
display: grid;
grid-template-columns: 56px 8px 1fr;
gap: 20px;
align-items: start;
padding: 22px 0;
border-top: 1px solid var(--line);
}
.path-step:last-child { border-bottom: 1px solid var(--line); }
.path-step__rank {
font-family: var(--serif);
font-weight: 800;
font-size: 1.4rem;
color: var(--muted);
}
.path-step__belt {
width: 8px;
align-self: stretch;
border-radius: 4px;
background: var(--belt, var(--cream));
box-shadow: 0 0 0 1px rgba(0,0,0,0.4) inset;
min-height: 44px;
}
.path-step__body h3 { font-size: 1.3rem; margin-bottom: 6px; }
.path-step__body p { color: var(--ink-2); font-size: 0.96rem; max-width: 62ch; }
/* ===== SCHEDULE ===== */
.sched {
border: 1px solid var(--line);
border-radius: var(--r-md);
overflow: hidden;
background: var(--surface);
}
.sched__row {
display: grid;
grid-template-columns: 88px 1fr 160px 130px;
gap: 16px;
align-items: center;
padding: 16px 22px;
border-top: 1px solid var(--line);
transition: background 0.16s ease;
}
.sched__row:first-child { border-top: none; }
.sched__row:not(.sched__row--head):hover { background: var(--surface-2); }
.sched__row--head {
background: var(--bg);
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
}
.sched__time {
font-family: var(--serif);
font-weight: 700;
color: var(--cream);
}
.sched__class { font-weight: 600; }
.sched__coach { color: var(--ink-2); font-size: 0.92rem; }
.lvl {
font-style: normal;
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
padding: 4px 10px;
border-radius: 999px;
border: 1px solid var(--line);
}
.lvl--all { color: var(--ink-2); }
.lvl--begin { color: var(--ok); border-color: rgba(52, 211, 153, 0.4); }
.lvl--inter { color: var(--warn); border-color: rgba(251, 191, 36, 0.4); }
/* ===== STORIES ===== */
.quotes {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 18px;
}
.quote {
margin: 0;
background: var(--surface);
border: 1px solid var(--line);
border-left: 3px solid var(--crimson);
border-radius: var(--r-md);
padding: 26px 24px;
}
.quote blockquote {
margin: 0 0 18px;
font-size: 1.02rem;
color: var(--ink);
line-height: 1.55;
}
.quote figcaption {
display: flex;
flex-direction: column;
gap: 2px;
}
.quote__name { font-weight: 700; font-family: var(--serif); }
.quote__meta { font-size: 0.8rem; color: var(--muted); }
/* ===== CTA BAND ===== */
.cta-band {
padding: clamp(48px, 7vw, 88px) 0;
background:
radial-gradient(100% 140% at 20% 0%, var(--crimson-d), transparent 60%),
linear-gradient(180deg, var(--crimson), var(--crimson-d));
border-top: 1px solid var(--line);
}
.cta-band__inner {
display: grid;
grid-template-columns: 1fr 0.95fr;
gap: clamp(28px, 5vw, 64px);
align-items: center;
}
.cta-band__copy h2 {
color: #fff;
font-size: clamp(2rem, 4vw, 3rem);
margin: 12px 0 12px;
}
.cta-band__copy p {
color: rgba(255, 255, 255, 0.85);
font-size: 1.04rem;
max-width: 42ch;
}
.trial-form {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
padding: 26px;
display: grid;
gap: 14px;
box-shadow: var(--shadow-lg);
}
.field { display: grid; gap: 6px; }
.field label {
font-size: 0.74rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--muted);
}
.field input,
.field select {
font-family: var(--sans);
font-size: 0.96rem;
color: var(--ink);
background: var(--bg);
border: 1px solid var(--line-2);
border-radius: var(--r-sm);
padding: 12px 14px;
transition: border-color 0.16s ease, box-shadow 0.16s ease;
}
.field input::placeholder { color: var(--muted); }
.field input:focus,
.field select:focus {
outline: none;
border-color: var(--crimson);
box-shadow: 0 0 0 3px var(--crimson-soft);
}
.field input.is-invalid { border-color: var(--crimson); }
.field select { appearance: none; cursor: pointer; }
/* ===== FOOTER ===== */
.footer {
background: var(--bg);
border-top: 1px solid var(--line);
padding: 44px 0 36px;
}
.footer__inner {
display: grid;
grid-template-columns: 1.4fr 1fr;
gap: 24px;
align-items: start;
}
.footer__brand {
display: flex;
gap: 14px;
align-items: flex-start;
}
.footer__brand p { color: var(--ink-2); font-size: 0.9rem; }
.footer__links {
display: flex;
flex-wrap: wrap;
gap: 8px 22px;
justify-content: flex-end;
}
.footer__links a {
color: var(--ink-2);
font-weight: 600;
font-size: 0.9rem;
transition: color 0.16s ease;
}
.footer__links a:hover { color: var(--crimson); }
.footer__fine {
grid-column: 1 / -1;
margin-top: 22px;
padding-top: 22px;
border-top: 1px solid var(--line);
color: var(--muted);
font-size: 0.82rem;
}
/* ===== TOAST ===== */
.toast {
position: fixed;
left: 50%;
bottom: 28px;
transform: translate(-50%, 140%);
background: var(--elevated);
color: var(--ink);
border: 1px solid var(--line-2);
border-left: 3px solid var(--crimson);
border-radius: var(--r-md);
padding: 14px 20px;
font-weight: 600;
font-size: 0.92rem;
box-shadow: var(--shadow-lg);
z-index: 300;
opacity: 0;
transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
max-width: calc(100% - 32px);
}
.toast.is-visible { transform: translate(-50%, 0); opacity: 1; }
/* ===== REVEAL ===== */
.reveal {
opacity: 0;
transform: translateY(22px);
transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal.is-in { opacity: 1; transform: none; }
/* ===== RESPONSIVE ===== */
@media (max-width: 900px) {
.hero__inner { grid-template-columns: 1fr; }
.hero__card { max-width: 460px; }
.cta-band__inner { grid-template-columns: 1fr; }
.footer__inner { grid-template-columns: 1fr; }
.footer__links { justify-content: flex-start; }
}
@media (max-width: 760px) {
.nav__links, .nav__cta { display: none; }
.nav__toggle { display: flex; }
.sched__row {
grid-template-columns: 70px 1fr;
grid-template-areas:
"time class"
"time meta";
row-gap: 6px;
}
.sched__row--head { display: none; }
.sched__time { grid-area: time; align-self: start; }
.sched__class { grid-area: class; }
.sched__coach { grid-area: meta; }
.sched__row span:last-child { grid-area: meta; justify-self: end; }
}
@media (max-width: 520px) {
.container { width: min(1140px, 100% - 28px); }
.hero__stats { gap: 18px 28px; }
.hero__stats strong { font-size: 1.7rem; }
.hero__actions .btn { flex: 1 1 100%; }
.section { padding: 52px 0; }
.d-card__badge { font-size: 2rem; }
.path-step {
grid-template-columns: 40px 6px 1fr;
gap: 14px;
}
.coach-row { grid-template-columns: 1fr 1fr; }
.coach { padding: 20px 14px; }
.trial-form { padding: 20px; }
.toast { bottom: 16px; }
}
@media (max-width: 380px) {
.coach-row { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
* { scroll-behavior: auto !important; }
.reveal { opacity: 1; transform: none; transition: none; }
.tag--live::before { animation: 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("is-visible");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("is-visible");
}, 3200);
}
/* ---------- Sticky nav shadow ---------- */
var nav = document.getElementById("nav");
function onScroll() {
if (!nav) return;
nav.classList.toggle("is-scrolled", window.scrollY > 8);
}
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- Mobile menu ---------- */
var toggle = document.getElementById("navToggle");
var menu = document.getElementById("mobileMenu");
function closeMenu() {
if (!toggle || !menu) return;
toggle.setAttribute("aria-expanded", "false");
toggle.setAttribute("aria-label", "Open menu");
menu.hidden = true;
}
if (toggle && menu) {
toggle.addEventListener("click", function () {
var open = toggle.getAttribute("aria-expanded") === "true";
if (open) {
closeMenu();
} else {
toggle.setAttribute("aria-expanded", "true");
toggle.setAttribute("aria-label", "Close menu");
menu.hidden = false;
}
});
menu.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", closeMenu);
});
window.addEventListener("keydown", function (e) {
if (e.key === "Escape") closeMenu();
});
}
/* ---------- Smooth-scroll to trial form ---------- */
document.querySelectorAll("[data-trial]").forEach(function (el) {
el.addEventListener("click", function (e) {
var target = document.getElementById("trial");
if (!target) return;
e.preventDefault();
target.scrollIntoView({ behavior: "smooth", block: "start" });
var name = document.getElementById("tName");
if (name) setTimeout(function () { name.focus({ preventScroll: true }); }, 500);
});
});
/* ---------- Discipline filter (tabs) ---------- */
var chips = Array.prototype.slice.call(document.querySelectorAll(".chip[data-filter]"));
var dCards = Array.prototype.slice.call(document.querySelectorAll(".d-card[data-tags]"));
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
var filter = chip.getAttribute("data-filter");
chips.forEach(function (c) {
var active = c === chip;
c.classList.toggle("is-active", active);
c.setAttribute("aria-selected", active ? "true" : "false");
});
var shown = 0;
dCards.forEach(function (card) {
var tags = card.getAttribute("data-tags") || "";
var match = filter === "all" || tags.indexOf(filter) !== -1;
card.classList.toggle("is-hidden", !match);
if (match) shown++;
});
toast(
filter === "all"
? "Showing all disciplines"
: shown + " " + filter + " discipline" + (shown === 1 ? "" : "s")
);
});
});
/* ---------- Discipline "view program" CTAs ---------- */
document.querySelectorAll(".d-card__cta[data-discipline]").forEach(function (btn) {
btn.addEventListener("click", function () {
var name = btn.getAttribute("data-discipline");
toast(name + " program details sent to your inbox — check soon.");
});
});
/* ---------- Reveal on scroll ---------- */
var revealEls = Array.prototype.slice.call(document.querySelectorAll(".reveal"));
if ("IntersectionObserver" in window) {
var io = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add("is-in");
io.unobserve(entry.target);
}
});
},
{ threshold: 0.12, rootMargin: "0px 0px -40px 0px" }
);
revealEls.forEach(function (el) { io.observe(el); });
} else {
revealEls.forEach(function (el) { el.classList.add("is-in"); });
}
/* ---------- Animated stat counters ---------- */
var counters = Array.prototype.slice.call(document.querySelectorAll("[data-count]"));
function animateCount(el) {
var target = parseInt(el.getAttribute("data-count"), 10) || 0;
var start = performance.now();
var dur = 1100;
function tick(now) {
var p = Math.min((now - start) / dur, 1);
var eased = 1 - Math.pow(1 - p, 3);
el.textContent = Math.round(target * eased) + "+";
if (p < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
if ("IntersectionObserver" in window) {
var co = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
animateCount(entry.target);
co.unobserve(entry.target);
}
});
},
{ threshold: 0.6 }
);
counters.forEach(function (el) { co.observe(el); });
} else {
counters.forEach(function (el) {
el.textContent = el.getAttribute("data-count") + "+";
});
}
/* ---------- Trial form validation ---------- */
var form = document.getElementById("trialForm");
if (form) {
var nameInput = document.getElementById("tName");
var emailInput = document.getElementById("tEmail");
var emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
[nameInput, emailInput].forEach(function (inp) {
if (!inp) return;
inp.addEventListener("input", function () {
inp.classList.remove("is-invalid");
});
});
form.addEventListener("submit", function (e) {
e.preventDefault();
var ok = true;
if (!nameInput.value.trim()) {
nameInput.classList.add("is-invalid");
ok = false;
}
if (!emailRe.test(emailInput.value.trim())) {
emailInput.classList.add("is-invalid");
ok = false;
}
if (!ok) {
toast("Please add your name and a valid email.");
(nameInput.classList.contains("is-invalid") ? nameInput : emailInput).focus();
return;
}
var discipline = document.getElementById("tDiscipline").value;
toast("Trial booked! We'll email " + nameInput.value.trim() + " about " + discipline + ".");
form.reset();
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Iron Dojo — Martial Arts & Boxing</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;900&family=Roboto+Slab:wght@500;600;700;800;900&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="nav">
<div class="container nav__inner">
<a class="brand" href="#top" aria-label="Iron Dojo home">
<span class="brand__mark" aria-hidden="true">道</span>
<span class="brand__name">Iron<span>Dojo</span></span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#disciplines">Disciplines</a>
<a href="#coaches">Coaches</a>
<a href="#path">The Path</a>
<a href="#schedule">Schedule</a>
<a href="#stories">Stories</a>
</nav>
<div class="nav__cta">
<a class="btn btn--ghost" href="#schedule">Class times</a>
<a class="btn btn--primary" href="#trial" data-trial>Free trial class</a>
</div>
<button class="nav__toggle" id="navToggle" aria-expanded="false" aria-controls="mobileMenu" aria-label="Open menu">
<span></span><span></span><span></span>
</button>
</div>
<div class="nav__mobile" id="mobileMenu" hidden>
<a href="#disciplines">Disciplines</a>
<a href="#coaches">Coaches</a>
<a href="#path">The Path</a>
<a href="#schedule">Schedule</a>
<a href="#stories">Stories</a>
<a class="btn btn--primary btn--block" href="#trial" data-trial>Free trial class</a>
</div>
</header>
<main id="main">
<span id="top"></span>
<!-- ===== HERO ===== -->
<section class="hero">
<div class="hero__grain" aria-hidden="true"></div>
<div class="container hero__inner">
<div class="hero__copy reveal">
<span class="eyebrow"><span class="eyebrow__dot"></span> Est. 2009 · Downtown Iron Quarter</span>
<h1 class="hero__title">Forge discipline.<br /><em>Earn</em> your edge.</h1>
<p class="hero__lead">
A traditional fight gym built on respect, repetition and ruthless conditioning.
Boxing, Muay Thai, Brazilian Jiu-Jitsu and Kickboxing — coached by ranked
fighters, open to everyone from first-timers to competitors.
</p>
<div class="hero__actions">
<a class="btn btn--primary btn--lg" href="#trial" data-trial>Start your free trial class</a>
<a class="btn btn--outline btn--lg" href="#disciplines">Explore disciplines</a>
</div>
<ul class="hero__stats" aria-label="Gym highlights">
<li><strong data-count="14">0</strong><span>Years training fighters</span></li>
<li><strong data-count="9">0</strong><span>Ranked coaches</span></li>
<li><strong data-count="40">0</strong><span>Classes / week</span></li>
</ul>
</div>
<aside class="hero__card reveal" aria-label="Next intro class">
<div class="hero__card-top">
<span class="tag tag--live">Open mat tonight</span>
<span class="hero__card-time">6:30 PM</span>
</div>
<h2 class="hero__card-title">Beginner Boxing Intro</h2>
<p class="hero__card-sub">Wraps & gloves provided · No experience needed</p>
<div class="hero__card-meta">
<div><span class="k">Coach</span><span class="v">Marcus "Anvil" Reyes</span></div>
<div><span class="k">Spots left</span><span class="v hero__spots">5 / 16</span></div>
<div><span class="k">Duration</span><span class="v">60 min</span></div>
</div>
<a class="btn btn--primary btn--block" href="#trial" data-trial>Claim a spot</a>
<p class="hero__card-fine">Free for first-time visitors. Bring water & a towel.</p>
</aside>
</div>
</section>
<!-- ===== DISCIPLINES ===== -->
<section class="section disciplines" id="disciplines">
<div class="container">
<header class="section__head reveal">
<span class="eyebrow">Train with intent</span>
<h2 class="section__title">Four disciplines, one standard</h2>
<p class="section__lead">Filter the arts by what you want from your training. Every program runs from fundamentals up to fight-team level.</p>
</header>
<div class="filters reveal" role="tablist" aria-label="Filter disciplines">
<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="striking">Striking</button>
<button class="chip" role="tab" aria-selected="false" data-filter="grappling">Grappling</button>
<button class="chip" role="tab" aria-selected="false" data-filter="conditioning">Conditioning</button>
</div>
<div class="cards" id="disciplineGrid">
<article class="d-card reveal" data-tags="striking conditioning">
<div class="d-card__badge">道</div>
<span class="tag">Striking</span>
<h3>Boxing</h3>
<p>The sweet science. Footwork, head movement and crisp combinations built on thousands of clean reps.</p>
<ul class="d-card__list">
<li>Bag & pad rounds</li>
<li>Controlled sparring</li>
<li>3 levels · 12 weekly classes</li>
</ul>
<button class="d-card__cta" data-discipline="Boxing">View program</button>
</article>
<article class="d-card reveal" data-tags="striking conditioning">
<div class="d-card__badge">拳</div>
<span class="tag">Striking</span>
<h3>Muay Thai</h3>
<p>The art of eight limbs. Punches, elbows, knees and kicks with traditional clinch work and ram muay respect.</p>
<ul class="d-card__list">
<li>Thai pad & clinch drills</li>
<li>Conditioning blocks</li>
<li>3 levels · 10 weekly classes</li>
</ul>
<button class="d-card__cta" data-discipline="Muay Thai">View program</button>
</article>
<article class="d-card reveal" data-tags="grappling">
<div class="d-card__badge">柔</div>
<span class="tag">Grappling</span>
<h3>Brazilian Jiu-Jitsu</h3>
<p>Leverage over strength. A belt-graded path through positions, submissions and live rolling under black belts.</p>
<ul class="d-card__list">
<li>Gi & no-gi sessions</li>
<li>IBJJF belt curriculum</li>
<li>5 belts · 14 weekly classes</li>
</ul>
<button class="d-card__cta" data-discipline="Brazilian Jiu-Jitsu">View program</button>
</article>
<article class="d-card reveal" data-tags="striking conditioning">
<div class="d-card__badge">蹴</div>
<span class="tag">Striking</span>
<h3>Kickboxing</h3>
<p>High-tempo striking for fitness or competition. Combinations, defense and relentless cardio rounds.</p>
<ul class="d-card__list">
<li>Circuit & round work</li>
<li>Optional ring time</li>
<li>2 levels · 8 weekly classes</li>
</ul>
<button class="d-card__cta" data-discipline="Kickboxing">View program</button>
</article>
</div>
</div>
</section>
<!-- ===== COACHES ===== -->
<section class="section coaches" id="coaches">
<div class="container">
<header class="section__head reveal">
<span class="eyebrow">Lineage matters</span>
<h2 class="section__title">Coached by ranked fighters</h2>
<p class="section__lead">Our floor is led by competitors and certified instructors who train the way they teach.</p>
</header>
<div class="coach-row">
<article class="coach reveal">
<div class="coach__avatar" data-initials="MR" aria-hidden="true"></div>
<h3 class="coach__name">Marcus "Anvil" Reyes</h3>
<p class="coach__role">Head Boxing Coach</p>
<ul class="coach__creds">
<li>Ex-national amateur, 38–4</li>
<li>USA Boxing certified</li>
<li>14 yrs coaching</li>
</ul>
</article>
<article class="coach reveal">
<div class="coach__avatar" data-initials="KA" aria-hidden="true"></div>
<h3 class="coach__name">Kru Apinya Sano</h3>
<p class="coach__role">Muay Thai Kru</p>
<ul class="coach__creds">
<li>Bangkok-trained, 60+ fights</li>
<li>WMC-certified Kru</li>
<li>Clinch specialist</li>
</ul>
</article>
<article class="coach reveal">
<div class="coach__avatar" data-initials="DS" aria-hidden="true"></div>
<h3 class="coach__name">Diego Salvador</h3>
<p class="coach__role">BJJ Black Belt</p>
<ul class="coach__creds">
<li>3rd-degree black belt</li>
<li>IBJJF medalist</li>
<li>Gi & no-gi program lead</li>
</ul>
</article>
<article class="coach reveal">
<div class="coach__avatar" data-initials="TN" aria-hidden="true"></div>
<h3 class="coach__name">Tasha Nguyen</h3>
<p class="coach__role">Kickboxing & S&C</p>
<ul class="coach__creds">
<li>Pro K-1 record 12–3</li>
<li>NSCA conditioning coach</li>
<li>Beginner-class lead</li>
</ul>
</article>
</div>
</div>
</section>
<!-- ===== THE PATH ===== -->
<section class="section path" id="path">
<div class="container">
<header class="section__head reveal">
<span class="eyebrow">The Path</span>
<h2 class="section__title">From white belt to fight team</h2>
<p class="section__lead">A clear progression so you always know what you're working toward — no guesswork, just earned rank.</p>
</header>
<ol class="path-list">
<li class="path-step reveal">
<span class="path-step__rank">01</span>
<div class="path-step__belt" style="--belt:#efe7d6"></div>
<div class="path-step__body">
<h3>Foundations</h3>
<p>Stance, breathing, basic strikes and gym etiquette. Build a habit and a body that can train.</p>
</div>
</li>
<li class="path-step reveal">
<span class="path-step__rank">02</span>
<div class="path-step__belt" style="--belt:#8aa1c0"></div>
<div class="path-step__body">
<h3>Fundamentals</h3>
<p>Combinations, defense and live drilling at controlled intensity. Earn your first stripe.</p>
</div>
</li>
<li class="path-step reveal">
<span class="path-step__rank">03</span>
<div class="path-step__belt" style="--belt:#7a4b22"></div>
<div class="path-step__body">
<h3>Sparring Ready</h3>
<p>Controlled sparring and rolling with intent. Read distance, manage pace, stay composed.</p>
</div>
</li>
<li class="path-step reveal">
<span class="path-step__rank">04</span>
<div class="path-step__belt" style="--belt:#b3122b"></div>
<div class="path-step__body">
<h3>Fight Team</h3>
<p>Invitation-only competition squad. Camps, corner work and a shot at the amateur circuit.</p>
</div>
</li>
</ol>
</div>
</section>
<!-- ===== SCHEDULE TEASER ===== -->
<section class="section schedule" id="schedule">
<div class="container">
<header class="section__head reveal">
<span class="eyebrow">This week</span>
<h2 class="section__title">Schedule teaser</h2>
<p class="section__lead">A taste of the daily floor. Members get the full timetable in the app.</p>
</header>
<div class="sched reveal">
<div class="sched__row sched__row--head" role="row">
<span>Time</span><span>Class</span><span>Coach</span><span>Level</span>
</div>
<div class="sched__row">
<span class="sched__time">06:00</span>
<span class="sched__class">Boxing — Roadwork & Bag</span>
<span class="sched__coach">Marcus Reyes</span>
<span><em class="lvl lvl--all">All levels</em></span>
</div>
<div class="sched__row">
<span class="sched__time">12:15</span>
<span class="sched__class">Lunch BJJ — No-Gi Drills</span>
<span class="sched__coach">Diego Salvador</span>
<span><em class="lvl lvl--inter">Intermediate</em></span>
</div>
<div class="sched__row">
<span class="sched__time">17:30</span>
<span class="sched__class">Muay Thai — Pads & Clinch</span>
<span class="sched__coach">Kru Apinya</span>
<span><em class="lvl lvl--all">All levels</em></span>
</div>
<div class="sched__row">
<span class="sched__time">18:30</span>
<span class="sched__class">Beginner Boxing Intro</span>
<span class="sched__coach">Tasha Nguyen</span>
<span><em class="lvl lvl--begin">Beginner</em></span>
</div>
<div class="sched__row">
<span class="sched__time">19:30</span>
<span class="sched__class">Kickboxing — Rounds</span>
<span class="sched__coach">Tasha Nguyen</span>
<span><em class="lvl lvl--all">All levels</em></span>
</div>
</div>
</div>
</section>
<!-- ===== STORIES ===== -->
<section class="section stories" id="stories">
<div class="container">
<header class="section__head reveal">
<span class="eyebrow">From the floor</span>
<h2 class="section__title">Stories of discipline</h2>
</header>
<div class="quotes">
<figure class="quote reveal">
<blockquote>"I walked in unable to skip rope and walked out with my first amateur win. The coaching here is patient but it never lets you coast."</blockquote>
<figcaption><span class="quote__name">Lena Vasquez</span><span class="quote__meta">Boxing · 2 yrs</span></figcaption>
</figure>
<figure class="quote reveal">
<blockquote>"The belt path made BJJ make sense. I always know the next thing to drill, and the rolls are tough but respectful."</blockquote>
<figcaption><span class="quote__name">Omar Haddad</span><span class="quote__meta">BJJ · Blue belt</span></figcaption>
</figure>
<figure class="quote reveal">
<blockquote>"Best conditioning of my life and the most welcoming room I've trained in. Kru Apinya treats every student like family."</blockquote>
<figcaption><span class="quote__name">Priya Menon</span><span class="quote__meta">Muay Thai · 1 yr</span></figcaption>
</figure>
</div>
</div>
</section>
<!-- ===== CTA BAND ===== -->
<section class="cta-band" id="trial">
<div class="container cta-band__inner reveal">
<div class="cta-band__copy">
<span class="eyebrow eyebrow--light">No contracts to start</span>
<h2>Your first class is on us.</h2>
<p>Book a free trial, meet a coach and feel the room. Bring nothing but the willingness to learn.</p>
</div>
<form class="trial-form" id="trialForm" novalidate>
<div class="field">
<label for="tName">Name</label>
<input id="tName" name="name" type="text" autocomplete="name" placeholder="Your name" required />
</div>
<div class="field">
<label for="tEmail">Email</label>
<input id="tEmail" name="email" type="email" autocomplete="email" placeholder="[email protected]" required />
</div>
<div class="field">
<label for="tDiscipline">Discipline</label>
<select id="tDiscipline" name="discipline">
<option>Boxing</option>
<option>Muay Thai</option>
<option>Brazilian Jiu-Jitsu</option>
<option>Kickboxing</option>
<option>Not sure yet</option>
</select>
</div>
<button class="btn btn--primary btn--lg btn--block" type="submit">Book free trial</button>
</form>
</div>
</section>
</main>
<!-- ===== FOOTER ===== -->
<footer class="footer">
<div class="container footer__inner">
<div class="footer__brand">
<span class="brand__mark" aria-hidden="true">道</span>
<p>Iron Dojo · 22 Forge Street, Iron Quarter<br />Open 6AM–10PM · 7 days a week</p>
</div>
<nav class="footer__links" aria-label="Footer">
<a href="#disciplines">Disciplines</a>
<a href="#coaches">Coaches</a>
<a href="#schedule">Schedule</a>
<a href="#trial" data-trial>Free trial</a>
</nav>
<p class="footer__fine">© 2026 Iron Dojo. Discipline equals freedom. Fictional demo.</p>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Martial Arts / Boxing Landing
A traditional-yet-modern landing page for a fight gym, built on a charcoal-and-crimson palette with slab-serif headings paired with an Inter body for a disciplined, gritty feel. The hero pairs a heavy headline and a “Start your free trial class” CTA with a live intro-class card that shows the coach, remaining spots and a one-tap booking action. Stat counters animate up as the hero enters view.
The disciplines section presents Boxing, Muay Thai, Brazilian Jiu-Jitsu and Kickboxing as cards with kanji watermarks and per-program details, filterable by Striking, Grappling and Conditioning via a tab-style chip row. Below it, a coaches row lists ranked instructors with credentials, a belt-style “Path” maps progression from Foundations to Fight Team, a schedule teaser previews the weekly floor, and member stories add social proof.
Everything is powered by dependency-free vanilla JS: a sticky nav with a mobile menu, IntersectionObserver scroll reveals and counters, the discipline filter, smooth-scroll-to-form CTAs, and an inline trial-booking form with name and email validation. A small toast() helper surfaces feedback for filters, program requests and successful bookings. The layout is fully responsive down to ~360px and respects prefers-reduced-motion.