docs(prd): learner-first mobile app PRD and interactive prototypes (#916)

* docs(prd): add learner-first mobile app PRD and interactive prototypes

Draft the ClassroomIO iOS/Android companion as a learner-first product
(attention home, compliance wallet, offline content, push on top of
prd/notification-system) with clickable HTML prototypes as the UX source
of truth.

Co-authored-by: Rotimi Best <[email protected]>

* style(prd): quiet mobile app prototype colours to match @cio/ui

Replace filled red/orange/green surfaces with the dashboard Badge and Alert recipes: 10% tint chips, card-background alerts, and default rows. Keep destructive fills only for actual destroy actions.

Co-authored-by: Rotimi Best <[email protected]>

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
Rotimi Best
2026-08-18 12:02:35 +01:00
committed by GitHub
co-authored by Rotimi Best Cursor Agent
parent 368a7fe5ae
commit 967e81d33f
20 changed files with 6327 additions and 0 deletions
+284
View File
@@ -0,0 +1,284 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Course detail — ClassroomIO Mobile</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:[email protected]&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="app-theme.css" />
<script>
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
document.documentElement.classList.add('dark');
</script>
</head>
<body>
<header class="proto-head">
<a class="back" href="index.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" width="14" height="14"><path d="m15 18-6-6 6-6"/></svg> All screens</a>
<span class="eyebrow">Learner · Course</span>
<h1>Course detail &amp; outline</h1>
<p>
Sections and lessons with an explicit state on every row: complete, current, locked (with the reason spelled out),
or downloaded. Compliance courses carry a deadline banner. Download is a whole-course action from the header,
sized before it starts and Wi-Fi-only by default.
</p>
<div class="proto-links">
<a href="lesson.html">Open lesson →</a>
<a href="exercise.html">Knowledge check →</a>
<a href="certificates.html">Certificate →</a>
<a href="learn.html">← Learn</a>
</div>
</header>
<div class="stage">
<!-- 1. OUTLINE -->
<figure class="device">
<div class="phone">
<div class="phone-inner">
<div class="notch"></div>
<div class="statusbar" data-status="9:44"></div>
<div class="navbar">
<a class="icon-btn plain" href="learn.html" aria-label="Back"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m15 18-6-6 6-6"/></svg></a>
<div class="grow"><div class="title-sm">Forklift Safety Recertification</div></div>
<button class="icon-btn" data-sheet-open="dl" aria-label="Download course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 15V3M7 10l5 5 5-5"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/></svg></button>
<button class="icon-btn" aria-label="More"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg></button>
</div>
<div class="tabs" data-select>
<button class="on" data-option>Content</button>
<button data-option>Compliance</button>
<button data-option>Newsfeed</button>
<button data-option>Community</button>
<button data-option>Certificate</button>
</div>
<div class="screen">
<div class="banner banner-danger" style="margin: 12px 0 12px">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 9v4M12 17h.01"/><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0"/></svg>
<div class="grow">
<div class="bt">Overdue by 3 days</div>
<div class="bd">Grace period ends 24 Aug. After that your forklift authorization is suspended.</div>
</div>
</div>
<div class="card card-pad" style="margin-bottom: 6px">
<div class="row">
<div class="ring lg">
<svg viewBox="0 0 36 36"><circle class="track" cx="18" cy="18" r="15.5" fill="none" stroke-width="3"/><circle class="arc primary" cx="18" cy="18" r="15.5" fill="none" stroke-width="3" stroke-linecap="round" stroke-dasharray="97.4" stroke-dashoffset="65.3"/></svg>
<span class="lbl tnum">33%</span>
</div>
<div class="grow">
<div class="lmeta" style="margin: 0"><span>4 of 12 lessons</span></div>
<div class="lmeta"><span>~28 min remaining</span></div>
<div class="lmeta"><span class="badge badge-success-soft">Downloaded · 84 MB</span></div>
</div>
</div>
<a class="btn btn-primary btn-block" href="lesson.html" style="margin-top: 12px">
<svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>
Continue lesson 4
</a>
</div>
<div class="sec-head"><h2>Section 1 · Before you drive</h2><span class="count">3/3</span></div>
<div class="stack stack-sm">
<a class="lrow flat done" href="lesson.html">
<div class="media is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div>
<div class="grow"><div class="ltitle">Why recertification matters</div><div class="lmeta"><span>Video · 4 min</span></div></div>
</a>
<a class="lrow flat done" href="lesson.html">
<div class="media is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div>
<div class="grow"><div class="ltitle">Site rules and exclusion zones</div><div class="lmeta"><span>Reading · 5 min</span></div></div>
</a>
<a class="lrow flat done" href="exercise.html">
<div class="media is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div>
<div class="grow"><div class="ltitle">Section 1 check</div><div class="lmeta"><span class="badge badge-success-soft">9/10</span></div></div>
</a>
</div>
<div class="sec-head"><h2>Section 2 · Inspection</h2><span class="count">1/4</span></div>
<div class="stack stack-sm">
<a class="lrow current" href="lesson.html" style="padding: 12px 14px">
<div class="media is-current"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg></div>
<div class="grow">
<div class="ltitle">Pre-operation inspection checklist</div>
<div class="lmeta"><span>Video · 9 min</span><span class="sep">·</span><span class="text-primary" style="font-weight: 600">6 min left</span></div>
</div>
<span class="dl-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span>
</a>
<a class="lrow flat" href="lesson.html">
<div class="media"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M8 5v14l11-7z"/></svg></div>
<div class="grow"><div class="ltitle">Load stability and centre of gravity</div><div class="lmeta"><span>Video · 7 min</span></div></div>
<span class="dl-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span>
</a>
<div class="lrow flat locked">
<div class="media"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
<div class="grow">
<div class="ltitle">Hydraulics walkthrough</div>
<div class="lmeta"><span>Complete "Load stability" to unlock</span></div>
</div>
</div>
<div class="lrow flat locked">
<div class="media"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
<div class="grow">
<div class="ltitle">Section 2 check</div>
<div class="lmeta"><span>Complete all lessons in this section</span></div>
</div>
</div>
</div>
<div class="sec-head"><h2>Section 3 · Assessment</h2><span class="count">0/5</span></div>
<div class="lrow flat locked">
<div class="media"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg></div>
<div class="grow">
<div class="ltitle">5 items locked</div>
<div class="lmeta"><span>Finish Section 2 to unlock the assessment</span></div>
</div>
</div>
</div>
<div class="home-bar"></div>
</div>
</div>
<figcaption><b>Outline</b>Every row states its own condition. Locked items name the prerequisite instead of just greying out — and the API enforces the same rule.</figcaption>
</figure>
<!-- 2. DOWNLOAD SHEET -->
<figure class="device">
<div class="phone">
<div class="phone-inner">
<div class="notch"></div>
<div class="statusbar" data-status="9:45"></div>
<div class="navbar">
<a class="icon-btn plain" href="learn.html" aria-label="Back"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m15 18-6-6 6-6"/></svg></a>
<div class="grow"><div class="title-sm">Warehouse Fire Safety</div></div>
<button class="icon-btn" aria-label="Download course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 15V3M7 10l5 5 5-5"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/></svg></button>
</div>
<div class="tabs">
<button class="on">Content</button>
<button>Compliance</button>
<button>Newsfeed</button>
<button>Community</button>
</div>
<div class="screen">
<div class="banner banner-warning" style="margin: 12px 0">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
<div class="grow"><div class="bt">Due in 6 days</div><div class="bd">Required for all warehouse staff</div></div>
</div>
<div class="stack stack-sm" style="opacity: 0.5">
<div class="lrow flat done"><div class="media is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div><div class="grow"><div class="ltitle">Fire triangle basics</div></div></div>
<div class="lrow flat done"><div class="media is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div><div class="grow"><div class="ltitle">Extinguisher classes</div></div></div>
<div class="lrow flat"><div class="media"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M8 5v14l11-7z"/></svg></div><div class="grow"><div class="ltitle">Evacuation routes</div></div></div>
</div>
</div>
<div class="scrim"></div>
<div class="sheet" style="display: flex">
<div class="grabber"></div>
<div class="sheet-head">
<div class="st">Download this course</div>
<button class="icon-btn plain" style="margin-left: auto" aria-label="Close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
</div>
<div class="sheet-body">
<div class="card card-pad" style="margin-bottom: 12px">
<div class="kv"><span class="k">8 lessons · video, PDFs, transcripts</span><span class="v tnum">112 MB</span></div>
<div class="kv"><span class="k">Free space on this device</span><span class="v tnum">3.4 GB</span></div>
<div class="kv"><span class="k">Connection</span><span class="v">Wi-Fi</span></div>
</div>
<div class="lrow" style="margin-bottom: 8px">
<div class="grow">
<div class="ltitle">Download over Wi-Fi only</div>
<div class="lsub">Avoids using your mobile data</div>
</div>
<label class="switch"><input type="checkbox" checked /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="banner banner-muted" style="margin-bottom: 14px">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
<div class="bd" style="color: var(--muted-foreground)">
Lessons, video, and transcripts work offline. The knowledge check still needs a connection to submit.
</div>
</div>
<button class="btn btn-primary btn-lg btn-block">Download 112 MB</button>
<button class="btn btn-ghost btn-block" style="margin-top: 6px">Not now</button>
</div>
</div>
<div class="home-bar"></div>
</div>
</div>
<figcaption><b>Download sheet</b>Size, free space, and connection shown before committing, with the offline limits stated up front rather than discovered on a plane.</figcaption>
</figure>
<!-- 3. COMPLETED -->
<figure class="device">
<div class="phone">
<div class="phone-inner">
<div class="notch"></div>
<div class="statusbar" data-status="10:02"></div>
<div class="navbar">
<a class="icon-btn plain" href="learn.html" aria-label="Back"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m15 18-6-6 6-6"/></svg></a>
<div class="grow"><div class="title-sm">Data Protection &amp; GDPR Essentials</div></div>
<button class="icon-btn" aria-label="Share"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/><path d="m16 6-4-4-4 4M12 2v13"/></svg></button>
</div>
<div class="screen">
<div class="card card-pad" style="margin: 14px 0 12px">
<div class="row row-top">
<div class="media lg is-done">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>
</div>
<div class="grow">
<div class="ltitle">Course complete</div>
<div class="lmeta"><span class="badge badge-success-soft">Finished 16 Aug 2026</span><span>Final score 92%</span></div>
</div>
</div>
<a class="btn btn-primary btn-block" href="certificates.html" style="margin-top: 14px">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="8" r="6"/><path d="M15.5 13.5 17 22l-5-3-5 3 1.5-8.5"/></svg>
View your certificate
</a>
</div>
<div class="card card-pad" style="margin-bottom: 12px">
<div class="kv"><span class="k">Lessons completed</span><span class="v tnum">10 / 10</span></div>
<div class="kv"><span class="k">Exercises passed</span><span class="v tnum">3 / 3</span></div>
<div class="kv"><span class="k">Time spent</span><span class="v">1h 12m</span></div>
<div class="kv"><span class="k">Certificate ID</span><span class="v tnum" style="font-size: 12.5px">CIO-GDPR-4F91-2026</span></div>
</div>
<div class="sec-head"><h2>Keep the content</h2></div>
<div class="lrow">
<div class="media is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 15V3M7 10l5 5 5-5"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/></svg></div>
<div class="grow">
<div class="ltitle">Downloaded · 96 MB</div>
<div class="lsub">Review offline any time, or free the space</div>
</div>
<button class="btn btn-outline btn-sm">Remove</button>
</div>
<div class="sec-head"><h2>Recommended next</h2></div>
<a class="lrow" href="course.html">
<div class="media"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg></div>
<div class="grow">
<div class="ltitle">Handling a Data Subject Request</div>
<div class="lmeta"><span>4 lessons</span><span class="sep">·</span><span>~18 min</span></div>
</div>
<span class="chev"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m9 18 6-6-6-6"/></svg></span>
</a>
</div>
<div class="home-bar"></div>
</div>
</div>
<figcaption><b>Completed</b>Certificate issuance is the payoff, and the download stays until the learner removes it.</figcaption>
</figure>
</div>
<button class="theme-toggle" title="Toggle theme" aria-label="Toggle theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
</button>
<script src="proto.js"></script>
</body>
</html>