TEST 2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Build Your Path</title>
<style>
:root {
--bg: #f5f7f9;
--panel: #ffffff;
--text: #1f2a37;
--muted: #5f6b7a;
--line: #dbe3ea;
--brand: #156082;
--brand-soft: #e8f3f7;
--accent: #5cacd7;
--success: #1f8a5b;
--warn: #fff4db;
--shadow: 0 12px 30px rgba(21, 96, 130, 0.08);
--radius: 22px;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Inter, Arial, Helvetica, sans-serif;
background: linear-gradient(180deg, #f7f9fb 0%, #eef3f6 100%);
color: var(--text);
line-height: 1.45;
}
.wrap {
max-width: 1280px;
margin: 0 auto;
padding: 32px 20px 56px;
}
.hero {
background: rgba(255,255,255,0.7);
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.7);
border-radius: 30px;
padding: 28px 28px 18px;
box-shadow: var(--shadow);
margin-bottom: 22px;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border-radius: 999px;
background: var(--brand-soft);
color: var(--brand);
font-size: 13px;
font-weight: 700;
letter-spacing: 0.02em;
margin-bottom: 12px;
}
h1 {
font-size: clamp(2rem, 4vw, 3rem);
line-height: 1.05;
margin: 0 0 10px;
letter-spacing: -0.03em;
}
.subtitle {
max-width: 880px;
color: var(--muted);
font-size: 1rem;
margin: 0;
}
.layout {
display: grid;
grid-template-columns: 360px 1fr;
gap: 22px;
align-items: start;
}
.panel {
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
}
.controls {
padding: 22px;
position: sticky;
top: 20px;
}
.control-block + .control-block { margin-top: 18px; }
.control-label {
display: block;
font-size: 0.95rem;
font-weight: 700;
margin-bottom: 8px;
}
select {
width: 100%;
padding: 14px 16px;
border-radius: 14px;
border: 1px solid var(--line);
background: #fff;
color: var(--text);
font-size: 0.98rem;
}
.note {
margin-top: 18px;
padding: 14px 14px;
border-radius: 16px;
background: var(--warn);
color: #6a5220;
font-size: 0.93rem;
}
.btn-row {
display: flex;
gap: 10px;
margin-top: 18px;
flex-wrap: wrap;
}
button {
border: 0;
border-radius: 999px;
padding: 12px 18px;
font-weight: 700;
cursor: pointer;
transition: transform 0.15s ease, opacity 0.15s ease;
}
button:hover { transform: translateY(-1px); }
.btn-primary {
background: linear-gradient(135deg, var(--brand), var(--accent));
color: white;
}
.btn-secondary {
background: #eef3f6;
color: var(--text);
}
.results {
padding: 22px;
}
.summary-card {
border: 1px solid var(--line);
border-radius: 18px;
padding: 18px;
background: linear-gradient(180deg, #fff 0%, #fbfdff 100%);
margin-bottom: 18px;
}
.chips {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 12px;
}
.chip {
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 7px 12px;
font-size: 0.84rem;
font-weight: 700;
}
.chip.mode { background: #edf7ff; color: #0f5e7e; }
.chip.award { background: #edf8f1; color: #156c48; }
.chip.entry { background: #f3efff; color: #5d4ca7; }
.summary-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
margin-top: 12px;
}
.metric {
border: 1px solid var(--line);
border-radius: 16px;
padding: 14px;
background: #fff;
}
.metric-label {
font-size: 0.8rem;
color: var(--muted);
margin-bottom: 6px;
}
.metric-value {
font-size: 1.08rem;
font-weight: 800;
}
.path-title {
display: flex;
justify-content: space-between;
gap: 16px;
align-items: flex-end;
margin: 10px 0 16px;
flex-wrap: wrap;
}
.path-title h2 {
margin: 0;
font-size: 1.4rem;
letter-spacing: -0.02em;
}
.path-sub {
color: var(--muted);
font-size: 0.95rem;
}
.timeline {
display: grid;
gap: 16px;
}
.term {
position: relative;
display: grid;
grid-template-columns: 190px 1fr;
gap: 16px;
padding: 18px;
border: 1px solid var(--line);
border-radius: 20px;
background: #fff;
overflow: hidden;
}
.term::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 6px;
background: linear-gradient(180deg, var(--brand), var(--accent));
}
.term-meta {
padding-left: 8px;
}
.term-kicker {
color: var(--brand);
font-size: 0.82rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 6px;
}
.term-name {
font-size: 1.25rem;
font-weight: 800;
margin-bottom: 6px;
}
.term-desc {
font-size: 0.93rem;
color: var(--muted);
}
.course-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
align-content: start;
}
.course-card {
border-radius: 18px;
padding: 16px;
min-height: 120px;
color: white;
display: flex;
flex-direction: column;
justify-content: space-between;
box-shadow: 0 8px 18px rgba(0,0,0,0.08);
}
.core { background: linear-gradient(160deg, #156082 0%, #2f86ad 100%); }
.elective { background: linear-gradient(160deg, #2b7a58 0%, #4aa876 100%); }
.research { background: linear-gradient(160deg, #6c52c8 0%, #8e73ef 100%); }
.project { background: linear-gradient(160deg, #bb7a11 0%, #dfaa47 100%); }
.course-top {
font-size: 0.76rem;
text-transform: uppercase;
letter-spacing: 0.08em;
opacity: 0.9;
font-weight: 700;
}
.course-name {
font-size: 1.18rem;
font-weight: 800;
line-height: 1.05;
margin: 10px 0;
}
.course-meta {
font-size: 0.88rem;
opacity: 0.95;
}
.milestone-row {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
margin-top: 18px;
}
.milestone {
border: 1px solid var(--line);
border-radius: 18px;
padding: 16px;
background: #f9fbfc;
}
.milestone h3 {
margin: 0 0 8px;
font-size: 1rem;
}
.milestone p {
margin: 0;
color: var(--muted);
font-size: 0.92rem;
}
.footer-note {
margin-top: 18px;
padding: 14px 16px;
border-radius: 16px;
background: #f4f8fb;
border: 1px dashed #cbd8e2;
font-size: 0.92rem;
color: var(--muted);
}
@media (max-width: 1040px) {
.layout { grid-template-columns: 1fr; }
.controls { position: static; }
.summary-grid, .milestone-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
.wrap { padding: 18px 14px 40px; }
.hero, .controls, .results { padding: 18px; }
.term { grid-template-columns: 1fr; }
.summary-grid, .milestone-row { grid-template-columns: 1fr; }
.course-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
.course-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="wrap">
<section class="hero panel">
<div class="eyebrow">Interactive programme planner</div>
<h1>Build Your Path</h1>
<p class="subtitle">
A student-facing roadmap that lets learners choose their study mode, intended award, and starting point, then instantly see a clear learning path from certificate to diploma to master's.
<br><br><strong>Disclaimer:</strong> The information in the interactive programme planner is for information purposes only. Please consult the Chief Academic Affairs Officer for tailored academic advising.
</p>
</section>
<section class="layout">
<aside class="panel controls">
<div class="control-block">
<label class="control-label" for="mode">1. Select study mode</label>
<select id="mode">
<option value="full">Full-time</option>
<option value="part">Part-time</option>
</select>
</div>
<div class="control-block">
<label class="control-label" for="award">2. Select your intended award</label>
<select id="award">
<option value="certificate">Postgraduate Certificate</option>
<option value="diploma">Postgraduate Diploma</option>
<option value="masters">Master's (MSc)</option>
</select>
</div>
<div class="control-block">
<label class="control-label" for="entry">3. Confirm your entry point</label>
<select id="entry">
<option value="start">I am starting from the beginning</option>
<option value="certificate_done">I have already completed the certificate</option>
<option value="diploma_done">I have already completed the diploma</option>
</select>
</div>
<div class="note" id="helperText">
This pathway shows the recommended registration sequence and keeps the learner focused on “what do I register for next?”
</div>
<div class="btn-row">
<button class="btn-primary" id="generateBtn">Generate my path</button>
<button class="btn-secondary" id="resetBtn">Reset</button>
</div>
</aside>
<main class="panel results">
<div class="summary-card">
<div class="chips" id="chips"></div>
<div class="path-title">
<div>
<h2 id="pathHeading">Your recommended path</h2>
<div class="path-sub" id="pathSub">Choose your options to view the sequence.</div>
</div>
</div>
<div class="summary-grid" id="summaryGrid"></div>
</div>
<div class="timeline" id="timeline"></div>
<div class="milestone-row" id="milestones"></div>
<div class="footer-note" id="footerNote"></div>
</main>
</section>
</div>
<script>
const data = {
certificate: {
label: 'Postgraduate Certificate',
credits: 12,
fullDuration: '16 weeks',
partDuration: '32 weeks',
terms: {
full: [
{ name: 'Block 1', weeks: '8 weeks', courses: [
{ label: 'Course 1', type: 'core', subtype: 'Core course' },
{ label: 'Course 2', type: 'core', subtype: 'Core course' }
]},
{ name: 'Block 2', weeks: '8 weeks', courses: [
{ label: 'Course 3', type: 'core', subtype: 'Core course' },
{ label: 'Course 4', type: 'core', subtype: 'Core course' }
]}
],
part: [
{ name: 'Block 1', weeks: '8 weeks', courses: [{ label: 'Course 1', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 2', weeks: '8 weeks', courses: [{ label: 'Course 2', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 3', weeks: '8 weeks', courses: [{ label: 'Course 3', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 4', weeks: '8 weeks', courses: [{ label: 'Course 4', type: 'core', subtype: 'Core course' }]}
]
}
},
diploma: {
label: 'Postgraduate Diploma',
credits: 21,
fullDuration: '32 weeks',
partDuration: '56 weeks',
terms: {
full: [
{ name: 'Block 1', weeks: '8 weeks', courses: [
{ label: 'Course 1', type: 'core', subtype: 'Core course' },
{ label: 'Course 2', type: 'core', subtype: 'Core course' }
]},
{ name: 'Block 2', weeks: '8 weeks', courses: [
{ label: 'Course 3', type: 'core', subtype: 'Core course' },
{ label: 'Course 4', type: 'core', subtype: 'Core course' }
]},
{ name: 'Block 3', weeks: '8 weeks', courses: [
{ label: 'Course 5', type: 'core', subtype: 'Core course' },
{ label: 'Course 6', type: 'elective', subtype: 'Elective' }
]},
{ name: 'Block 4', weeks: '8 weeks', courses: [
{ label: 'Course 7', type: 'elective', subtype: 'Elective' }
]}
],
part: [
{ name: 'Block 1', weeks: '8 weeks', courses: [{ label: 'Course 1', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 2', weeks: '8 weeks', courses: [{ label: 'Course 2', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 3', weeks: '8 weeks', courses: [{ label: 'Course 3', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 4', weeks: '8 weeks', courses: [{ label: 'Course 4', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 5', weeks: '8 weeks', courses: [{ label: 'Course 5', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 6', weeks: '8 weeks', courses: [{ label: 'Course 6', type: 'elective', subtype: 'Elective' }]},
{ name: 'Block 7', weeks: '8 weeks', courses: [{ label: 'Course 7', type: 'elective', subtype: 'Elective' }]}
]
}
},
masters: {
label: "Master's (MSc)",
credits: 36,
fullDuration: '56 weeks',
partDuration: '96 weeks',
terms: {
full: [
{ name: 'Block 1', weeks: '8 weeks', courses: [
{ label: 'Course 1', type: 'core', subtype: 'Core course' },
{ label: 'Course 2', type: 'core', subtype: 'Core course' }
]},
{ name: 'Block 2', weeks: '8 weeks', courses: [
{ label: 'Course 3', type: 'core', subtype: 'Core course' },
{ label: 'Course 4', type: 'core', subtype: 'Core course' }
]},
{ name: 'Block 3', weeks: '8 weeks', courses: [
{ label: 'Course 5', type: 'core', subtype: 'Core course' },
{ label: 'Course 6', type: 'elective', subtype: 'Elective' }
]},
{ name: 'Block 4', weeks: '8 weeks', courses: [
{ label: 'Course 7', type: 'elective', subtype: 'Elective' },
{ label: 'Course 8', type: 'elective', subtype: 'Elective' }
]},
{ name: 'Block 5', weeks: '8 weeks', courses: [
{ label: 'Course 9', type: 'research', subtype: 'Research Methods' },
{ label: 'Course 10', type: 'elective', subtype: 'Elective' }
]},
{ name: 'Final Project', weeks: '16 weeks', courses: [
{ label: 'Course 11', type: 'project', subtype: 'Final Project' }
]}
],
part: [
{ name: 'Block 1', weeks: '8 weeks', courses: [{ label: 'Course 1', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 2', weeks: '8 weeks', courses: [{ label: 'Course 2', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 3', weeks: '8 weeks', courses: [{ label: 'Course 3', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 4', weeks: '8 weeks', courses: [{ label: 'Course 4', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 5', weeks: '8 weeks', courses: [{ label: 'Course 5', type: 'core', subtype: 'Core course' }]},
{ name: 'Block 6', weeks: '8 weeks', courses: [{ label: 'Course 6', type: 'elective', subtype: 'Elective' }]},
{ name: 'Block 7', weeks: '8 weeks', courses: [{ label: 'Course 7', type: 'elective', subtype: 'Elective' }]},
{ name: 'Block 8', weeks: '8 weeks', courses: [{ label: 'Course 8', type: 'elective', subtype: 'Elective' }]},
{ name: 'Block 9', weeks: '8 weeks', courses: [{ label: 'Course 9', type: 'research', subtype: 'Research Methods' }]},
{ name: 'Block 10', weeks: '8 weeks', courses: [{ label: 'Course 10', type: 'elective', subtype: 'Elective' }]},
{ name: 'Final Project', weeks: '16 weeks', courses: [{ label: 'Course 11', type: 'project', subtype: 'Final Project' }]}
]
}
}
};
const modeEl = document.getElementById('mode');
const awardEl = document.getElementById('award');
const entryEl = document.getElementById('entry');
const chipsEl = document.getElementById('chips');
const pathSubEl = document.getElementById('pathSub');
const summaryGridEl = document.getElementById('summaryGrid');
const timelineEl = document.getElementById('timeline');
const milestonesEl = document.getElementById('milestones');
const helperTextEl = document.getElementById('helperText');
const footerNoteEl = document.getElementById('footerNote');
function getEntryOptionsForAward(award) {
if (award === 'certificate') return ['start'];
if (award === 'diploma') return ['start', 'certificate_done'];
return ['start', 'certificate_done', 'diploma_done'];
}
function syncEntryOptions() {
const award = awardEl.value;
const allowed = getEntryOptionsForAward(award);
Array.from(entryEl.options).forEach(opt => {
opt.hidden = !allowed.includes(opt.value);
});
if (!allowed.includes(entryEl.value)) entryEl.value = allowed[0];
}
function getFilteredTerms(award, entry, mode) {
const allTerms = data[award].terms[mode];
if (award === 'certificate') return allTerms;
if (award === 'diploma' && entry === 'certificate_done') {
return allTerms.filter(term => !term.courses.some(c => ['Course 1','Course 2','Course 3','Course 4'].includes(c.label)));
}
if (award === 'masters') {
if (entry === 'certificate_done') {
return allTerms.filter(term => !term.courses.some(c => ['Course 1','Course 2','Course 3','Course 4'].includes(c.label)));
}
if (entry === 'diploma_done') {
if (mode === 'full') {
return [
{ name: 'Block 5', weeks: '8 weeks', courses: [
{ label: 'Course 8', type: 'elective', subtype: 'Elective' },
{ label: 'Course 9', type: 'research', subtype: 'Research Methods' }
]},
{ name: 'Block 6', weeks: '8 weeks', courses: [
{ label: 'Course 10', type: 'elective', subtype: 'Elective' }
]},
{ name: 'Final Project', weeks: '16 weeks', courses: [
{ label: 'Course 11', type: 'project', subtype: 'Final Project' }
]}
];
}
return allTerms.filter(term => !term.courses.some(c => ['Course 1','Course 2','Course 3','Course 4','Course 5','Course 6','Course 7'].includes(c.label)));
}
}
return allTerms;
}
function getEstimatedDuration(termCount, award, mode, entry) {
const terms = getFilteredTerms(award, entry, mode);
const weeks = terms.reduce((sum, term) => sum + parseInt(term.weeks, 10), 0);
return `${weeks} learning weeks`;
}
function render() {
syncEntryOptions();
const mode = modeEl.value;
const award = awardEl.value;
const entry = entryEl.value;
const awardData = data[award];
const terms = getFilteredTerms(award, entry, mode);
const totalCourses = terms.flatMap(t => t.courses).length;
const duration = getEstimatedDuration(terms.length, award, mode, entry);
const perBlock = mode === 'full' ? '2 courses simultaneously' : '1 course at a time';
const entryLabelMap = {
start: 'Starting from the beginning',
certificate_done: 'Certificate already completed',
diploma_done: 'Diploma already completed'
};
chipsEl.innerHTML = `
<span class="chip mode">${mode === 'full' ? 'Full-time' : 'Part-time'}</span>
<span class="chip award">${awardData.label}</span>
<span class="chip entry">${entryLabelMap[entry]}</span>
`;
pathSubEl.textContent = `${awardData.label} · recommended sequence through each 8 weeks learning cycle`;
summaryGridEl.innerHTML = `
<div class="metric"><div class="metric-label">Estimated duration</div><div class="metric-value">${duration}</div></div>
<div class="metric"><div class="metric-label">Credits</div><div class="metric-value">${awardData.credits}</div></div>
<div class="metric"><div class="metric-label">Course progress</div><div class="metric-value">${perBlock}</div></div>
<div class="metric"><div class="metric-label">Courses to complete</div><div class="metric-value">${totalCourses}</div></div>
`;
timelineEl.innerHTML = terms.map((term, index) => `
<section class="term">
<div class="term-meta">
<div class="term-kicker">Step ${index + 1}</div>
<div class="term-name">${term.name}</div>
<div class="term-desc">${term.weeks} · Access ${term.courses.length} course${term.courses.length > 1 ? 's' : ''}</div>
</div>
<div class="course-grid">
${term.courses.map(course => `
<article class="course-card ${course.type}">
<div>
<div class="course-top">${course.subtype}</div>
<div class="course-name">${course.label}</div>
</div>
<div class="course-meta">${term.weeks}</div>
</article>
`).join('')}
</div>
</section>
`).join('');
const certificateDone = ['diploma', 'masters'].includes(award) || entry === 'certificate_done' || entry === 'diploma_done';
const diplomaDone = award === 'masters' || entry === 'diploma_done';
const masterUnlocked = award === 'masters';
milestonesEl.innerHTML = `
<div class="milestone">
<h3>Certificate milestone</h3>
<p>Complete Courses 1-4 before progressing to the diploma stage.</p>
</div>
<div class="milestone">
<h3>Diploma milestone</h3>
<p>Continue with Courses 5-7 before moving to the master’s schedule.</p>
</div>
<div class="milestone">
<h3>Master's milestone</h3>
<p>Complete Courses 8-10. Course 11 is the final project and is taken after the earlier master's courses are completed.</p>
</div>
`;
helperTextEl.textContent = award === 'masters'
? 'This view emphasises progression: certificate first, then diploma, then the full master\'s sequence.'
: award === 'diploma'
? 'This view helps learners see the full diploma journey and where the certificate stage fits within it.'
: 'This view gives prospective students a simple first-step path into the programme.';
footerNoteEl.textContent = mode === 'full'
? 'Drupal implementation note: this prototype works well as a single embedded HTML block or a custom Drupal block with inline CSS/JS. The visual cards reduce text load and make the next registration step immediately visible.'
: 'Accessibility note: the card layout, plain-language labels, and progressive sequencing support mobile users and reduce cognitive load for part-time learners planning one course at a time.';
}
document.getElementById('generateBtn').addEventListener('click', render);
document.getElementById('resetBtn').addEventListener('click', () => {
modeEl.value = 'full';
awardEl.value = 'certificate';
entryEl.value = 'start';
render();
});
awardEl.addEventListener('change', render);
modeEl.addEventListener('change', render);
entryEl.addEventListener('change', render);
render();
</script>
</body>
</html>
