Storybook — Educational / EdTech Landing
A bright, primary-color landing page for a fictional kids EdTech app, Sparkleton, guided by Sparky the fox mascot. It pairs a friendly SVG hero with three switchable subject tiles for Reading, Math and Science that swap a live daily-lesson list, a guided curriculum map with an interactive weekly progress strip where tapping stars flies a rocket to the finish, a parent-trust section on safe ad-free screens, family pricing with a monthly-yearly toggle, and an easy-read font switch.
MCP
Code
/* ============================================================
Sparkleton — Educational / EdTech Landing
Storybook design system: bright primary colors + white,
chunky rounded shapes, playful Fredoka display + Nunito body.
============================================================ */
:root {
--bg: #fff7ec;
--surface: #ffffff;
--ink: #2c2350;
--ink-soft: #5a5377;
--primary: #ff5a8a; /* reading / pink */
--blue: #3aa0ff; /* math */
--green: #2bb673; /* science / safe */
--amber: #ffb020; /* accent */
--yellow: #ffce2e;
--fox: #ff7a3c;
--line: #efe4d6;
--ring: #3aa0ff;
--r: 22px;
--r-lg: 30px;
--r-pill: 999px;
--shadow-sm: 0 6px 18px rgba(44, 35, 80, .08);
--shadow: 0 16px 40px rgba(44, 35, 80, .12);
--shadow-lift: 0 22px 50px rgba(44, 35, 80, .18);
--font-display: "Fredoka", system-ui, sans-serif;
--font-body: "Nunito", system-ui, sans-serif;
--max: 1120px;
}
/* easy-read / dyslexia-friendly mode */
body.easy-read {
--font-display: "Nunito", system-ui, sans-serif;
--font-body: "Nunito", system-ui, sans-serif;
letter-spacing: .035em;
word-spacing: .12em;
line-height: 1.75;
}
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
font-family: var(--font-body);
color: var(--ink);
background: var(--bg);
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
h1, h2, h3 { font-family: var(--font-display); line-height: 1.12; margin: 0; }
p { margin: 0; }
a { color: inherit; }
img, svg { display: block; max-width: 100%; }
.wrap { width: min(100% - 2.4rem, var(--max)); margin-inline: auto; }
.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: 50%; top: -60px; transform: translateX(-50%);
background: var(--ink); color: #fff; padding: .65rem 1.1rem;
border-radius: var(--r-pill); z-index: 100; font-weight: 700; transition: top .2s;
}
.skip-link:focus { top: 12px; }
:where(a, button, input):focus-visible {
outline: 3px solid var(--ring);
outline-offset: 3px;
border-radius: 12px;
}
/* ===== Buttons ===== */
.btn {
font-family: var(--font-display);
font-weight: 600;
font-size: 1rem;
border: none;
border-radius: var(--r-pill);
padding: .85rem 1.5rem;
min-height: 48px;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: .5rem;
transition: transform .14s ease, box-shadow .14s ease, background .14s ease;
white-space: nowrap;
}
.btn:active { transform: translateY(1px) scale(.98); }
.btn-lg { padding: 1.05rem 1.8rem; font-size: 1.08rem; min-height: 56px; }
.btn-block { width: 100%; }
.btn-primary { background: var(--primary); color: #fff; box-shadow: 0 10px 22px rgba(255, 90, 138, .35); }
.btn-primary:hover { background: #ff447b; transform: translateY(-2px); box-shadow: 0 16px 30px rgba(255, 90, 138, .42); }
.btn-accent { background: var(--yellow); color: var(--ink); box-shadow: 0 10px 22px rgba(255, 206, 46, .4); }
.btn-accent:hover { background: #ffd84d; transform: translateY(-2px); }
.btn-soft { background: #fff; color: var(--ink); box-shadow: inset 0 0 0 2.5px var(--line), var(--shadow-sm); }
.btn-soft:hover { transform: translateY(-2px); box-shadow: inset 0 0 0 2.5px var(--blue), var(--shadow); }
.btn-ghost { background: transparent; color: var(--ink); }
.btn-ghost:hover { background: rgba(44, 35, 80, .06); }
/* ===== Header ===== */
.site-header {
position: sticky; top: 0; z-index: 50;
background: rgba(255, 247, 236, .85);
backdrop-filter: blur(10px);
border-bottom: 2px solid var(--line);
}
.header-inner { display: flex; align-items: center; gap: 1rem; padding: .7rem 0; }
.brand { display: inline-flex; align-items: center; gap: .55rem; text-decoration: none; font-family: var(--font-display); font-weight: 700; }
.brand-mark svg { filter: drop-shadow(0 4px 8px rgba(44, 35, 80, .18)); }
.brand-name { font-size: 1.4rem; color: var(--ink); }
.main-nav { margin-left: auto; }
.main-nav ul { list-style: none; display: flex; gap: .35rem; margin: 0; padding: 0; }
.main-nav a {
text-decoration: none; font-weight: 700; color: var(--ink-soft);
padding: .5rem .8rem; border-radius: var(--r-pill); transition: background .15s, color .15s;
}
.main-nav a:hover { background: #fff; color: var(--ink); box-shadow: var(--shadow-sm); }
.header-cta { display: flex; gap: .5rem; }
.nav-toggle {
display: none; flex-direction: column; gap: 5px; background: #fff; border: 2px solid var(--line);
border-radius: 14px; padding: 11px 10px; cursor: pointer; margin-left: auto;
}
.nav-toggle span { width: 22px; height: 3px; background: var(--ink); border-radius: 3px; transition: transform .2s, opacity .2s; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }
.mobile-nav { display: none; flex-direction: column; gap: .35rem; padding: .8rem 1.2rem 1.2rem; border-bottom: 2px solid var(--line); background: var(--bg); }
.mobile-nav a { text-decoration: none; font-weight: 700; padding: .8rem 1rem; border-radius: 14px; color: var(--ink); }
.mobile-nav a:hover { background: #fff; }
.mobile-nav .btn { margin-top: .4rem; }
/* ===== Hero ===== */
.hero { position: relative; overflow: hidden; padding: clamp(2.5rem, 6vw, 5rem) 0 clamp(3rem, 6vw, 5.5rem); }
.blob { position: absolute; border-radius: 50%; filter: blur(8px); opacity: .5; z-index: 0; }
.blob-a { width: 340px; height: 340px; background: radial-gradient(circle at 30% 30%, #ffe0ec, transparent 70%); top: -90px; right: -60px; }
.blob-b { width: 300px; height: 300px; background: radial-gradient(circle at 60% 40%, #dceeff, transparent 70%); bottom: -120px; left: -80px; }
.hero-inner { position: relative; z-index: 1; display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(1.5rem, 4vw, 3rem); align-items: center; }
.eyebrow {
display: inline-flex; align-items: center; gap: .5rem; font-weight: 800; font-size: .85rem;
color: var(--green); background: #e3f6ec; padding: .4rem .9rem; border-radius: var(--r-pill);
text-transform: uppercase; letter-spacing: .04em;
}
.eyebrow-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--green); animation: pulse 1.8s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.5); opacity: .55; } }
.hero h1 { font-size: clamp(2.3rem, 6vw, 3.6rem); font-weight: 700; margin: 1rem 0 .8rem; }
.hl { color: var(--primary); position: relative; white-space: nowrap; }
.hl::after { content: ""; position: absolute; left: 0; right: 0; bottom: .05em; height: .32em; background: var(--yellow); border-radius: 6px; z-index: -1; opacity: .65; }
.lede { font-size: clamp(1.05rem, 2.2vw, 1.22rem); color: var(--ink-soft); max-width: 34ch; font-weight: 600; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin: 1.6rem 0 1.8rem; }
.trust { list-style: none; display: flex; gap: 1.4rem; padding: 0; margin: 0; flex-wrap: wrap; }
.trust li { display: flex; flex-direction: column; }
.trust strong { font-family: var(--font-display); font-size: 1.4rem; color: var(--ink); }
.trust span { font-size: .85rem; color: var(--ink-soft); font-weight: 700; }
.hero-art { display: flex; justify-content: center; }
.scene { width: 100%; max-width: 460px; filter: drop-shadow(0 24px 40px rgba(44, 35, 80, .14)); }
.scene text { font-family: var(--font-body); }
.mascot { transform-origin: 210px 300px; animation: bob 4s ease-in-out infinite; }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
.chip-art { animation: float 5s ease-in-out infinite; }
.chip-1 { animation-delay: 0s; } .chip-2 { animation-delay: .6s; } .chip-3 { animation-delay: 1.2s; } .chip-4 { animation-delay: 1.8s; }
@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
.twinkle { animation: twinkle 2.4s ease-in-out infinite; transform-origin: center; }
@keyframes twinkle { 0%, 100% { opacity: .4; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.15); } }
/* ===== Stats strip ===== */
.logos { background: var(--ink); color: #fff; padding: 1.4rem 0; text-align: center; }
.logos p { font-weight: 800; text-transform: uppercase; letter-spacing: .08em; font-size: .8rem; opacity: .7; margin-bottom: .7rem; }
.logos ul { list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 1.2rem 2rem; padding: 0; margin: 0; }
.logos li { font-family: var(--font-display); font-weight: 600; font-size: 1.05rem; }
/* ===== Section heads ===== */
.section-head { text-align: center; max-width: 40ch; margin: 0 auto clamp(2rem, 4vw, 3rem); }
.kicker { font-weight: 800; color: var(--primary); text-transform: uppercase; letter-spacing: .08em; font-size: .82rem; margin-bottom: .5rem; }
.section-head h2 { font-size: clamp(1.7rem, 4vw, 2.5rem); font-weight: 700; }
.section-sub { color: var(--ink-soft); font-weight: 600; margin-top: .7rem; font-size: 1.05rem; }
/* ===== Subjects ===== */
.subjects { padding: clamp(3rem, 6vw, 5rem) 0; }
.subject-grid { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.1rem; padding: 0; margin: 0 0 1.6rem; }
.subject-card {
width: 100%; text-align: left; cursor: pointer; font-family: var(--font-body);
background: var(--surface); border: 3px solid var(--line); border-radius: var(--r-lg);
padding: 1.4rem; display: flex; flex-direction: column; gap: .55rem; color: var(--ink);
transition: transform .15s, border-color .15s, box-shadow .15s; box-shadow: var(--shadow-sm);
}
.subject-card:hover { transform: translateY(-5px); box-shadow: var(--shadow); border-color: var(--c); }
.subject-card.is-on { border-color: var(--c); background: var(--c2); box-shadow: var(--shadow); }
.subject-icon {
width: 60px; height: 60px; display: grid; place-items: center; font-size: 1.8rem;
background: var(--c); border-radius: 20px; box-shadow: 0 8px 18px color-mix(in srgb, var(--c) 45%, transparent);
}
.subject-name { font-family: var(--font-display); font-weight: 600; font-size: 1.4rem; }
.subject-desc { color: var(--ink-soft); font-weight: 600; font-size: .98rem; }
.subject-meta { font-weight: 800; font-size: .85rem; color: var(--c); display: inline-flex; align-items: center; gap: .45rem; margin-top: auto; }
.subject-meta .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
/* lesson preview */
.lesson-preview {
background: var(--surface); border: 3px solid var(--line); border-radius: var(--r-lg);
padding: clamp(1.3rem, 3vw, 2rem); box-shadow: var(--shadow-sm);
}
.lesson-head { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.lesson-badge { font-family: var(--font-display); font-weight: 600; color: #fff; background: var(--primary); padding: .35rem .9rem; border-radius: var(--r-pill); font-size: .9rem; transition: background .25s; }
.lesson-head h3 { font-size: 1.4rem; }
.lesson-list { list-style: none; counter-reset: step; padding: 0; margin: 0; display: grid; gap: .7rem; }
.lesson-list li {
counter-increment: step; display: flex; align-items: center; gap: .9rem;
background: var(--bg); border-radius: 18px; padding: .85rem 1rem; font-weight: 700; color: var(--ink);
animation: pop .3s ease both;
}
.lesson-list li::before {
content: counter(step); flex: none; width: 38px; height: 38px; border-radius: 12px;
display: grid; place-items: center; font-family: var(--font-display); font-weight: 600; color: #fff;
background: var(--accent, var(--primary));
}
.lesson-list .l-emoji { font-size: 1.3rem; }
.lesson-list .l-meta { margin-left: auto; font-size: .82rem; color: var(--ink-soft); font-weight: 800; white-space: nowrap; }
@keyframes pop { from { opacity: 0; transform: translateY(8px) scale(.97); } to { opacity: 1; transform: none; } }
/* ===== Learning path ===== */
.path { padding: clamp(3rem, 6vw, 5rem) 0; background: linear-gradient(180deg, #fff 0%, #f4faff 100%); }
.journey { list-style: none; display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; padding: 0; margin: 0 0 2.4rem; counter-reset: stg; }
.stage {
position: relative; background: var(--surface); border: 3px solid var(--line); border-radius: var(--r);
padding: 1.3rem 1.1rem; text-align: center; box-shadow: var(--shadow-sm); transition: transform .15s;
}
.stage:hover { transform: translateY(-4px); }
.stage::before {
content: ""; position: absolute; top: 50%; right: -1rem; width: 1rem; height: 4px;
background: var(--line); z-index: 0;
}
.stage:last-child::before { display: none; }
.stage-art { font-size: 2.2rem; display: block; margin-bottom: .5rem; }
.stage h3 { font-size: 1.25rem; font-weight: 600; }
.stage p { color: var(--ink-soft); font-weight: 600; font-size: .9rem; margin: .35rem 0 .7rem; }
.stage-tag { display: inline-block; font-weight: 800; font-size: .78rem; padding: .25rem .7rem; border-radius: var(--r-pill); background: color-mix(in srgb, var(--s) 18%, #fff); color: var(--s); }
.stage.is-done { border-color: var(--s); }
.stage.is-done .stage-art::after { content: "✓"; }
.stage.is-current { border-color: var(--s); box-shadow: 0 0 0 4px color-mix(in srgb, var(--s) 22%, transparent), var(--shadow); }
.stage.is-current::after { content: "You're here"; position: absolute; top: -14px; left: 50%; transform: translateX(-50%); background: var(--s); color: #fff; font-weight: 800; font-size: .72rem; padding: .25rem .7rem; border-radius: var(--r-pill); white-space: nowrap; }
/* progress demo */
.progress-demo {
display: grid; grid-template-columns: 1fr 1.1fr; gap: clamp(1.5rem, 4vw, 3rem); align-items: center;
background: var(--surface); border: 3px solid var(--line); border-radius: var(--r-lg);
padding: clamp(1.5rem, 4vw, 2.4rem); box-shadow: var(--shadow);
}
.progress-copy h3 { font-size: 1.6rem; margin: .5rem 0; }
.progress-copy p { color: var(--ink-soft); font-weight: 600; }
.progress-figure { margin-top: 1rem !important; color: var(--ink) !important; }
.progress-figure strong { font-family: var(--font-display); font-size: 1.5rem; color: var(--primary); }
.progress-track { display: flex; flex-direction: column; gap: 1.3rem; }
.track-rail { position: relative; height: 16px; background: #eef1f6; border-radius: var(--r-pill); }
.track-fill { position: absolute; inset: 0 auto 0 0; width: 0; background: linear-gradient(90deg, var(--green), var(--blue)); border-radius: var(--r-pill); transition: width .5s cubic-bezier(.34, 1.56, .64, 1); }
.track-rocket { position: absolute; top: 50%; left: 0; transform: translate(-50%, -50%); font-size: 1.5rem; transition: left .5s cubic-bezier(.34, 1.56, .64, 1); }
.track-stars { display: flex; justify-content: space-between; gap: .4rem; }
.star-btn {
flex: 1; min-height: 52px; cursor: pointer; background: var(--bg); border: 2.5px solid var(--line);
border-radius: 16px; font-size: 1.5rem; line-height: 1; padding: .5rem; transition: transform .14s, background .14s, border-color .14s;
filter: grayscale(1) opacity(.5);
}
.star-btn:hover { transform: translateY(-3px); border-color: var(--amber); }
.star-btn.is-done { filter: none; background: #fff5d6; border-color: var(--amber); animation: pop-star .4s ease; }
@keyframes pop-star { 0% { transform: scale(.6); } 60% { transform: scale(1.25); } 100% { transform: scale(1); } }
/* ===== Parent trust ===== */
.parents { padding: clamp(3rem, 6vw, 5rem) 0; }
.parents-inner { display: grid; grid-template-columns: 1.15fr .85fr; gap: clamp(1.8rem, 4vw, 3rem); align-items: center; }
.parents-copy > p { color: var(--ink-soft); font-weight: 600; font-size: 1.08rem; margin: .8rem 0 1.6rem; max-width: 44ch; }
.parents-copy h2 { font-size: clamp(1.7rem, 4vw, 2.4rem); font-weight: 700; }
.trust-grid { list-style: none; display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; padding: 0; margin: 0; }
.trust-grid li { background: var(--surface); border: 3px solid var(--line); border-radius: var(--r); padding: 1.1rem; box-shadow: var(--shadow-sm); transition: transform .15s, border-color .15s; }
.trust-grid li:hover { transform: translateY(-4px); border-color: var(--c); }
.trust-icon { display: inline-grid; place-items: center; width: 48px; height: 48px; font-size: 1.4rem; border-radius: 14px; background: color-mix(in srgb, var(--c) 16%, #fff); margin-bottom: .5rem; }
.trust-grid h3 { font-size: 1.12rem; font-weight: 600; }
.trust-grid p { color: var(--ink-soft); font-weight: 600; font-size: .9rem; margin-top: .25rem; }
.parent-quote {
margin: 0; background: linear-gradient(160deg, var(--primary), #ff8db0); color: #fff;
border-radius: var(--r-lg); padding: clamp(1.6rem, 4vw, 2.4rem); box-shadow: var(--shadow-lift);
position: relative; overflow: hidden;
}
.parent-quote::before { content: "\201C"; position: absolute; top: -20px; left: 16px; font-family: var(--font-display); font-size: 7rem; opacity: .25; }
.parent-quote blockquote { margin: 0 0 1.2rem; font-family: var(--font-display); font-weight: 500; font-size: 1.25rem; line-height: 1.4; position: relative; }
.parent-quote figcaption { display: flex; align-items: center; gap: .8rem; }
.avatar { width: 48px; height: 48px; display: grid; place-items: center; font-size: 1.6rem; background: rgba(255, 255, 255, .25); border-radius: 50%; }
.parent-quote figcaption strong { display: block; font-family: var(--font-display); font-weight: 600; }
.parent-quote figcaption small { opacity: .85; font-weight: 700; }
/* ===== Plans ===== */
.plans { padding: clamp(3rem, 6vw, 5rem) 0; background: linear-gradient(180deg, #fff7ec 0%, #ffeaf0 100%); }
.bill-toggle { display: inline-flex; gap: .25rem; background: #fff; border: 2.5px solid var(--line); border-radius: var(--r-pill); padding: .25rem; margin-top: 1.1rem; box-shadow: var(--shadow-sm); }
.bill-btn { font-family: var(--font-display); font-weight: 600; border: none; background: transparent; color: var(--ink-soft); padding: .55rem 1.2rem; border-radius: var(--r-pill); cursor: pointer; min-height: 44px; display: inline-flex; align-items: center; gap: .4rem; transition: background .15s, color .15s; }
.bill-btn.is-on { background: var(--ink); color: #fff; }
.save { font-size: .7rem; font-weight: 800; background: var(--green); color: #fff; padding: .12rem .5rem; border-radius: var(--r-pill); }
.bill-btn.is-on .save { background: var(--yellow); color: var(--ink); }
.plan-grid { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.2rem; padding: 0; margin: 0; align-items: stretch; }
.plan-card {
position: relative; background: var(--surface); border: 3px solid var(--line); border-radius: var(--r-lg);
padding: 1.7rem 1.5rem; display: flex; flex-direction: column; gap: .7rem; box-shadow: var(--shadow-sm);
transition: transform .15s, box-shadow .15s;
}
.plan-card:hover { transform: translateY(-5px); box-shadow: var(--shadow); }
.plan-card.is-featured { border-color: var(--c); box-shadow: 0 0 0 4px color-mix(in srgb, var(--c) 18%, transparent), var(--shadow); transform: scale(1.02); }
.plan-card.is-featured:hover { transform: scale(1.02) translateY(-5px); }
.plan-flag { position: absolute; top: -15px; left: 50%; transform: translateX(-50%); background: var(--c); color: #fff; font-family: var(--font-display); font-weight: 600; font-size: .8rem; padding: .3rem 1rem; border-radius: var(--r-pill); box-shadow: var(--shadow-sm); }
.plan-card h3 { font-size: 1.5rem; font-weight: 600; color: var(--c); }
.plan-for { color: var(--ink-soft); font-weight: 700; font-size: .92rem; }
.price-tag { display: flex; align-items: baseline; gap: .35rem; margin: .3rem 0; }
.price-tag .amt { font-family: var(--font-display); font-weight: 700; font-size: 2.6rem; color: var(--ink); }
.price-tag .per { color: var(--ink-soft); font-weight: 700; }
.plan-perks { list-style: none; padding: 0; margin: .5rem 0 1.1rem; display: grid; gap: .55rem; }
.plan-perks li { position: relative; padding-left: 1.7rem; font-weight: 700; color: var(--ink); }
.plan-perks li::before { content: "✓"; position: absolute; left: 0; top: -1px; width: 22px; height: 22px; display: grid; place-items: center; background: color-mix(in srgb, var(--green) 18%, #fff); color: var(--green); border-radius: 50%; font-weight: 800; font-size: .8rem; }
.plan-card .btn { margin-top: auto; }
.plan-fine { text-align: center; color: var(--ink-soft); font-weight: 700; margin-top: 1.4rem; }
/* ===== Final CTA ===== */
.cta { padding: clamp(3rem, 6vw, 5rem) 0; }
.cta-inner {
background: linear-gradient(150deg, var(--blue), #6cc0ff); color: #fff; text-align: center;
border-radius: var(--r-lg); padding: clamp(2.2rem, 5vw, 3.4rem); box-shadow: var(--shadow-lift);
position: relative; overflow: hidden;
}
.cta-inner::before, .cta-inner::after { content: ""; position: absolute; border-radius: 50%; background: rgba(255, 255, 255, .15); }
.cta-inner::before { width: 200px; height: 200px; top: -70px; right: -50px; }
.cta-inner::after { width: 150px; height: 150px; bottom: -60px; left: -30px; }
.cta-inner h2 { font-size: clamp(1.6rem, 4vw, 2.4rem); font-weight: 700; position: relative; }
.cta-inner > p { font-weight: 700; opacity: .95; margin-top: .7rem; position: relative; }
.cta-form { position: relative; display: flex; flex-wrap: wrap; gap: .6rem; justify-content: center; margin-top: 1.6rem; }
.cta-form input {
flex: 1 1 260px; max-width: 340px; font-family: var(--font-body); font-weight: 700; font-size: 1rem;
border: none; border-radius: var(--r-pill); padding: .9rem 1.3rem; min-height: 52px; color: var(--ink);
}
.cta-msg { flex-basis: 100%; font-weight: 800; min-height: 1.2em; }
/* ===== Footer ===== */
.site-footer { background: var(--ink); color: #fff; padding: clamp(2.5rem, 5vw, 3.5rem) 0 1.4rem; }
.footer-inner { display: grid; grid-template-columns: 1.3fr 1.7fr; gap: 2rem; }
.footer-brand .brand-name { font-family: var(--font-display); font-size: 1.5rem; }
.footer-brand p { opacity: .75; font-weight: 600; margin: .5rem 0 1.1rem; max-width: 34ch; }
.dyslexia-toggle {
display: inline-flex; align-items: center; gap: .6rem; background: rgba(255, 255, 255, .1);
border: 2px solid rgba(255, 255, 255, .2); color: #fff; font-family: var(--font-body); font-weight: 700;
border-radius: var(--r-pill); padding: .5rem .85rem .5rem .5rem; cursor: pointer; min-height: 44px; transition: background .15s;
}
.dyslexia-toggle:hover { background: rgba(255, 255, 255, .18); }
.dx-knob { width: 38px; height: 22px; border-radius: var(--r-pill); background: rgba(255, 255, 255, .25); position: relative; flex: none; transition: background .2s; }
.dx-knob::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: transform .2s; }
.dyslexia-toggle[aria-pressed="true"] .dx-knob { background: var(--green); }
.dyslexia-toggle[aria-pressed="true"] .dx-knob::after { transform: translateX(16px); }
.footer-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.2rem; }
.footer-cols h3 { font-family: var(--font-display); font-weight: 600; font-size: 1rem; margin-bottom: .6rem; }
.footer-cols a { display: block; text-decoration: none; color: rgba(255, 255, 255, .72); font-weight: 600; padding: .3rem 0; transition: color .15s; }
.footer-cols a:hover { color: #fff; }
.footer-base { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: 2.2rem; padding-top: 1.2rem; border-top: 1px solid rgba(255, 255, 255, .14); }
.footer-base p { opacity: .7; font-weight: 600; font-size: .9rem; }
.footer-emojis { font-size: 1.1rem; letter-spacing: .2rem; }
/* ===== Toast ===== */
.toast {
position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%) translateY(140%);
background: var(--ink); color: #fff; font-weight: 700; padding: .9rem 1.4rem; border-radius: var(--r-pill);
box-shadow: var(--shadow-lift); z-index: 200; max-width: min(90vw, 380px); text-align: center;
opacity: 0; transition: transform .35s cubic-bezier(.34, 1.56, .64, 1), opacity .25s;
}
.toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
/* ===== Responsive ===== */
@media (max-width: 920px) {
.main-nav, .header-cta { display: none; }
.nav-toggle { display: flex; }
.mobile-nav { display: none; }
.mobile-nav.open { display: flex; }
.hero-inner { grid-template-columns: 1fr; text-align: center; }
.hero-copy { order: 2; }
.hero-art { order: 1; }
.lede { margin-inline: auto; }
.hero-actions, .trust { justify-content: center; }
.parents-inner { grid-template-columns: 1fr; }
.progress-demo { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
.subject-grid { grid-template-columns: 1fr; }
.journey { grid-template-columns: 1fr 1fr; }
.stage::before { display: none; }
.plan-grid { grid-template-columns: 1fr; }
.plan-card.is-featured { transform: none; order: -1; }
.plan-card.is-featured:hover { transform: translateY(-5px); }
.footer-inner { grid-template-columns: 1fr; }
}
@media (max-width: 460px) {
.trust-grid { grid-template-columns: 1fr; }
.journey { grid-template-columns: 1fr; }
.footer-cols { grid-template-columns: 1fr 1fr; }
.lesson-list .l-meta { display: none; }
.footer-base { justify-content: center; text-align: center; }
}
/* ===== Reduced motion ===== */
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
*, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}/* ============================================================
Sparkleton — Educational / EdTech Landing
Vanilla JS interactions: mobile nav, toasts, subject switcher
with live lesson list, weekly progress stars + rocket,
billing toggle, email capture, dyslexia-friendly font toggle.
============================================================ */
(function () {
"use strict";
const $ = (sel, root = document) => root.querySelector(sel);
const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel));
/* ---------- Toast helper ---------- */
const toastEl = $("#toast");
let toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => toastEl.classList.remove("show"), 2600);
}
// any element with data-toast fires a toast
document.addEventListener("click", (e) => {
const t = e.target.closest("[data-toast]");
if (t) {
if (t.tagName === "A" && (t.getAttribute("href") || "").startsWith("#")) {
// allow anchor scroll AND toast for demo links that are just "#"
if (t.getAttribute("href") === "#") e.preventDefault();
}
toast(t.getAttribute("data-toast"));
}
const sc = e.target.closest("[data-scroll]");
if (sc) {
const target = $(sc.getAttribute("data-scroll"));
if (target) target.scrollIntoView({ behavior: "smooth", block: "start" });
}
});
/* ---------- Mobile nav ---------- */
const navToggle = $(".nav-toggle");
const mobileNav = $("#mobile-nav");
if (navToggle && mobileNav) {
navToggle.addEventListener("click", () => {
const open = mobileNav.classList.toggle("open");
mobileNav.hidden = !open;
navToggle.setAttribute("aria-expanded", String(open));
navToggle.setAttribute("aria-label", open ? "Close menu" : "Open menu");
});
mobileNav.addEventListener("click", (e) => {
if (e.target.closest("a, .btn")) {
mobileNav.classList.remove("open");
mobileNav.hidden = true;
navToggle.setAttribute("aria-expanded", "false");
navToggle.setAttribute("aria-label", "Open menu");
}
});
}
/* ---------- Subject switcher with live lesson list ---------- */
const SUBJECTS = {
reading: {
name: "Reading",
color: "#ff5a8a",
title: "Today in Reading",
lessons: [
{ emoji: "🔤", text: "Sound out the 'sh' sound", meta: "5 min" },
{ emoji: "📚", text: "Read along: The Sleepy Snail", meta: "8 min" },
{ emoji: "🧩", text: "Match rhyming word pairs", meta: "Game" },
],
},
math: {
name: "Math",
color: "#3aa0ff",
title: "Today in Math",
lessons: [
{ emoji: "🔢", text: "Count fireflies to 30", meta: "4 min" },
{ emoji: "➕", text: "Add the apples in the basket", meta: "6 min" },
{ emoji: "🍕", text: "Share the pizza into halves", meta: "Game" },
],
},
science: {
name: "Science",
color: "#2bb673",
title: "Today in Science",
lessons: [
{ emoji: "🐝", text: "Why do bees buzz?", meta: "5 min" },
{ emoji: "🌧️", text: "Where does rain come from?", meta: "7 min" },
{ emoji: "🪐", text: "Spot the planets puzzle", meta: "Game" },
],
},
};
const subjectCards = $$(".subject-card");
const lessonBadge = $("#lesson-badge");
const lessonTitle = $("#lesson-title");
const lessonList = $("#lesson-list");
function renderSubject(key) {
const s = SUBJECTS[key];
if (!s || !lessonList) return;
if (lessonBadge) {
lessonBadge.textContent = s.name;
lessonBadge.style.background = s.color;
}
if (lessonTitle) lessonTitle.textContent = s.title;
lessonList.innerHTML = "";
s.lessons.forEach((l, i) => {
const li = document.createElement("li");
li.style.setProperty("--accent", s.color);
li.style.animationDelay = i * 80 + "ms";
li.innerHTML =
'<span class="l-emoji" aria-hidden="true"></span>' +
'<span class="l-text"></span>' +
'<span class="l-meta"></span>';
li.querySelector(".l-emoji").textContent = l.emoji;
li.querySelector(".l-text").textContent = l.text;
li.querySelector(".l-meta").textContent = l.meta;
lessonList.appendChild(li);
});
}
subjectCards.forEach((card) => {
card.addEventListener("click", () => {
subjectCards.forEach((c) => {
c.classList.remove("is-on");
c.setAttribute("aria-pressed", "false");
});
card.classList.add("is-on");
card.setAttribute("aria-pressed", "true");
renderSubject(card.dataset.subject);
});
});
// initial render
renderSubject("reading");
/* ---------- Weekly progress: stars + rocket ---------- */
const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const starsWrap = $("#track-stars");
const trackFill = $("#track-fill");
const trackRocket = $("#track-rocket");
const progressPct = $("#progress-pct");
const streakCount = $("#streak-count");
const doneState = new Array(DAYS.length).fill(false);
// pre-complete the streak (Mon–Fri) to match the "5-day streak" copy
for (let i = 0; i < 5; i++) doneState[i] = true;
function refreshProgress(animate) {
const done = doneState.filter(Boolean).length;
const pct = Math.round((done / DAYS.length) * 100);
if (trackFill) trackFill.style.width = pct + "%";
if (trackRocket) trackRocket.style.left = pct + "%";
if (progressPct) progressPct.textContent = pct + "%";
if (streakCount) {
// streak = leading run of completed days from Monday
let streak = 0;
for (let i = 0; i < doneState.length && doneState[i]; i++) streak++;
streakCount.textContent = streak;
}
if (animate && pct === 100) toast("Whole week done — you're a superstar! 🌟");
}
if (starsWrap) {
DAYS.forEach((day, i) => {
const btn = document.createElement("button");
btn.type = "button";
btn.className = "star-btn" + (doneState[i] ? " is-done" : "");
btn.textContent = "⭐";
btn.setAttribute("aria-pressed", String(doneState[i]));
btn.setAttribute("aria-label", day + (doneState[i] ? " — lesson done" : " — mark lesson done"));
btn.addEventListener("click", () => {
doneState[i] = !doneState[i];
btn.classList.toggle("is-done", doneState[i]);
btn.setAttribute("aria-pressed", String(doneState[i]));
btn.setAttribute("aria-label", day + (doneState[i] ? " — lesson done" : " — mark lesson done"));
refreshProgress(true);
});
starsWrap.appendChild(btn);
});
refreshProgress(false);
}
/* ---------- Pricing: billing toggle ---------- */
const billBtns = $$(".bill-btn");
const amts = $$(".price-tag .amt");
const pers = $$(".price-tag .per");
billBtns.forEach((btn) => {
btn.addEventListener("click", () => {
const mode = btn.dataset.bill; // monthly | yearly
billBtns.forEach((b) => {
b.classList.toggle("is-on", b === btn);
b.setAttribute("aria-pressed", String(b === btn));
});
amts.forEach((a) => {
a.textContent = mode === "yearly" ? a.dataset.year : a.dataset.month;
});
pers.forEach((p) => {
p.textContent = mode === "yearly" ? "/ month, billed yearly" : "/ month";
});
});
});
/* ---------- CTA email capture ---------- */
const ctaForm = $("#cta-form");
if (ctaForm) {
const input = $("#cta-email");
const msg = $("#cta-msg");
ctaForm.addEventListener("submit", (e) => {
e.preventDefault();
const val = (input.value || "").trim();
const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
if (!ok) {
msg.textContent = "Oops — please enter a valid email. 🙂";
msg.style.color = "#fff3a8";
input.focus();
return;
}
msg.textContent = "You're in! Check your inbox for the first lesson. 🎉";
msg.style.color = "#fff";
input.value = "";
toast("Free trial started — let's learn! 🎉");
});
}
/* ---------- Dyslexia-friendly / easy-read toggle ---------- */
const dx = $("#dyslexia-toggle");
if (dx) {
dx.addEventListener("click", () => {
const on = document.body.classList.toggle("easy-read");
dx.setAttribute("aria-pressed", String(on));
toast(on ? "Easy-read font on 📖" : "Easy-read font off");
});
}
/* ---------- Active-section highlight in nav ---------- */
const navLinks = $$(".main-nav a[href^='#']");
const sections = navLinks
.map((a) => $(a.getAttribute("href")))
.filter(Boolean);
if ("IntersectionObserver" in window && sections.length) {
const io = new IntersectionObserver(
(entries) => {
entries.forEach((en) => {
if (en.isIntersecting) {
const id = "#" + en.target.id;
navLinks.forEach((a) =>
a.style.setProperty(
"background",
a.getAttribute("href") === id ? "#fff" : ""
)
);
}
});
},
{ rootMargin: "-45% 0px -50% 0px" }
);
sections.forEach((s) => io.observe(s));
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Sparkleton — learning made playful</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fredoka:wght@500;600;700&family=Nunito:wght@400;600;700;800&display=swap" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<!-- ===== Header ===== -->
<header class="site-header" role="banner">
<div class="wrap header-inner">
<a class="brand" href="#main" aria-label="Sparkleton home">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 48 48" width="40" height="40" focusable="false">
<rect x="2" y="2" width="44" height="44" rx="14" fill="#ffce2e"/>
<circle cx="24" cy="22" r="13" fill="#ff5a8a"/>
<circle cx="19.5" cy="20" r="3.2" fill="#fff"/>
<circle cx="28.5" cy="20" r="3.2" fill="#fff"/>
<circle cx="19.5" cy="20.6" r="1.5" fill="#222"/>
<circle cx="28.5" cy="20.6" r="1.5" fill="#222"/>
<path d="M19 27q5 4 10 0" stroke="#fff" stroke-width="2.4" fill="none" stroke-linecap="round"/>
<path d="M24 6l2 4 4 .5-3 3 .8 4-3.8-2-3.8 2 .8-4-3-3 4-.5z" fill="#2bb673"/>
</svg>
</span>
<span class="brand-name">Sparkleton</span>
</a>
<nav class="main-nav" aria-label="Primary">
<ul>
<li><a href="#subjects">Subjects</a></li>
<li><a href="#path">Learning path</a></li>
<li><a href="#parents">For parents</a></li>
<li><a href="#plans">Pricing</a></li>
</ul>
</nav>
<div class="header-cta">
<button class="btn btn-ghost" type="button" data-toast="Welcome back! Sign-in is just a demo.">Log in</button>
<button class="btn btn-primary" type="button" data-toast="Free trial started — let's learn! 🎉">Start free</button>
</div>
<button class="nav-toggle" type="button" aria-expanded="false" aria-controls="mobile-nav" aria-label="Open menu">
<span></span><span></span><span></span>
</button>
</div>
<div class="mobile-nav" id="mobile-nav" hidden>
<a href="#subjects">Subjects</a>
<a href="#path">Learning path</a>
<a href="#parents">For parents</a>
<a href="#plans">Pricing</a>
<button class="btn btn-primary" type="button" data-toast="Free trial started — let's learn! 🎉">Start free</button>
</div>
</header>
<main id="main">
<!-- ===== Hero ===== -->
<section class="hero" aria-labelledby="hero-title">
<span class="blob blob-a" aria-hidden="true"></span>
<span class="blob blob-b" aria-hidden="true"></span>
<div class="wrap hero-inner">
<div class="hero-copy">
<p class="eyebrow"><span class="eyebrow-dot" aria-hidden="true"></span> Standards-aligned · ages 4–11</p>
<h1 id="hero-title">Where curious kids <span class="hl">love to learn</span>.</h1>
<p class="lede">Sparkleton turns reading, math and science into bright, bite-size
adventures — guided by Sparky the fox, with zero ads and 100% safe screens.</p>
<div class="hero-actions">
<button class="btn btn-primary btn-lg" type="button" data-toast="Free trial started — let's learn! 🎉">Try 14 days free</button>
<button class="btn btn-soft btn-lg" type="button" data-scroll="#path">See how it works</button>
</div>
<ul class="trust" aria-label="Why families trust us">
<li><strong>4.9★</strong><span>Parent rating</span></li>
<li><strong>0 ads</strong><span>Always</span></li>
<li><strong>COPPA</strong><span>Safe & private</span></li>
</ul>
</div>
<!-- Flat SVG hero illustration: Sparky the fox mascot with floating subjects -->
<div class="hero-art">
<svg viewBox="0 0 420 380" class="scene" role="img" aria-label="Sparky the fox holding a book, surrounded by floating learning icons">
<!-- back panel -->
<rect x="14" y="18" width="392" height="300" rx="34" fill="#eaf3ff"/>
<!-- ground arc -->
<path d="M14 256c80-34 150-30 200-2s140 22 192-8v48a30 30 0 0 1-30 30H44a30 30 0 0 1-30-30Z" fill="#b9e6c8"/>
<!-- floating learning chips -->
<g class="chip-art chip-1"><circle cx="78" cy="80" r="30" fill="#ff5a8a"/><text x="78" y="90" font-size="26" text-anchor="middle">📖</text></g>
<g class="chip-art chip-2"><circle cx="338" cy="74" r="30" fill="#3aa0ff"/><text x="338" y="84" font-size="26" text-anchor="middle">➗</text></g>
<g class="chip-art chip-3"><circle cx="356" cy="186" r="26" fill="#2bb673"/><text x="356" y="195" font-size="22" text-anchor="middle">🔬</text></g>
<g class="chip-art chip-4"><circle cx="62" cy="196" r="24" fill="#ffb020"/><text x="62" y="205" font-size="20" text-anchor="middle">🎨</text></g>
<!-- Sparky the fox -->
<g class="mascot">
<ellipse cx="210" cy="316" rx="74" ry="14" fill="#000" opacity=".08"/>
<!-- tail -->
<path d="M150 250c-30 6-46 30-40 56 18 4 40-6 50-26-4-12-6-22-10-30Z" fill="#ff7a3c"/>
<path d="M126 296c2 8 8 12 16 14 2-10-2-20-8-26-4 4-6 8-8 12Z" fill="#fff"/>
<!-- body -->
<rect x="168" y="210" width="84" height="86" rx="34" fill="#ff7a3c"/>
<path d="M168 250a42 42 0 0 0 84 0v36a42 42 0 0 1-84 0Z" fill="#fff" opacity=".55"/>
<!-- arms holding book -->
<rect x="150" y="252" width="40" height="20" rx="10" fill="#ff7a3c" transform="rotate(-12 170 262)"/>
<rect x="230" y="252" width="40" height="20" rx="10" fill="#ff7a3c" transform="rotate(12 250 262)"/>
<!-- book -->
<g class="book">
<rect x="172" y="252" width="76" height="50" rx="8" fill="#3aa0ff"/>
<rect x="178" y="258" width="30" height="38" rx="4" fill="#eaf3ff"/>
<rect x="212" y="258" width="30" height="38" rx="4" fill="#fff"/>
<path d="M208 256v44" stroke="#1f7fd6" stroke-width="3"/>
</g>
<!-- head -->
<circle cx="210" cy="172" r="46" fill="#ff7a3c"/>
<path d="M168 158l-14-34 30 20zM252 158l14-34-30 20z" fill="#ff7a3c"/>
<path d="M170 152l-7-18 16 11zM250 152l7-18-16 11z" fill="#7a2e10"/>
<!-- face mask -->
<path d="M176 168q34-24 68 0-12 28-34 28-22 0-34-28Z" fill="#fff"/>
<ellipse cx="210" cy="196" rx="14" ry="11" fill="#fff"/>
<!-- eyes -->
<circle cx="194" cy="170" r="6.5" fill="#2c2350"/>
<circle cx="226" cy="170" r="6.5" fill="#2c2350"/>
<circle cx="196" cy="168" r="2.2" fill="#fff"/>
<circle cx="228" cy="168" r="2.2" fill="#fff"/>
<!-- nose + smile -->
<ellipse cx="210" cy="190" rx="6" ry="5" fill="#2c2350"/>
<path d="M210 195q0 8 -8 10M210 195q0 8 8 10" stroke="#2c2350" stroke-width="3" fill="none" stroke-linecap="round"/>
<!-- cheeks -->
<circle cx="180" cy="190" r="6" fill="#ff5a8a" opacity=".5"/>
<circle cx="240" cy="190" r="6" fill="#ff5a8a" opacity=".5"/>
<!-- sparkle -->
<path class="twinkle" d="M150 118l3 7 7 1-5 4 1 7-6-4-6 4 1-7-5-4 7-1z" fill="#ffce2e"/>
</g>
</svg>
</div>
</div>
</section>
<!-- ===== Stats strip ===== -->
<section class="logos" aria-label="Sparkleton by the numbers">
<p>Helping kids learn in</p>
<ul>
<li>🏡 28,000 homes</li><li>🏫 640 classrooms</li><li>🧩 900+ lessons</li><li>🌍 7 languages</li>
</ul>
</section>
<!-- ===== Subjects ===== -->
<section class="subjects" id="subjects" aria-labelledby="subjects-title">
<div class="wrap">
<header class="section-head">
<p class="kicker">Three big worlds to explore</p>
<h2 id="subjects-title">Pick a subject & start the adventure</h2>
<p class="section-sub">Every world is a sequence of short, playful lessons that adapt to how your child learns.</p>
</header>
<ul class="subject-grid" id="subject-grid">
<li>
<button class="subject-card is-on" type="button" data-subject="reading" aria-pressed="true" style="--c:#ff5a8a;--c2:#ffe2ec">
<span class="subject-icon" aria-hidden="true">📖</span>
<span class="subject-name">Reading</span>
<span class="subject-desc">Phonics, sight words & story comprehension that builds real fluency.</span>
<span class="subject-meta"><span class="dot" aria-hidden="true"></span> 320 lessons</span>
</button>
</li>
<li>
<button class="subject-card" type="button" data-subject="math" aria-pressed="false" style="--c:#3aa0ff;--c2:#dceeff">
<span class="subject-icon" aria-hidden="true">➗</span>
<span class="subject-name">Math</span>
<span class="subject-desc">Counting to fractions through games, puzzles and number sense.</span>
<span class="subject-meta"><span class="dot" aria-hidden="true"></span> 410 lessons</span>
</button>
</li>
<li>
<button class="subject-card" type="button" data-subject="science" aria-pressed="false" style="--c:#2bb673;--c2:#d6f3e2">
<span class="subject-icon" aria-hidden="true">🔬</span>
<span class="subject-name">Science</span>
<span class="subject-desc">Curious experiments about animals, space and how the world works.</span>
<span class="subject-meta"><span class="dot" aria-hidden="true"></span> 170 lessons</span>
</button>
</li>
</ul>
<!-- Lesson preview, driven by the selected subject -->
<div class="lesson-preview" id="lesson-preview" aria-live="polite">
<div class="lesson-head">
<span class="lesson-badge" id="lesson-badge">Reading</span>
<h3 id="lesson-title">Today in Reading</h3>
</div>
<ol class="lesson-list" id="lesson-list"><!-- injected by script.js --></ol>
</div>
</div>
</section>
<!-- ===== Learning path / curriculum strip ===== -->
<section class="path" id="path" aria-labelledby="path-title">
<div class="wrap">
<header class="section-head">
<p class="kicker">A clear path, step by step</p>
<h2 id="path-title">Sparky's learning journey</h2>
<p class="section-sub">Kids climb a guided map — each island unlocks the next, so there's always a next little win.</p>
</header>
<ol class="journey" aria-label="Curriculum stages">
<li class="stage is-done" style="--s:#2bb673"><span class="stage-art" aria-hidden="true">🌱</span><h3>Sprout</h3><p>Letters, sounds & counting to 20.</p><span class="stage-tag">Ages 4–5</span></li>
<li class="stage is-done" style="--s:#3aa0ff"><span class="stage-art" aria-hidden="true">🚀</span><h3>Explorer</h3><p>First words, addition & living things.</p><span class="stage-tag">Ages 6–7</span></li>
<li class="stage is-current" style="--s:#ff5a8a"><span class="stage-art" aria-hidden="true">🏆</span><h3>Champion</h3><p>Reading fluency, times tables & weather.</p><span class="stage-tag">Ages 8–9</span></li>
<li class="stage" style="--s:#ffb020"><span class="stage-art" aria-hidden="true">🌟</span><h3>Star</h3><p>Chapter books, fractions & the solar system.</p><span class="stage-tag">Ages 10–11</span></li>
</ol>
<!-- Live progress demo -->
<div class="progress-demo">
<div class="progress-copy">
<p class="kicker">Sparky's week</p>
<h3>You're on a <span id="streak-count">5</span>-day streak! 🔥</h3>
<p>Tap a star to mark a lesson done and watch the rocket fly to the finish line.</p>
<p class="progress-figure"><strong id="progress-pct">0%</strong> of this week complete</p>
</div>
<div class="progress-track" role="group" aria-label="This week's lessons">
<div class="track-rail"><span class="track-fill" id="track-fill"></span><span class="track-rocket" id="track-rocket" aria-hidden="true">🚀</span></div>
<div class="track-stars" id="track-stars"><!-- injected by script.js --></div>
</div>
</div>
</div>
</section>
<!-- ===== Parent trust ===== -->
<section class="parents" id="parents" aria-labelledby="parents-title">
<div class="wrap parents-inner">
<div class="parents-copy">
<p class="kicker">Built for grown-ups too</p>
<h2 id="parents-title">Screens you can feel good about</h2>
<p>No ads, no autoplay rabbit holes, no chat with strangers. Just a calm, focused
place to learn — with a parent dashboard that shows real progress.</p>
<ul class="trust-grid">
<li style="--c:#2bb673"><span class="trust-icon" aria-hidden="true">🛡️</span><h3>Ad-free & safe</h3><p>Zero ads and no in-app purchases inside kid screens.</p></li>
<li style="--c:#3aa0ff"><span class="trust-icon" aria-hidden="true">🔒</span><h3>Private by design</h3><p>COPPA & GDPR-K compliant. We never sell data.</p></li>
<li style="--c:#ff5a8a"><span class="trust-icon" aria-hidden="true">⏱️</span><h3>Screen-time tools</h3><p>Set daily limits and a gentle wind-down timer.</p></li>
<li style="--c:#ffb020"><span class="trust-icon" aria-hidden="true">📊</span><h3>Progress reports</h3><p>Weekly emails on what your child mastered.</p></li>
</ul>
</div>
<figure class="parent-quote">
<blockquote>"My daughter asks to do her Sparkleton lessons before screen-time cartoons.
She doesn't even realise it's school work."</blockquote>
<figcaption>
<span class="avatar" aria-hidden="true">👩🏽</span>
<span><strong>Priya M.</strong><small>Parent of a 7-year-old · verified</small></span>
</figcaption>
</figure>
</div>
</section>
<!-- ===== Plans / pricing for families ===== -->
<section class="plans" id="plans" aria-labelledby="plans-title">
<div class="wrap">
<header class="section-head">
<p class="kicker">Family pricing</p>
<h2 id="plans-title">One plan, the whole family learns</h2>
<div class="bill-toggle" role="group" aria-label="Choose billing period">
<button class="bill-btn is-on" type="button" data-bill="monthly" aria-pressed="true">Monthly</button>
<button class="bill-btn" type="button" data-bill="yearly" aria-pressed="false">Yearly <span class="save">save 30%</span></button>
</div>
</header>
<ul class="plan-grid">
<li class="plan-card" style="--c:#3aa0ff">
<h3>Starter</h3>
<p class="plan-for">1 child, the essentials</p>
<p class="price-tag"><span class="amt" data-month="$6.99" data-year="$4.90">$6.99</span><span class="per" data-per>/ month</span></p>
<ul class="plan-perks">
<li>1 learner profile</li>
<li>Reading, Math & Science</li>
<li>Offline lessons</li>
</ul>
<button class="btn btn-soft btn-block" type="button" data-toast="Starter trial started — happy learning! 🎉">Start free trial</button>
</li>
<li class="plan-card is-featured" style="--c:#ff5a8a">
<span class="plan-flag">Most loved</span>
<h3>Family</h3>
<p class="plan-for">Up to 4 kids, everything</p>
<p class="price-tag"><span class="amt" data-month="$11.99" data-year="$8.39">$11.99</span><span class="per" data-per>/ month</span></p>
<ul class="plan-perks">
<li>4 learner profiles</li>
<li>Everything in Starter</li>
<li>Parent dashboard & reports</li>
<li>Screen-time controls</li>
</ul>
<button class="btn btn-primary btn-block" type="button" data-toast="Family trial started — the whole crew is in! 🎉">Start free trial</button>
</li>
<li class="plan-card" style="--c:#2bb673">
<h3>Classroom</h3>
<p class="plan-for">For teachers & co-ops</p>
<p class="price-tag"><span class="amt" data-month="$29" data-year="$20.30">$29</span><span class="per" data-per>/ month</span></p>
<ul class="plan-perks">
<li>Up to 30 learners</li>
<li>Group progress board</li>
<li>Printable worksheets</li>
</ul>
<button class="btn btn-soft btn-block" type="button" data-toast="Classroom demo requested — we'll be in touch! 🎉">Talk to us</button>
</li>
</ul>
<p class="plan-fine">14-day free trial · no card needed · cancel anytime.</p>
</div>
</section>
<!-- ===== Final CTA ===== -->
<section class="cta" aria-labelledby="cta-title">
<div class="wrap cta-inner">
<h2 id="cta-title">Ready to make learning the best part of the day?</h2>
<p>Join 28,000 families turning screen time into glow-up time.</p>
<form class="cta-form" id="cta-form" novalidate>
<label class="sr-only" for="cta-email">Parent email</label>
<input id="cta-email" type="email" name="email" placeholder="[email protected]" autocomplete="email" required />
<button class="btn btn-accent" type="submit">Start free</button>
<p class="cta-msg" id="cta-msg" role="status" aria-live="polite"></p>
</form>
</div>
</section>
</main>
<!-- ===== Footer ===== -->
<footer class="site-footer" role="contentinfo">
<div class="wrap footer-inner">
<div class="footer-brand">
<span class="brand-name">Sparkleton</span>
<p>Learning made playful — bright, safe & ad-free for curious kids.</p>
<button class="dyslexia-toggle" id="dyslexia-toggle" type="button" aria-pressed="false">
<span class="dx-knob" aria-hidden="true"></span>
<span>Easy-read font</span>
</button>
</div>
<nav class="footer-cols" aria-label="Footer">
<div>
<h3>Learn</h3>
<a href="#subjects">Subjects</a>
<a href="#path">Learning path</a>
<a href="#plans">Pricing</a>
</div>
<div>
<h3>Company</h3>
<a href="#" data-toast="Just a demo link.">About</a>
<a href="#" data-toast="Just a demo link.">Careers</a>
<a href="#" data-toast="Just a demo link.">Press</a>
</div>
<div>
<h3>Trust</h3>
<a href="#parents" >For parents</a>
<a href="#" data-toast="Just a demo link.">Privacy</a>
<a href="#" data-toast="Just a demo link.">Safety</a>
</div>
</nav>
</div>
<div class="footer-base">
<p>© 2026 Sparkleton — a fictional EdTech app.</p>
<p class="footer-emojis" aria-hidden="true">🦊 📖 ➗ 🔬 🌟</p>
</div>
</footer>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Educational / EdTech Landing
A cheerful, credible landing page for Sparkleton, a fictional learning app for ages 4–11. It leads with a chunky SVG hero — Sparky the fox holding a book, ringed by floating subject chips — and a clear value prop set in friendly Fredoka display type over high-legibility Nunito body. A dark stats strip and a value-prop grid keep the energy up while staying readable, and every control has hover, active and :focus-visible states with WCAG AA contrast.
The page is genuinely interactive. Three subject tiles (Reading, Math, Science) act as a radio-style group: choosing one recolors and rewrites a live “Today in…” lesson list. The curriculum strip shows a four-stage learning journey with a “You’re here” marker, plus a weekly progress track where tapping the day stars marks lessons done, animates the fill bar, flies a rocket emoji to the finish line and updates the streak count and percentage. Family pricing flips between monthly and yearly prices via an accessible toggle, the final CTA validates the email before confirming, and a footer switch turns on a dyslexia-friendly easy-read font with looser spacing. The layout collapses gracefully from a two-column hero to a single column down to 360px, and all motion respects prefers-reduced-motion.
Illustrative kids’ UI only — fictional stories, characters, and audio.