docs(prd): add learning paths PRD with end-to-end HTML prototypes

Full spec for ordered, sequentially unlocked, bundle-priced learning
paths, plus 16 clickable prototypes (public org site, learner LMS, and
teacher workspace) built on the packages/ui tokens and the minimal
org-landing theme. The prototypes are the UX source of truth; start at
prototypes/learning-paths/index.html. Also adds the write-prd skill
codifying the clarify -> write -> prototype workflow.
This commit is contained in:
Rotimi Best
2026-08-06 07:35:10 +01:00
parent a83e172e6d
commit 2a82abfa21
20 changed files with 5630 additions and 0 deletions
+277
View File
@@ -0,0 +1,277 @@
# Learning Paths PRD
## Status
- Draft (prototyped, ready for engineering review)
## Prototypes — the UX source of truth
**The UX of this feature must be taken from the prototype folder.** Interactive HTML prototypes for every surface live in [`prototypes/learning-paths/`](../../prototypes/learning-paths/) and are the approved design reference for layout, states (done / in progress / locked), copy, and navigation flow. When this document and a prototype disagree on a UI detail, the prototype wins.
**Start here:**
```
prototypes/learning-paths/index.html
```
Open it in a browser (`open prototypes/learning-paths/index.html`) — it maps all three journeys (visitor → learner → teacher) and every page cross-links so you can click through each flow end to end. Each page has a light/dark toggle.
The prototypes are built on the real design tokens (`packages/ui/src/index.css` for app pages via `app-theme.css`, the `minimal` org-landing theme for public pages via `landing-theme.css`) and encode every decision below.
| Surface | Files |
| --- | --- |
| Public (org site) | `org-landing.html`, `public-paths.html`, `public-path.html` |
| Learner (LMS) | `lms-home.html`, `paths.html`, `path-detail.html`, `course-in-path.html` |
| Teacher (admin) | `teacher-paths.html`, `teacher-path-setup.html`, `teacher-path-builder.html`, `teacher-path-people.html`, `teacher-path-analytics.html`, `teacher-path-landing-editor.html`, `teacher-path-certificate.html`, `teacher-path-settings.html` |
## Purpose
Let orgs package multiple courses into an **ordered, sequentially unlocked, bundle-priced learning path** that is sold on the org's public site, completed step-by-step in the LMS, and finished with an optional path certificate. Reference experience: Coursera Professional Certificates (e.g. IBM Data Science).
## Problem Statement
- Courses can only be sold and taken individually; there is no way to sell a curriculum as one product with one price.
- Programs (shipped) group courses for cohort admin purposes but are explicitly **unordered**, have no gating, no public page, no pricing, and no path-level certificate.
- Instructors who run structured curricula cannot enforce prerequisites ("finish JS before React").
- The org landing page has no product above the individual course, so multi-course offerings are invisible to visitors.
## Confirmed Decisions
1. **New entity, separate from Programs.** `learning_path` is its own table set. Programs remain unchanged (cohort hub + newsfeed). No migration.
2. **Terminology**: "Learning Path" everywhere (admin, LMS, public site).
3. **Self-enrollment with bundle pricing.** A path is public on the org landing site with one price. Enrolling (buy or free) auto-enrolls the learner in every course in the path.
4. **Show savings.** The public page shows the bundle price against the summed individual course prices ("$199 ~~$280~~ · Save $81 (29%)"). Toggleable per path.
5. **Unlock rule = lessons + exercises.** Course N+1 unlocks when course N has every lesson complete AND every exercise submitted/passed. Sequential unlocking is a per-path toggle (off = take in any order).
6. **Path certificate is a teacher toggle** with its own admin tab; issued automatically on full completion; appears in the learner's LMS Certificates page.
7. **Teacher workspace tabs**: Courses (ordering), People, Analytics, Landing page, Certificate, Settings. **No path newsfeed** (Programs covers cohort communication).
8. **Visitor access is teacher-configurable**: teaser only / full syllabus / syllabus + preview lessons.
9. **Public path page follows the Coursera professional-certificate shape**: hero with stats + enroll CTA, what-you'll-learn, skills tags, sequential course cards with per-course outcomes and lesson outlines, certificate block, instructors, testimonials, FAQ accordion, pricing card.
10. **Org landing page: Learning Paths section sits ABOVE the Courses section.** Plus a `/paths` catalog page and `/path/[slug]` detail page mirroring how `/courses` and `/course/[slug]` work today.
11. **Course independence**: a course can be in multiple paths and remain individually sellable. Removing a course from a path or a learner from a path never deletes `groupmember` rows or progress.
12. **Statuses**: `ACTIVE` (public + LMS), `DRAFT` (hidden while building), `ARCHIVED` (hidden everywhere, restorable).
## Current-State Audit
| Capability | Current state | Notes |
| --- | --- | --- |
| Grouping above course | `program` tables (unordered, admin-enrolled, newsfeed) | Keep as-is; do not extend |
| Enrollment | `groupmember` per course group; `enrollInCourse()` in `apps/api/src/services/course/invite.ts` | Reuse for auto-enrollment |
| Course completion | lesson completion + exercise submissions tracked per course | Source data for the unlock rule |
| Public org site | `(org-site)` routes + `packages/ui/src/custom/org-landing-page/` (10 themes, default `minimal`) | Mirror for paths section/list/detail |
| Course landing page | theme `course.svelte` composer: hero → anchor nav → social proof → info blocks → curriculum → chips → instructor → reviews → pricing | Path page reuses these shared components where possible |
| Payments | course payment flow on paid enroll CTA (`course-landing-page.svelte`) | Path enroll reuses the same flow with the path as the product |
| Certificates | course certificate system + LMS Certificates page | Add path-level issuance |
| Setup checklist pattern | `routes/(app)/org/[slug]/setup/+page.svelte` + `PercentRingProgress` + `Item.*` | Reuse for "Set up your path" and learner checklist view |
## Product Goals
1. A visitor can discover a path on the org landing page, read a full Coursera-style path page, and self-enroll (paid or free).
2. Enrolling in a path creates path membership and `groupmember` rows for every course in it.
3. A learner sees paths in the LMS (home section + Learning Paths nav), opens a path hub with per-course progress and locked/unlocked states, and moves through courses in order.
4. Inside a course that belongs to a path, the learner sees path context (position stepper, "next course unlocks when…").
5. Teachers create a path via a setup checklist, order courses by drag, price the bundle, customize the public page, configure the certificate, and track a per-course funnel.
6. Completing all courses issues the path certificate (when enabled).
7. Programs, standalone courses, and existing enrollments are untouched (zero regression).
## Non-Goals (v1)
- Branching / non-linear paths (graphs, optional courses, parallel tracks).
- Path-level newsfeed or community.
- Subscriptions or installment pricing; coupon codes beyond what courses support.
- Path templates, cloning, or cross-org sharing.
- Per-learner overrides of the unlock rule (admin "skip ahead" can be a fast-follow).
- Team/B2B seat purchasing.
---
## Functional Requirements
### 1. Public — org landing site
**Landing page section** (above Courses; see `org-landing.html`):
- Section heading "Learning Paths" + lead line; grid of path cards.
- Path card: "Learning Path" chip, name, description, ordered course preview list (first 3 + "+N more"), meta row (course count, total hours, certificate), bundle price with struck-through sum.
- "View all learning paths" → `/paths`.
- Rendered per landing-page theme like the courses section (start with `minimal`; other themes can fall back to base styling).
**Catalog page `/paths`** (see `public-paths.html`): compact hero with search, filter sidebar (topic/tags, pricing, length), path card list, pagination. Mirrors `(org-site)/courses`.
**Detail page `/path/[slug]`** (see `public-path.html`), section order:
1. Hero: chip, headline, subheadline (teacher-editable), instructor avatar stack, Enroll CTA with price + savings chip, sticky enroll box (price, savings, feature list, CTA, enrolled/rating counts).
2. Stats row: courses, total hours, level, rating.
3. Sticky anchor nav: About / Courses / Certificate / Instructors / Testimonials / FAQ.
4. What you'll learn (outcome bullets) + Skills tags.
5. Course series: one card per course in order — number, title, lesson count + duration, per-course outcome bullets, expandable lesson outline (lessons marked preview are openable when the teacher allows).
6. Certificate block (when enabled).
7. Instructors (auto-derived from course tutors, hideable).
8. Testimonials (teacher-managed, hideable).
9. FAQ accordion (teacher-managed, hideable).
10. Pricing card + footer.
- Enroll: free path → enroll flow like `/course/{slug}/enroll`; paid path → payment flow with the path as product. Requires auth like course enrollment.
- Visitor access level (teaser / syllabus / syllabus+preview) gates sections 5's lesson detail.
- JSON-LD `Course`/`LearningResource` schema like the course page.
### 2. Learner — LMS
**Home** (`lms-home.html`): "Learning Paths" section above Courses when `enrolledPaths.length > 0`; path cards show segmented per-course progress (one segment per course: done/current/locked) + overall %, and "Next: {course}". Course cards belonging to a path carry a "{path} · i/N" chip.
**Nav**: "Learning Paths" item in the LMS sidebar with enrolled count badge, shown only when enrolled in ≥1 path.
**List `/lms/paths`** (`paths.html`): tabs In progress / Completed / All; rows with segment bar, next course, Continue / View certificate.
**Path hub `/lms/paths/[id]`** (`path-detail.html`): the journey spine — a vertical rail of course nodes that fills as courses complete. Per course: state (Completed / In progress / Locked), progress bar, lesson+exercise counts, unlock note ("Unlocks after Course N"), certificate end-row.
**Course in path** (`course-in-path.html`): when the visited course belongs to a path the learner is in, wrap the course view with a path ribbon — back pill to the path, "Course 3 of 5", overall path %, horizontal stepper (done/current/locked) — and a "Next in your path" callout under the lesson showing what completing this course unlocks.
**Unlock enforcement**: locked courses are not openable from path surfaces; direct navigation to a locked course (URL) shows a "locked — finish {course} first" state. Learners enrolled in a course independently (outside the path) keep their normal access.
### 3. Teacher — admin dashboard
**Org listing `/org/[slug]/paths`** (`teacher-paths.html`): nav item "Learning Paths" after Courses; stat cards (active paths, enrolled learners, completions); table (name, courses, learners, status); Create path → creation modal → setup checklist.
**Setup checklist `/paths/[id]/setup`** (`teacher-path-setup.html`): Get Started pattern (ring + dots + item rows): name/describe ✓ auto, add courses, set order, set price, customize landing page, activate. Each step deep-links to its tab. Shown until complete; "Finish setup · N%" chip in the workspace top bar.
**Path workspace `/paths/[id]/*`** — course-style sidebar (back link, path identity + status, tabs):
| Tab | File | Contents |
| --- | --- | --- |
| Courses | `teacher-path-builder.html` | "Unlock courses in order" toggle; drag-to-reorder course rows (order, thumb, lessons/exercises/price, open/remove); add-course picker (org courses not in path); certificate end-row. Remove-course confirmation notes nobody is unenrolled. |
| People | `teacher-path-people.html` | Auto-enroll info banner; search + progress filter; table: learner, path progress bar, current course, enrolled date, actions (view, remove — preserves course access). Add learners (batch email, like course invites). |
| Analytics | `teacher-path-analytics.html` | Stat cards (enrolled, active, completion rate, avg time); per-course funnel with drop-off callouts; "stuck" list (lessons/exercises blocking most learners). |
| Landing page | `teacher-path-landing-editor.html` | Hero headline/subheadline; visitor access radio (teaser / syllabus / syllabus+previews); what-you'll-learn bullets; skills tags; instructors toggle (auto from course tutors); testimonials CRUD + toggle; FAQ CRUD + toggle; "View live page". |
| Certificate | `teacher-path-certificate.html` | Award toggle; requirements summary (all lessons + all exercises); title + issuer fields; live preview; awarded count. |
| Settings | `teacher-path-settings.html` | General (name, description, cover); Pricing (bundle price, currency, show-savings toggle with computed sum); Enrollment & flow (self-enrollment toggle, unlock-in-order toggle, auto-enroll toggle); Status radio (Active / Draft / Archived); Danger zone (delete path — courses & progress preserved). |
### 4. Access control
- Org admins manage all paths; path-level TUTOR role can manage content but not delete (mirror Programs roles: ADMIN/TUTOR/STUDENT via `roleId`).
- Students: read path data they're members of; public endpoints serve ACTIVE paths only.
- DRAFT paths: admin/tutor only. ARCHIVED: hidden everywhere, data preserved.
---
## Technical Design
### Data model (`packages/db/src/schema.ts`)
```
learning_path
id uuid PK · organizationId FK(organization, cascade) · name varchar · slug varchar (unique per org)
description text · coverImage text · status LEARNING_PATH_STATUS default 'DRAFT'
cost numeric · currency varchar default 'USD' · showSavings boolean default true
sequentialUnlock boolean default true · selfEnrollment boolean default true · autoEnroll boolean default true
certificateEnabled boolean default true · certificateTitle text · certificateIssuer text
landingPage jsonb -- { headline, subheadline, visitorAccess: 'teaser'|'syllabus'|'preview',
-- outcomes: string[], skills: string[], showInstructors, testimonials: [...],
-- showTestimonials, faqs: [...], showFaqs }
visitorAccess is inside landingPage; no relational IDs inside the jsonb (per repo rule)
createdByProfileId FK(profile) · createdAt / updatedAt
learning_path_course
id uuid PK · pathId FK(learning_path, cascade) · courseId FK(course, cascade)
order integer NOT NULL -- 1-based position; the gating sequence
unique(pathId, courseId) · unique(pathId, order) · index(pathId)
learning_path_member
id uuid PK · pathId FK(learning_path, cascade) · profileId FK(profile) · roleId FK(role)
enrolledAt timestamptz · completedAt timestamptz nullable
certificateIssuedAt timestamptz nullable · certificateId varchar nullable
unique(pathId, profileId) · index(pathId) · index(profileId)
enum LEARNING_PATH_STATUS: ACTIVE | DRAFT | ARCHIVED
```
Notes:
- No denormalized progress on `learning_path_member` beyond `completedAt`; per-course progress is computed from existing lesson-completion + exercise-submission data (already queried for course cards).
- Savings figure is computed at read time from the sum of `course.cost` over path courses — never stored.
- Schema work stops at a passing `@cio/db` build; migrations are handled outside this workflow.
### Completion / unlock logic (service layer)
```
courseCompleteForPath(profileId, courseId):
lessonsComplete = completedLessons == totalLessons
exercisesComplete = submittedOrPassedExercises == totalExercises
return lessonsComplete && exercisesComplete
unlockedCourses(path, profileId):
if !path.sequentialUnlock → all
else → courses[0..k] where k = first index whose course is not complete
```
Path completion: all courses complete → set `completedAt`; if `certificateEnabled`, issue certificate (id `LP-XXXX-XXXX`), set `certificateIssuedAt`. Evaluate on lesson/exercise completion events for members of paths containing that course (reuse the pattern used by course-completion side effects).
### API routes (`apps/api/src/routes/learning-path/`)
Follow the standard layering (validation in `packages/utils/src/validation/learning-path/`, queries in `packages/db/src/queries/learning-path/`, services in `apps/api/src/services/learning-path/`). Mount as a single root segment: `.route('/learning-path', learningPathRouter)`.
| Method | Path | Auth | Description |
| --- | --- | --- | --- |
| GET | `/learning-path` | org admin | List org paths (admin) |
| POST | `/learning-path` | org admin | Create (name, description) → DRAFT |
| GET | `/learning-path/:pathId` | member/admin | Detail incl. ordered courses + caller progress |
| PUT | `/learning-path/:pathId` | admin/tutor | Update settings/pricing/landingPage/status |
| DELETE | `/learning-path/:pathId` | org admin | Delete (courses/progress preserved) |
| POST | `/learning-path/:pathId/courses` | admin/tutor | Add course (+ auto-enroll existing students) |
| PUT | `/learning-path/:pathId/courses/order` | admin/tutor | Reorder (array of courseIds) |
| DELETE | `/learning-path/:pathId/courses/:courseId` | admin/tutor | Remove (no unenrollment) |
| GET | `/learning-path/:pathId/members` | admin/tutor | Members + per-course progress |
| POST | `/learning-path/:pathId/members` | admin/tutor | Batch add (email+role) + auto-enroll |
| DELETE | `/learning-path/:pathId/members/:memberId` | admin/tutor | Remove (course access preserved) |
| GET | `/learning-path/:pathId/analytics` | admin/tutor | Funnel + stuck items |
| POST | `/learning-path/:pathId/enroll` | auth user | Self-enroll (free) / post-payment callback (paid) |
| GET | `/organization/learning-paths/enrolled` | auth user | LMS: caller's paths with progress + unlock states |
Public (org-site loaders, no auth): list ACTIVE paths for landing/catalog; get path by slug with landingPage content filtered by `visitorAccess`.
### Frontend plan (dashboard)
Follow CLAUDE.md conventions: types in `features/learning-path/utils/types.ts` inferred from the API, API classes in `features/learning-path/api/*.svelte.ts`, thin components, all copy in `en.json` under `"learningPath"`, `ui:` prefix for theme colors.
- **Admin**: nav item in `org-navigation.ts` after Courses; routes `org/[slug]/paths/+page.svelte` and `paths/[id]/{setup,courses,people,analytics,landing,certificate,settings}` with a `PathSidebar` mirroring the course sidebar pattern. Reuse `Item.*`, `PercentRingProgress`, `Field.*`, existing drag-reorder approach from lesson ordering if present.
- **LMS**: `lms/paths` + `lms/paths/[id]`; path ribbon injected in the course layout when course ∈ caller's path; reuse `course-progress-card` math for per-course %.
- **Public**: paths section added to org landing themes (start `minimal`), `(org-site)/paths` and `(org-site)/path/[slug]` mirroring the courses equivalents; reuse `CourseSectionNav`, `CourseSocialProof`, `CourseCurriculum`-style rows, `CoursePricing` card, `LandingButton`, footer.
### Build verification
```bash
pnpm --filter @cio/utils build && pnpm --filter @cio/db build && pnpm --filter @cio/api build
pnpm --filter @cio/dashboard^... build && pnpm --filter @cio/dashboard build
pnpm format:check
```
---
## Implementation Order
1. **Schema + validation + queries** (`learning_path*` tables, Zod schemas, query layer).
2. **API**: CRUD + course ordering + members + enroll service (auto-enroll transaction, `ON CONFLICT DO NOTHING` idempotency) + unlock/completion service + enrolled-paths endpoint.
3. **Admin UI**: listing → workspace shell + Courses tab → Settings → People → setup checklist → Landing editor → Certificate → Analytics.
4. **LMS**: enrolled section on home + nav, list, path hub (pick journey or checklist), course-in-path ribbon + lock enforcement.
5. **Public**: landing section (minimal theme) → catalog → detail page → enroll flow (free first, then paid via existing payment flow).
6. **Certificate issuance** + LMS Certificates page integration.
## Acceptance Criteria
1. Teacher can create a path, add + reorder courses, set a bundle price, and activate it; the setup checklist reflects real completion.
2. ACTIVE paths appear on the org landing page above courses, in `/paths`, and at `/path/[slug]` with all enabled sections; DRAFT/ARCHIVED paths do not.
3. Savings displays as bundle price vs summed course prices and updates when course prices change.
4. Visitor access level correctly gates lesson outlines/previews for non-enrolled visitors.
5. Enrolling (free or paid) creates the member row and `groupmember` rows for all path courses, idempotently.
6. With sequential unlock on, course N+1 is locked until course N's lessons AND exercises are complete — enforced in UI and API; toggle off restores free order.
7. Learner LMS shows path progress (segments + %), locked states, and the in-course path ribbon; direct URL access to a locked course is blocked with an explanatory state.
8. Completing all courses sets `completedAt` and (when enabled) issues the path certificate, visible in LMS Certificates.
9. Removing a course from a path or a member from a path never deletes course enrollments or progress.
10. Adding a course to a path with existing students auto-enrolls them in that course.
11. Analytics funnel counts match member course-completion data.
12. Programs and standalone courses behave exactly as before.
13. All user-facing strings use translation keys; all builds and `pnpm format:check` pass.
## Risks and Mitigations
- **Unlock-rule evaluation cost** (checked on every lesson/exercise completion): scope the check to paths containing that course with the learner as member; index `learning_path_course.courseId`.
- **Auto-enroll transaction size** for large paths/cohorts: batch inserts with `ON CONFLICT DO NOTHING`; >500 members → background job (same mitigation as Programs).
- **Price drift**: savings computed at read time, so course price changes are always reflected; if a course in an active path becomes free/pricier, surface a notice in the Settings pricing section.
- **Learner already enrolled in a member course independently**: idempotent enrollment; their existing progress counts toward the unlock rule immediately (decide: acceptable and desirable).
- **Locked-course deep links** shared between learners: API must enforce the lock (not just UI), returning a typed error the frontend renders as the locked state.
- **Landing theme sprawl** (10 themes): v1 ships the paths section/pages for the base + `minimal` theme with a neutral fallback for others, mirroring how course landing tokens are layered.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,304 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Course in Path · ClassroomIO LMS</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.shell { display: grid; grid-template-columns: 300px 1fr; min-height: 100vh; }
/* ============ COURSE SIDEBAR (matches app course content sidebar) ============ */
.csb { background: var(--sidebar); border-right: 1px solid var(--sidebar-border); display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; }
.csb-scroll { flex: 1; overflow-y: auto; padding: 12px; }
/* course identity block */
.course-id { display: flex; align-items: center; gap: 12px; padding: 12px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 7%, transparent); margin-bottom: 10px; }
.course-id .nm { font-size: 14px; font-weight: 600; color: var(--foreground); line-height: 1.3; }
.course-id .ct { font-size: 12px; color: var(--muted-foreground); margin-top: 1px; }
.back-path { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--primary); padding: 4px 12px 10px; }
.back-path svg { width: 14px; height: 14px; stroke-width: 2.2; }
/* Content header row */
.content-row { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 8%, transparent); color: var(--primary); font-size: 14px; font-weight: 600; margin-bottom: 6px; }
.content-row > svg { width: 16px; height: 16px; stroke-width: 2; }
.content-row .counts { margin-left: auto; display: flex; align-items: center; gap: 10px; font-size: 12px; font-weight: 600; }
.content-row .counts .c { display: flex; align-items: center; gap: 4px; }
.content-row .counts svg { width: 13px; height: 13px; stroke-width: 2; }
/* module section rows */
.module { display: flex; align-items: center; gap: 8px; padding: 7px 8px 7px 14px; font-size: 13.5px; font-weight: 500; color: var(--foreground); border-radius: var(--radius-md); cursor: pointer; }
.module:hover { background: var(--sidebar-accent); }
.module > svg:first-child { width: 15px; height: 15px; stroke-width: 2; color: var(--primary); flex-shrink: 0; }
.module .pct { margin-left: auto; font-size: 12px; color: var(--muted-foreground); font-weight: 500; }
.module .chev { width: 14px; height: 14px; stroke-width: 2; color: var(--muted-foreground); flex-shrink: 0; }
/* lesson rows */
.lessons { padding-left: 14px; }
.lesson { display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 10px; font-size: 13.5px; color: var(--foreground); border-radius: var(--radius-md); cursor: pointer; }
.lesson:hover { background: var(--sidebar-accent); }
.lesson > svg:first-child { width: 15px; height: 15px; stroke-width: 1.8; color: color-mix(in oklab, var(--primary) 70%, var(--muted-foreground)); flex-shrink: 0; }
.lesson .t { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.lesson.active { background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); font-weight: 500; }
.lesson.active > svg:first-child { color: var(--primary); }
.lesson .done-mark { width: 16px; height: 16px; border-radius: 999px; background: var(--foreground); color: var(--background); display: grid; place-items: center; flex-shrink: 0; }
.lesson .done-mark svg { width: 9px; height: 9px; stroke-width: 3.4; }
.lesson.locked { color: var(--muted-foreground); cursor: not-allowed; }
.lesson.locked > svg:first-child { color: var(--muted-foreground); }
.lesson .lock { width: 13px; height: 13px; stroke-width: 2; color: var(--muted-foreground); flex-shrink: 0; }
/* sidebar footer: progress card + powered by */
.csb-foot { padding: 12px; border-top: 1px solid var(--sidebar-border); }
.prog-card { background: color-mix(in oklab, var(--primary) 7%, transparent); border-radius: var(--radius-md); padding: 12px 14px; }
.prog-card .row { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
.prog-card .row .l { font-size: 13px; font-weight: 600; }
.prog-card .row .p { font-size: 13px; font-weight: 700; color: var(--primary); }
.prog-card .cap { font-size: 11.5px; color: var(--muted-foreground); margin-top: 8px; }
.powered { display: flex; align-items: center; justify-content: center; gap: 5px; font-size: 11.5px; color: var(--muted-foreground); padding: 12px 0 2px; }
.powered b { color: var(--foreground); font-weight: 600; }
/* ============ HEADER (matches app course header) ============ */
.chead { height: 52px; border-bottom: 1px solid var(--border); background: var(--background); position: sticky; top: 0; z-index: 100; display: flex; align-items: center; gap: 12px; padding: 0 20px; }
.panel-btn { width: 30px; height: 30px; border: none; background: transparent; border-radius: var(--radius-md); display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; }
.panel-btn:hover { background: var(--accent); color: var(--foreground); }
.panel-btn svg { width: 17px; height: 17px; stroke-width: 2; }
.chead .crumb { font-size: 14px; font-weight: 500; }
.chead .right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.chead .sep { width: 1px; height: 18px; background: var(--border); flex-shrink: 0; margin: 0 4px; }
/* path widget — tinted pill so it clearly reads as the learning path */
.path-widget {
display: inline-flex; align-items: center; gap: 10px;
padding: 4px 12px 4px 10px; border-radius: 999px;
background: color-mix(in oklab, var(--primary) 8%, transparent);
border: 1px solid color-mix(in oklab, var(--primary) 22%, transparent);
min-width: 0;
}
.path-widget:hover { border-color: color-mix(in oklab, var(--primary) 45%, transparent); }
.path-widget .pw-kind { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--primary); white-space: nowrap; }
.path-widget .pw-kind svg { width: 13px; height: 13px; stroke-width: 2.2; }
.mini-stepper { display: flex; align-items: center; gap: 0; min-width: 0; }
.ms-node { display: flex; align-items: center; }
.ms-dot { width: 22px; height: 22px; border-radius: 999px; display: grid; place-items: center; font-size: 10.5px; font-weight: 600; background: var(--muted); color: var(--muted-foreground); border: 1px solid var(--border); flex-shrink: 0; }
.ms-dot svg { width: 11px; height: 11px; stroke-width: 2.8; }
.ms-node.done .ms-dot { background: var(--success); border-color: var(--success); color: var(--success-foreground); }
.ms-node.current .ms-dot { background: var(--primary); border-color: var(--primary); color: var(--primary-foreground); }
.ms-bar { width: 22px; height: 2px; background: var(--border); flex-shrink: 0; }
.ms-bar.filled { background: var(--success); }
.ms-label { font-size: 12.5px; font-weight: 500; color: var(--foreground); margin-left: 8px; white-space: nowrap; }
@media (max-width: 760px) { .path-widget, .chead .sep { display: none; } }
/* ============ LESSON VIEW ============ */
.lesson-view { padding: 28px 32px 48px; min-width: 0; }
.lv-inner { max-width: 760px; }
.lv-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 22px; }
.lv-title { font-size: 26px; font-weight: 600; letter-spacing: -0.02em; margin: 0; flex: 1; min-width: 200px; }
.lv-actions { display: flex; align-items: center; gap: 8px; }
.pill-btn { display: inline-flex; align-items: center; gap: 7px; height: 34px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--input); background: var(--background); font-size: 13.5px; font-weight: 500; cursor: pointer; box-shadow: var(--shadow-2xs); }
.pill-btn:hover { background: var(--accent); }
.pill-btn svg { width: 15px; height: 15px; stroke-width: 2; }
.round-btn { width: 34px; height: 34px; border-radius: 999px; border: 1px solid var(--input); background: var(--background); display: grid; place-items: center; color: var(--foreground); cursor: pointer; box-shadow: var(--shadow-2xs); }
.round-btn:hover { background: var(--accent); }
.round-btn svg { width: 15px; height: 15px; stroke-width: 2; }
.lang { display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 12px; border-radius: var(--radius-md); border: 1px solid var(--input); background: var(--background); font-size: 13.5px; cursor: pointer; box-shadow: var(--shadow-2xs); }
.lang svg { width: 14px; height: 14px; stroke-width: 2; color: var(--muted-foreground); }
.lv-rule { border: none; border-top: 1px solid var(--border); margin: 0 0 20px; }
.video { aspect-ratio: 16 / 9; border-radius: var(--radius-xl); background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376)); display: grid; place-items: center; box-shadow: var(--shadow-sm); margin-bottom: 22px; }
.play { width: 56px; height: 56px; border-radius: 999px; background: oklch(1 0 0 / 0.92); display: grid; place-items: center; }
.play svg { width: 22px; height: 22px; color: var(--primary); margin-left: 3px; }
.lv-body p { margin: 0 0 14px; line-height: 1.65; font-size: 15px; }
.lv-body h3 { font-size: 16px; font-weight: 600; margin: 22px 0 8px; }
.lv-body ul { margin: 0 0 14px; padding-left: 20px; color: var(--muted-foreground); }
.lv-body li { margin-bottom: 5px; }
/* next in path callout */
.path-next { margin-top: 28px; overflow: hidden; }
.pn-head { display: flex; align-items: center; gap: 8px; padding: 10px 16px; background: color-mix(in oklab, var(--muted) 50%, transparent); border-bottom: 1px solid var(--border); font-size: 12px; font-weight: 500; color: var(--muted-foreground); letter-spacing: 0.04em; }
.pn-head svg { width: 14px; height: 14px; stroke-width: 2; color: var(--primary); }
.pn-body { padding: 14px 16px; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.pn-req { font-size: 12.5px; color: var(--muted-foreground); display: flex; align-items: center; gap: 6px; margin-top: 3px; }
.pn-req svg { width: 13px; height: 13px; stroke-width: 2; color: var(--warning); }
.pn-req b { color: var(--foreground); font-weight: 500; }
@media (max-width: 900px) { .shell { grid-template-columns: 1fr; } .csb { display: none; } .lesson-view { padding: 22px 18px 40px; } }
</style>
</head>
<body>
<div class="shell">
<!-- ============ SIDEBAR ============ -->
<aside class="csb">
<div class="csb-scroll">
<div class="course-id">
<div class="ring ring-sm" style="width: 42px; height: 42px">
<svg viewBox="0 0 100 100">
<circle class="track" cx="50" cy="50" r="45" fill="none" stroke-width="10" />
<circle class="arc" cx="50" cy="50" r="45" fill="none" stroke-width="10" stroke-linecap="round" stroke-dasharray="282.7" stroke-dashoffset="155.5" />
</svg>
<span class="lbl tnum" style="font-size: 10px">45%</span>
</div>
<div style="min-width: 0">
<div class="nm">Modern Web Development with React</div>
<div class="ct tnum">9 of 16 completed</div>
</div>
</div>
<a class="back-path" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>Frontend Engineering Bootcamp</a>
<div class="content-row">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg>
Content
<span class="counts">
<span class="c tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>12</span>
<span class="c tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>4</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 14px; height: 14px"><path d="m6 9 6 6 6-6"/></svg>
</span>
</div>
<!-- Module 1 -->
<div class="module">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
Fundamentals
<span class="pct tnum">100%</span>
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg>
</div>
<div class="lessons">
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">What is React?</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">JSX &amp; rendering</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Components &amp; props</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
</div>
<!-- Module 2 -->
<div class="module">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
Interactivity
<span class="pct tnum">38%</span>
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg>
</div>
<div class="lessons">
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">State with useState</span><span class="done-mark"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></div>
<div class="lesson active"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Handling events</span></div>
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Lists &amp; keys</span></div>
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Conditional rendering</span></div>
<div class="lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg><span class="t">Interactivity Checkpoint</span></div>
</div>
<!-- Module 3 (locked) -->
<div class="module">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
Effects &amp; Data
<span class="pct tnum">0%</span>
<svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg>
</div>
<div class="lessons">
<div class="lesson locked"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">The useEffect hook</span><svg class="lock" 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="lesson locked"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg><span class="t">Fetching data</span><svg class="lock" 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="lesson locked"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg><span class="t">Effects Checkpoint</span><svg class="lock" 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>
</div>
<div class="csb-foot">
<div class="prog-card">
<div class="row"><span class="l">Your progress</span><span class="p tnum">45%</span></div>
<div class="progress progress-thin"><span style="width: 45%"></span></div>
<div class="cap tnum">9 of 12 lessons · 2 of 4 exercises</div>
</div>
<div class="powered">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 13px; height: 13px; stroke-width: 2; color: var(--primary)"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Powered by <b>ClassroomIO</b>
</div>
</div>
</aside>
<!-- ============ MAIN ============ -->
<div style="display: flex; flex-direction: column; min-width: 0">
<!-- header -->
<header class="chead">
<button class="panel-btn" title="Toggle sidebar" aria-label="Toggle sidebar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 3v18"/></svg></button>
<span class="crumb">Content</span>
<span class="sep"></span>
<a class="path-widget" href="path-detail.html" title="Frontend Engineering Bootcamp — open path">
<span class="pw-kind"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
<div class="mini-stepper">
<span class="ms-node done" title="HTML &amp; CSS Foundations"><span class="ms-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></span>
<span class="ms-bar filled"></span>
<span class="ms-node done" title="JavaScript Essentials"><span class="ms-dot"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></span></span>
<span class="ms-bar filled"></span>
<span class="ms-node current" title="Modern Web Development with React"><span class="ms-dot tnum">3</span></span>
<span class="ms-bar"></span>
<span class="ms-node" title="State Management &amp; Data Fetching"><span class="ms-dot"><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></span></span>
<span class="ms-bar"></span>
<span class="ms-node" title="Building &amp; Shipping a Capstone"><span class="ms-dot"><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></span></span>
<span class="ms-label tnum">Course 3 of 5</span>
</div>
</a>
<div class="right">
<button class="icon-btn" id="theme" 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>
<button class="btn btn-primary btn-sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 3l1.9 5.8a2 2 0 0 0 1.3 1.3L21 12l-5.8 1.9a2 2 0 0 0-1.3 1.3L12 21l-1.9-5.8a2 2 0 0 0-1.3-1.3L3 12l5.8-1.9a2 2 0 0 0 1.3-1.3z"/></svg>Assistant</button>
</div>
</header>
<!-- lesson -->
<main class="lesson-view">
<div class="lv-inner">
<div class="lv-head">
<h1 class="lv-title">Handling events</h1>
<div class="lv-actions">
<button class="pill-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="m8.5 12 2.5 2.5 5-5"/></svg>Mark as Complete</button>
<button class="round-btn" title="Previous lesson" aria-label="Previous lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m15 18-6-6 6-6"/></svg></button>
<button class="round-btn" title="Next lesson" aria-label="Next lesson"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m9 18 6-6-6-6"/></svg></button>
<button class="lang">English<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
</div>
</div>
<hr class="lv-rule" />
<div class="video"><div class="play"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg></div></div>
<div class="lv-body">
<p>In React you respond to user interaction by passing event handlers as props to elements. Handlers are regular functions, and React normalizes the underlying browser event for you.</p>
<h3>What you'll learn</h3>
<ul>
<li>Attaching <code>onClick</code>, <code>onChange</code>, and <code>onSubmit</code> handlers</li>
<li>Reading values from the synthetic event object</li>
<li>Updating state in response to an event</li>
</ul>
<p>By the end of this lesson you'll wire up a small form that updates the screen as the user types — the foundation for everything interactive you'll build in this path.</p>
</div>
<div class="card path-next">
<div class="pn-head">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
NEXT IN YOUR PATH
</div>
<div class="pn-body">
<div class="item-media-icon item-media-lg"><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="item-content">
<span class="item-eyebrow">Course 4</span>
<span class="item-title">State Management &amp; Data Fetching</span>
<span class="pn-req">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>
Unlocks when you finish this course — <b>3 lessons &amp; 2 exercises</b> to go.
</span>
</div>
<span class="btn btn-outline btn-sm disabled"><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>Locked</span>
</div>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
+142
View File
@@ -0,0 +1,142 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Learning Paths — Prototype Map</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.page { max-width: 980px; margin: 0 auto; padding: 56px 24px 80px; }
h1 { font-size: 32px; font-weight: 600; letter-spacing: -0.03em; margin: 8px 0 8px; }
.lead { color: var(--muted-foreground); font-size: 15px; max-width: 70ch; margin: 0 0 12px; }
.eyebrow { font-size: 12px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--primary); }
.sec { font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted-foreground); margin: 36px 0 14px; display: flex; align-items: center; gap: 10px; }
.sec::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.shot { overflow: hidden; display: flex; flex-direction: column; transition: border-color 0.15s, box-shadow 0.15s; }
.shot:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
.shot .cover { height: 72px; display: grid; place-items: center; color: #fff; }
.shot .cover svg { width: 26px; height: 26px; stroke-width: 1.8; }
.shot .b { padding: 13px 15px 15px; }
.shot .n { font-size: 11px; font-weight: 600; color: var(--muted-foreground); letter-spacing: 0.05em; text-transform: uppercase; }
.shot .t { font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em; margin: 3px 0 4px; }
.shot .d { font-size: 12.5px; color: var(--muted-foreground); margin: 0; line-height: 1.5; }
.foot { margin-top: 44px; padding-top: 20px; border-top: 1px solid var(--border); color: var(--muted-foreground); font-size: 13.5px; line-height: 1.7; }
.foot b { color: var(--foreground); font-weight: 500; }
.foot code { background: var(--muted); padding: 1px 6px; border-radius: 4px; font-size: 12.5px; }
@media (max-width: 860px) { .grid { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="page">
<span class="eyebrow">ClassroomIO · Prototype + PRD handoff</span>
<h1>Learning Paths</h1>
<p class="lead">
A <b style="color: var(--foreground)">learning path</b> is an ordered bundle of courses sold and taken as one:
courses unlock sequentially (lessons + exercises complete → next course), one bundle price with savings,
and an optional path certificate at the end. Built on the real <code>packages/ui</code> tokens.
The engineering PRD lives at <code>prd/learning-paths/README.md</code>.
</p>
<p class="lead" style="font-size: 13.5px">Every page has a theme toggle and cross-links so you can click through each journey end to end.</p>
<!-- PUBLIC -->
<div class="sec">1 · Public — org landing site (visitor)</div>
<div class="grid">
<a class="card shot" href="org-landing.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
<div class="b"><div class="n">Entry</div><div class="t">Org Landing Page</div><p class="d">Learning Paths section above Courses — mirrors the "minimal" landing theme.</p></div>
</a>
<a class="card shot" href="public-paths.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.546 0.245 262.881), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
<div class="b"><div class="n">List</div><div class="t">Paths Catalog</div><p class="d">/paths — search, filters, and path cards with savings pricing (like /courses).</p></div>
</a>
<a class="card shot" href="public-path.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.424 0.199 265.638), oklch(0.546 0.245 262.881))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div class="b"><div class="n">Detail · Coursera-style</div><div class="t">Public Path Page</div><p class="d">Hero + enroll box with savings, stats, outcomes, skills, course series with lesson outlines, certificate, instructors, testimonials, FAQ.</p></div>
</a>
</div>
<!-- LEARNER -->
<div class="sec">2 · Learner — LMS (enrolled student)</div>
<div class="grid">
<a class="card shot" href="lms-home.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg></div>
<div class="b"><div class="n">Entry</div><div class="t">LMS Home</div><p class="d">Paths above courses, segmented cross-course progress bars.</p></div>
</a>
<a class="card shot" href="paths.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
<div class="b"><div class="n">List</div><div class="t">My Learning Paths</div><p class="d">In progress / Completed tabs; each row shows segment progress + next course.</p></div>
</a>
<a class="card shot" href="path-detail.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.696 0.17 162.48), oklch(0.596 0.145 163.225))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div class="b"><div class="n">Detail</div><div class="t">Path Detail</div><p class="d">The journey spine — Done / Continue / Locked courses with per-course progress and a certificate end-row.</p></div>
</a>
<a class="card shot" href="course-in-path.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg></div>
<div class="b"><div class="n">Inside a course</div><div class="t">Course in Path</div><p class="d">Lesson view wrapped in path chrome: stepper ribbon + "next course unlocks" callout.</p></div>
</a>
</div>
<!-- TEACHER -->
<div class="sec">3 · Teacher — admin dashboard</div>
<div class="grid">
<a class="card shot" href="teacher-paths.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.37 0.044 257.287), oklch(0.279 0.041 260.031))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
<div class="b"><div class="n">List</div><div class="t">Manage Paths</div><p class="d">Org-level listing: stats, statuses, Create path → setup checklist.</p></div>
</a>
<a class="card shot" href="teacher-path-setup.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></div>
<div class="b"><div class="n">Onboarding</div><div class="t">Set up your path</div><p class="d">"Get Started"-style checklist: courses → order → price → landing page → activate.</p></div>
</a>
<a class="card shot" href="teacher-path-builder.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.424 0.199 265.638))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></div>
<div class="b"><div class="n">Tab · Courses</div><div class="t">Path Builder</div><p class="d">Drag-to-reorder course list + sequential-unlock toggle. Try dragging rows.</p></div>
</a>
<a class="card shot" href="teacher-path-people.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.546 0.245 262.881), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg></div>
<div class="b"><div class="n">Tab · People</div><div class="t">Learners</div><p class="d">Per-learner path progress, current course, auto-enroll note, add learners.</p></div>
</a>
<a class="card shot" href="teacher-path-analytics.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.666 0.179 58.318), oklch(0.769 0.188 70.08))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg></div>
<div class="b"><div class="n">Tab · Analytics</div><div class="t">Path Funnel</div><p class="d">Course-by-course funnel, drop-off callouts, stuck lessons/exercises.</p></div>
</a>
<a class="card shot" href="teacher-path-landing-editor.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.623 0.214 259.815), oklch(0.546 0.245 262.881))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
<div class="b"><div class="n">Tab · Landing page</div><div class="t">Landing Editor</div><p class="d">Hero copy, visitor access level, outcomes, skills, instructors, testimonials, FAQ.</p></div>
</a>
<a class="card shot" href="teacher-path-certificate.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.769 0.188 70.08), oklch(0.666 0.179 58.318))"><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></div>
<div class="b"><div class="n">Tab · Certificate</div><div class="t">Path Certificate</div><p class="d">Award toggle, completion requirements, live certificate preview.</p></div>
</a>
<a class="card shot" href="teacher-path-settings.html">
<div class="cover" style="background: linear-gradient(135deg, oklch(0.37 0.044 257.287), oklch(0.488 0.243 264.376))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg></div>
<div class="b"><div class="n">Tab · Settings</div><div class="t">Path Settings</div><p class="d">General, bundle pricing + savings, enrollment & unlock rules, status, danger zone.</p></div>
</a>
</div>
<div class="foot">
<b>Key product decisions baked into these prototypes:</b><br />
· Learning paths are a <b>new entity</b> (separate from Programs) — <code>learning_path</code>, <code>learning_path_course</code> (ordered), <code>learning_path_member</code>.<br />
· <b>Self-enrollment with bundle pricing</b> from the public site; the price shows savings vs summed course prices.<br />
· A course unlocks when the previous course's <b>lessons AND exercises</b> are complete; sequential unlocking is a per-path toggle.<br />
· <b>Path certificate</b> is a teacher toggle with its own tab; visitor access to the syllabus is teacher-configurable.<br />
· Public pages mirror the <b>"minimal" org-landing theme</b>; app pages mirror <code>packages/ui</code> (shadcn-svelte, Geist, OKLCH tokens).
</div>
</div>
<button class="icon-btn" id="theme" title="Toggle theme" aria-label="Toggle theme" style="position: fixed; bottom: 18px; right: 18px">
<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>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
+947
View File
@@ -0,0 +1,947 @@
/*
* landing-theme.css — public org-site pages for the learning-paths prototypes.
*
* Mirrors packages/ui/src/custom/org-landing-page/ default theme ("minimal"):
* --landing-* CSS vars from theme-vars-base.ts, square-cornered cards
* (--landing-radius-card: 0), no card shadows, pill floating nav, accent
* radial-gradient hero. Accent = the org brand (default ClassroomIO indigo).
*/
:root {
--landing-bg: oklch(1 0 0);
--landing-fg: oklch(0.185 0 0);
--landing-fg-muted: oklch(0.5 0 0);
--landing-border: oklch(0.9 0 0);
--landing-card: oklch(1 0 0);
--landing-card-soft: oklch(0.975 0 0);
--landing-accent: oklch(0.488 0.243 264.376);
--landing-accent-soft: oklch(0.488 0.243 264.376 / 0.08);
--landing-button-primary-bg: oklch(0.488 0.243 264.376);
--landing-button-primary-bg-hover: oklch(0.424 0.199 265.638);
--landing-button-primary-fg: #fff;
--landing-success: oklch(0.596 0.145 163.225);
--landing-radius-card: 0px;
--landing-radius-button: 6px;
}
.dark {
--landing-bg: oklch(0.16 0 0);
--landing-fg: oklch(0.96 0 0);
--landing-fg-muted: oklch(0.68 0 0);
--landing-border: oklch(1 0 0 / 14%);
--landing-card: oklch(0.2 0 0);
--landing-card-soft: oklch(0.24 0 0);
--landing-accent: oklch(0.623 0.214 259.815);
--landing-accent-soft: oklch(0.623 0.214 259.815 / 0.14);
--landing-button-primary-bg: oklch(0.546 0.245 262.881);
--landing-button-primary-bg-hover: oklch(0.623 0.214 259.815);
--landing-success: oklch(0.696 0.17 162.48);
}
* {
box-sizing: border-box;
border-color: var(--landing-border);
}
html {
scroll-behavior: smooth;
}
html,
body {
margin: 0;
padding: 0;
}
body {
font-family:
'Geist',
ui-sans-serif,
system-ui,
-apple-system,
'Segoe UI',
Roboto,
sans-serif;
background: var(--landing-bg);
color: var(--landing-fg);
font-size: 16px;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
a {
color: inherit;
text-decoration: none;
}
button {
font: inherit;
}
.tnum {
font-variant-numeric: tabular-nums;
}
.lp-wrap {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.lp-wrap-narrow {
max-width: 880px;
margin: 0 auto;
padding: 0 20px;
}
/* ===== pill nav (minimal theme) ===== */
.lp-nav-outer {
padding: 20px 20px 0;
max-width: 1240px;
margin: 0 auto;
}
.lp-nav {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
padding: 14px 24px;
border-radius: 999px;
border: 1px solid color-mix(in oklab, var(--landing-border) 60%, transparent);
background: linear-gradient(
135deg,
color-mix(in oklab, var(--landing-accent) 14%, transparent),
color-mix(in oklab, var(--landing-accent) 6%, transparent)
);
backdrop-filter: blur(8px);
}
.lp-nav-brand {
display: flex;
align-items: center;
gap: 10px;
font-weight: 600;
font-size: 19px;
}
.lp-nav-logo {
width: 32px;
height: 32px;
border-radius: 8px;
background: var(--landing-accent);
color: #fff;
display: grid;
place-items: center;
font-weight: 700;
font-size: 15px;
}
.lp-nav-links {
display: flex;
align-items: center;
gap: 28px;
font-size: 14.5px;
}
.lp-nav-links > a {
opacity: 0.72;
}
.lp-nav-links > a:hover,
.lp-nav-links > a.active {
opacity: 1;
}
.lp-nav-auth {
border: 1px solid var(--landing-border);
border-radius: 999px;
padding: 8px 18px;
font-size: 14px;
font-weight: 500;
background: var(--landing-card);
}
.lp-nav-auth:hover {
border-color: var(--landing-fg-muted);
}
@media (max-width: 760px) {
.lp-nav-links > a {
display: none;
}
}
/* ===== hero ===== */
.lp-hero {
position: relative;
padding: 72px 0 80px;
text-align: center;
overflow: hidden;
background:
radial-gradient(60% 90% at 50% -10%, var(--landing-accent-soft) 0%, transparent 70%),
linear-gradient(180deg, transparent, transparent);
}
.lp-hero-dots {
position: absolute;
inset: 0;
opacity: 0.08;
pointer-events: none;
background-image: radial-gradient(circle, var(--landing-fg) 1px, transparent 1.5px);
background-size: 22px 22px;
}
.lp-hero-inner {
position: relative;
max-width: 860px;
margin: 0 auto;
padding: 0 20px;
}
.lp-hero h1 {
font-size: clamp(34px, 6vw, 56px);
font-weight: 600;
letter-spacing: -0.03em;
line-height: 1.08;
margin: 0 0 20px;
text-wrap: balance;
}
.lp-hero .sub {
font-size: 19px;
font-weight: 300;
color: color-mix(in oklab, var(--landing-fg) 72%, transparent);
margin: 0 auto 32px;
max-width: 60ch;
}
.lp-cta-row {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
}
/* ===== buttons ===== */
.lp-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
border-radius: var(--landing-radius-button);
border: 1px solid transparent;
font-weight: 500;
font-size: 15px;
padding: 10px 22px;
cursor: pointer;
transition:
background 0.12s,
border-color 0.12s;
}
.lp-btn svg {
width: 16px;
height: 16px;
stroke-width: 2;
}
.lp-btn-primary {
background: var(--landing-button-primary-bg);
color: var(--landing-button-primary-fg);
}
.lp-btn-primary:hover {
background: var(--landing-button-primary-bg-hover);
}
.lp-btn-secondary {
background: var(--landing-card);
border-color: var(--landing-border);
color: var(--landing-fg);
}
.lp-btn-secondary:hover {
border-color: var(--landing-fg-muted);
}
.lp-btn-lg {
padding: 13px 28px;
font-size: 16px;
}
.lp-btn-pill {
border-radius: 999px;
}
.lp-btn-block {
width: 100%;
}
/* ===== sections ===== */
.lp-section {
padding: 72px 0;
}
.lp-section + .lp-section {
border-top: 1px solid var(--landing-border);
}
.lp-section h2 {
font-size: 26px;
font-weight: 600;
letter-spacing: -0.02em;
margin: 0 0 8px;
}
.lp-section .lead {
color: var(--landing-fg-muted);
margin: 0 0 32px;
max-width: 62ch;
}
.lp-eyebrow {
font-size: 12px;
letter-spacing: 0.12em;
text-transform: uppercase;
font-weight: 600;
color: var(--landing-accent);
margin-bottom: 10px;
display: block;
}
/* ===== cards (minimal: square, hairline, no shadow) ===== */
.lp-card {
background: var(--landing-card);
border: 1px solid color-mix(in oklab, var(--landing-border) 60%, transparent);
border-radius: var(--landing-radius-card);
transition: border-color 0.15s;
}
a.lp-card:hover {
border-color: var(--landing-fg-muted);
}
/* course card (minimal shape) */
.lp-course-card {
display: flex;
flex-direction: column;
padding: 32px;
}
.lp-course-card h3 {
font-size: 20px;
font-weight: 400;
margin: 0 0 14px;
letter-spacing: -0.01em;
}
.lp-course-card .desc {
font-size: 15.5px;
line-height: 1.65;
color: var(--landing-fg-muted);
margin: 0 0 30px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.lp-meta-row {
display: flex;
align-items: center;
gap: 20px;
font-size: 14px;
color: var(--landing-fg-muted);
margin-top: auto;
flex-wrap: wrap;
}
.lp-meta-row .m {
display: flex;
align-items: center;
gap: 6px;
}
.lp-meta-row svg {
width: 15px;
height: 15px;
stroke-width: 1.8;
}
.lp-meta-row .price {
margin-left: auto;
font-weight: 600;
color: var(--landing-fg);
font-size: 15px;
}
.lp-meta-row .price s {
color: var(--landing-fg-muted);
font-weight: 400;
font-size: 13px;
margin-left: 6px;
}
/* path badge + save chip */
.lp-chip {
display: inline-flex;
align-items: center;
gap: 6px;
width: fit-content;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--landing-accent);
background: var(--landing-accent-soft);
padding: 4px 10px;
margin-bottom: 16px;
}
.lp-chip svg {
width: 13px;
height: 13px;
stroke-width: 2.2;
}
.lp-save {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12.5px;
font-weight: 600;
color: var(--landing-success);
background: color-mix(in oklab, var(--landing-success) 10%, transparent);
padding: 3px 9px;
}
/* ordered course list inside a path card */
.lp-path-courses {
border-top: 1px solid var(--landing-border);
margin: 22px 0;
}
.lp-path-course {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 0;
border-bottom: 1px solid var(--landing-border);
font-size: 14.5px;
}
.lp-path-course .n {
width: 22px;
height: 22px;
border-radius: 999px;
background: var(--landing-accent-soft);
color: var(--landing-accent);
display: grid;
place-items: center;
font-size: 11.5px;
font-weight: 600;
flex-shrink: 0;
}
.lp-path-course .t {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.lp-path-course .d {
font-size: 13px;
color: var(--landing-fg-muted);
flex-shrink: 0;
}
/* ===== stats row (social proof) ===== */
.lp-stats {
display: flex;
justify-content: center;
border-block: 1px solid var(--landing-border);
padding: 28px 0;
flex-wrap: wrap;
}
.lp-stat {
padding: 0 36px;
text-align: center;
border-right: 1px solid var(--landing-border);
}
.lp-stat:last-child {
border-right: none;
}
.lp-stat .v {
font-size: 24px;
font-weight: 600;
letter-spacing: -0.02em;
}
.lp-stat .k {
font-size: 13px;
color: var(--landing-fg-muted);
margin-top: 2px;
}
@media (max-width: 720px) {
.lp-stat {
padding: 10px 20px;
border-right: none;
}
}
/* ===== anchor nav ===== */
.lp-anchor-nav {
position: sticky;
top: 0;
z-index: 50;
background: color-mix(in oklab, var(--landing-bg) 92%, transparent);
backdrop-filter: blur(8px);
border-bottom: 1px solid var(--landing-border);
}
.lp-anchor-nav .in {
display: flex;
gap: 6px;
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
overflow-x: auto;
}
.lp-anchor-nav a {
padding: 14px 14px;
font-size: 14.5px;
color: var(--landing-fg-muted);
border-bottom: 2px solid transparent;
white-space: nowrap;
}
.lp-anchor-nav a:hover {
color: var(--landing-fg);
}
.lp-anchor-nav a.active {
color: var(--landing-fg);
border-bottom-color: var(--landing-accent);
font-weight: 500;
}
/* ===== outcomes / bullets ===== */
.lp-outcomes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px 32px;
}
.lp-outcome {
display: flex;
gap: 12px;
font-size: 15.5px;
line-height: 1.55;
}
.lp-outcome svg {
width: 18px;
height: 18px;
stroke-width: 2.2;
color: var(--landing-accent);
flex-shrink: 0;
margin-top: 3px;
}
@media (max-width: 720px) {
.lp-outcomes {
grid-template-columns: 1fr;
}
}
/* skill tags */
.lp-skills {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.lp-skill {
border: 1px solid var(--landing-border);
padding: 7px 16px;
font-size: 14px;
border-radius: 999px;
color: var(--landing-fg);
}
/* ===== series (sequential course cards) ===== */
.lp-series {
display: flex;
flex-direction: column;
gap: 16px;
}
.lp-series-card {
padding: 26px 28px;
}
.lp-series-head {
display: flex;
align-items: flex-start;
gap: 16px;
}
.lp-series-n {
width: 36px;
height: 36px;
border-radius: 999px;
background: var(--landing-accent-soft);
color: var(--landing-accent);
display: grid;
place-items: center;
font-weight: 600;
font-size: 15px;
flex-shrink: 0;
}
.lp-series-card h3 {
font-size: 18px;
font-weight: 500;
margin: 4px 0 2px;
letter-spacing: -0.01em;
}
.lp-series-sub {
font-size: 13.5px;
color: var(--landing-fg-muted);
}
.lp-series-body {
margin: 16px 0 0 52px;
}
.lp-series-body .lbl {
font-size: 12px;
letter-spacing: 0.1em;
text-transform: uppercase;
font-weight: 600;
color: var(--landing-fg-muted);
margin-bottom: 10px;
}
.lp-series-outcomes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px 24px;
margin-bottom: 4px;
}
.lp-series-outcomes .o {
display: flex;
gap: 9px;
font-size: 14px;
color: var(--landing-fg);
line-height: 1.5;
}
.lp-series-outcomes .o svg {
width: 15px;
height: 15px;
stroke-width: 2.2;
color: var(--landing-accent);
flex-shrink: 0;
margin-top: 3px;
}
.lp-lessons-toggle {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 500;
color: var(--landing-accent);
background: none;
border: none;
cursor: pointer;
padding: 10px 0 0;
}
.lp-lessons-toggle svg {
width: 15px;
height: 15px;
stroke-width: 2.2;
transition: transform 0.15s;
}
.lp-lessons-toggle.open svg {
transform: rotate(180deg);
}
.lp-lessons {
display: none;
border-top: 1px solid var(--landing-border);
margin-top: 12px;
}
.lp-lessons.open {
display: block;
}
.lp-lesson {
display: flex;
align-items: center;
gap: 12px;
padding: 9px 0;
border-bottom: 1px solid var(--landing-border);
font-size: 14px;
}
.lp-lesson .ix {
font-family: ui-monospace, monospace;
font-size: 12.5px;
color: var(--landing-fg-muted);
min-width: 3ch;
}
.lp-lesson .dur {
margin-left: auto;
font-size: 12.5px;
color: var(--landing-fg-muted);
}
.lp-lesson .prev {
font-size: 12px;
font-weight: 600;
color: var(--landing-accent);
}
@media (max-width: 720px) {
.lp-series-outcomes {
grid-template-columns: 1fr;
}
.lp-series-body {
margin-left: 0;
}
}
/* ===== instructors ===== */
.lp-instructors {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.lp-instructor {
padding: 24px;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
}
.lp-instructor .av {
width: 52px;
height: 52px;
border-radius: 999px;
background: var(--landing-accent-soft);
color: var(--landing-accent);
display: grid;
place-items: center;
font-weight: 600;
font-size: 17px;
margin-bottom: 10px;
}
.lp-instructor .nm {
font-size: 15.5px;
font-weight: 600;
}
.lp-instructor .rl {
font-size: 13px;
color: var(--landing-fg-muted);
}
.lp-instructor .bio {
font-size: 13.5px;
color: var(--landing-fg-muted);
margin-top: 8px;
line-height: 1.55;
}
@media (max-width: 760px) {
.lp-instructors {
grid-template-columns: 1fr;
}
}
/* ===== testimonials ===== */
.lp-testimonials {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.lp-testimonial {
padding: 26px;
}
.lp-testimonial .q {
font-size: 15.5px;
line-height: 1.65;
margin: 0 0 16px;
}
.lp-testimonial .who {
display: flex;
align-items: center;
gap: 10px;
font-size: 13.5px;
}
.lp-testimonial .who .av {
width: 34px;
height: 34px;
border-radius: 999px;
background: var(--landing-accent-soft);
color: var(--landing-accent);
display: grid;
place-items: center;
font-weight: 600;
font-size: 12px;
}
.lp-testimonial .who .nm {
font-weight: 600;
}
.lp-testimonial .who .loc {
color: var(--landing-fg-muted);
}
@media (max-width: 720px) {
.lp-testimonials {
grid-template-columns: 1fr;
}
}
/* ===== FAQ accordion ===== */
.lp-faq {
border-top: 1px solid var(--landing-border);
}
.lp-faq-item {
border-bottom: 1px solid var(--landing-border);
}
.lp-faq-q {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
padding: 18px 4px;
background: none;
border: none;
cursor: pointer;
text-align: left;
font-size: 15.5px;
font-weight: 500;
color: var(--landing-fg);
}
.lp-faq-q svg {
width: 17px;
height: 17px;
stroke-width: 2;
color: var(--landing-fg-muted);
flex-shrink: 0;
transition: transform 0.15s;
}
.lp-faq-item.open .lp-faq-q svg {
transform: rotate(180deg);
}
.lp-faq-a {
display: none;
padding: 0 4px 18px;
font-size: 14.5px;
color: var(--landing-fg-muted);
line-height: 1.65;
max-width: 68ch;
}
.lp-faq-item.open .lp-faq-a {
display: block;
}
/* ===== pricing card ===== */
.lp-pricing-card {
max-width: 440px;
margin: 0 auto;
padding: 32px;
text-align: center;
}
.lp-pricing-card .eyebrow {
font-size: 12px;
letter-spacing: 0.12em;
text-transform: uppercase;
font-weight: 600;
color: var(--landing-fg-muted);
margin-bottom: 12px;
}
.lp-price {
font-size: 46px;
font-weight: 600;
letter-spacing: -0.03em;
line-height: 1;
}
.lp-price-was {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
margin: 10px 0 20px;
font-size: 14.5px;
color: var(--landing-fg-muted);
}
.lp-price-was s {
font-size: 16px;
}
.lp-features {
text-align: left;
margin: 0 0 24px;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
gap: 10px;
}
.lp-features li {
display: flex;
gap: 10px;
font-size: 14.5px;
}
.lp-features svg {
width: 16px;
height: 16px;
stroke-width: 2.2;
color: var(--landing-accent);
flex-shrink: 0;
margin-top: 3px;
}
/* certificate banner */
.lp-cert {
display: flex;
align-items: center;
gap: 22px;
padding: 28px 30px;
}
.lp-cert .frame {
width: 130px;
height: 92px;
border: 1px solid var(--landing-border);
background: var(--landing-card-soft);
position: relative;
flex-shrink: 0;
display: grid;
place-items: center;
}
.lp-cert .frame::before {
content: '';
position: absolute;
inset: 6px;
border: 1px solid color-mix(in oklab, var(--landing-accent) 35%, transparent);
}
.lp-cert .frame svg {
width: 26px;
height: 26px;
stroke-width: 1.8;
color: var(--landing-accent);
}
.lp-cert h3 {
font-size: 18px;
font-weight: 600;
margin: 0 0 4px;
}
.lp-cert p {
font-size: 14.5px;
color: var(--landing-fg-muted);
margin: 0;
max-width: 56ch;
}
/* ===== footer ===== */
.lp-footer {
border-top: 1px solid var(--landing-border);
padding: 48px 0 40px;
margin-top: 24px;
}
.lp-footer-grid {
display: grid;
grid-template-columns: minmax(0, 1.4fr) repeat(auto-fit, minmax(140px, 1fr));
gap: 32px;
}
.lp-footer h4 {
font-size: 13px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--landing-fg-muted);
font-weight: 600;
margin: 0 0 12px;
}
.lp-footer a {
display: block;
font-size: 14px;
color: var(--landing-fg-muted);
padding: 3px 0;
}
.lp-footer a:hover {
color: var(--landing-fg);
}
.lp-footer .brand {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
margin-bottom: 10px;
}
.lp-footer .copy {
font-size: 13px;
color: var(--landing-fg-muted);
margin-top: 12px;
}
@media (max-width: 720px) {
.lp-footer-grid {
grid-template-columns: 1fr;
}
}
/* theme toggle button (prototype affordance) */
.lp-theme-btn {
position: fixed;
bottom: 18px;
right: 18px;
z-index: 200;
width: 38px;
height: 38px;
border-radius: 999px;
border: 1px solid var(--landing-border);
background: var(--landing-card);
color: var(--landing-fg-muted);
cursor: pointer;
display: grid;
place-items: center;
box-shadow: 0 2px 8px rgb(0 0 0 / 0.08);
}
.lp-theme-btn svg {
width: 16px;
height: 16px;
stroke-width: 2;
}
+191
View File
@@ -0,0 +1,191 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My Learning · ClassroomIO LMS</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.path-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.path-card { overflow: hidden; display: flex; flex-direction: column; transition: box-shadow 0.15s, border-color 0.15s; }
.path-card:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
.pc-cover { height: 80px; position: relative; }
.pc-cover .badge { position: absolute; top: 12px; left: 14px; background: oklch(1 0 0 / 0.18); color: #fff; border-color: oklch(1 0 0 / 0.3); backdrop-filter: blur(4px); }
.pc-body { padding: 16px; display: flex; flex-direction: column; gap: 12px; flex: 1; }
.pc-title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 2px; }
.pc-desc { font-size: 13px; color: var(--muted-foreground); margin: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.seg-row { display: flex; align-items: center; gap: 10px; }
.seg-pct { font-size: 13px; font-weight: 600; min-width: 34px; text-align: right; }
.pc-meta { display: flex; gap: 14px; font-size: 12.5px; color: var(--muted-foreground); }
.pc-meta .m { display: flex; align-items: center; gap: 5px; }
.pc-meta svg { width: 14px; height: 14px; stroke-width: 2; }
.pc-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: auto; }
.pc-next { font-size: 12.5px; color: var(--muted-foreground); min-width: 0; }
.pc-next strong { color: var(--foreground); font-weight: 500; }
.course-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.course-card { overflow: hidden; transition: box-shadow 0.15s, border-color 0.15s; }
.course-card:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
.cc-cover { height: 92px; }
.cc-body { padding: 14px; }
.cc-title { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 4px; }
.cc-desc { font-size: 12.5px; color: var(--muted-foreground); margin: 0 0 12px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 34px; }
.cc-prog { display: flex; align-items: center; gap: 9px; }
.cc-prog .p { font-size: 12px; font-weight: 600; color: var(--muted-foreground); min-width: 32px; text-align: right; }
.greet { font-size: 24px; font-weight: 500; letter-spacing: -0.02em; margin: 4px 0 4px; }
@media (max-width: 980px) { .path-grid { grid-template-columns: 1fr; } .course-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) { .course-grid { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
<div class="nav-label">Learn</div>
<a class="nav-item active" href="lms-home.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>My Learning</a>
<a class="nav-item" href="paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths<span class="nav-badge">2</span></a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Exercises</a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Community</a>
<a class="nav-item" href="#"><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>Certificates</a>
<div class="sidebar-foot"><div class="avatar">AO</div><div class="who"><div class="nm">Ada Okafor</div><div class="rl">Student</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<span class="top-title">My Learning</span>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
<button class="icon-btn" title="Notifications" aria-label="Notifications"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg></button>
</div>
</header>
<main class="content">
<div class="wrap" style="max-width: 1040px">
<h1 class="greet">Welcome back, Ada</h1>
<p class="page-sub" style="margin-bottom: 8px">Pick up where you left off — you're 49% through your bootcamp.</p>
<div class="sec-head">
<h2 class="sec-title" style="display: flex; align-items: center; gap: 8px">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 16px; height: 16px; stroke-width: 2; color: var(--primary)"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
Learning Paths
</h2>
<span class="count">2</span>
<a class="more" href="paths.html">View all <svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></a>
</div>
<div class="path-grid">
<a class="card path-card" href="path-detail.html">
<div class="pc-cover" style="background: linear-gradient(120deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))">
<span class="badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Path</span>
</div>
<div class="pc-body">
<div>
<h3 class="pc-title">Frontend Engineering Bootcamp</h3>
<p class="pc-desc">From HTML foundations to shipping a production React app.</p>
</div>
<div class="seg-row">
<div class="segs"><span class="seg done"></span><span class="seg done"></span><span class="seg half"></span><span class="seg"></span><span class="seg"></span></div>
<span class="seg-pct tnum text-primary">49%</span>
</div>
<div class="pc-meta">
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>2 of 5 done</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38h</span>
</div>
<div class="pc-foot">
<div class="pc-next">Next: <strong>Modern Web Development with React</strong></div>
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</div>
</a>
<a class="card path-card" href="paths.html">
<div class="pc-cover" style="background: linear-gradient(120deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))">
<span class="badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Path</span>
</div>
<div class="pc-body">
<div>
<h3 class="pc-title">Data Science with Python</h3>
<p class="pc-desc">Pandas, visualization, and applied machine-learning basics.</p>
</div>
<div class="seg-row">
<div class="segs"><span class="seg half"></span><span class="seg"></span><span class="seg"></span><span class="seg"></span></div>
<span class="seg-pct tnum text-primary">8%</span>
</div>
<div class="pc-meta">
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>0 of 4 done</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30h</span>
</div>
<div class="pc-foot">
<div class="pc-next">Just started: <strong>Intro to Python</strong></div>
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</div>
</a>
</div>
<div class="sec-head">
<h2 class="sec-title" style="display: flex; align-items: center; gap: 8px">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" style="width: 16px; height: 16px; stroke-width: 2; color: var(--primary)"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Courses
</h2>
<span class="count">4</span>
</div>
<div class="course-grid">
<a class="card course-card" href="course-in-path.html">
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"></div>
<div class="cc-body">
<span class="badge badge-primary-soft" style="margin-bottom: 8px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Frontend Bootcamp · 3/5</span>
<h3 class="cc-title">Modern Web Development with React</h3>
<p class="cc-desc">Components, hooks, and building interactive UIs.</p>
<div class="cc-prog"><div class="progress progress-thin"><span style="width: 45%"></span></div><span class="p tnum">45%</span></div>
</div>
</a>
<a class="card course-card" href="path-detail.html">
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.705 0.213 47.604), oklch(0.75 0.183 55.934))"></div>
<div class="cc-body">
<span class="badge badge-primary-soft" style="margin-bottom: 8px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Frontend Bootcamp · 1/5</span>
<h3 class="cc-title">HTML &amp; CSS Foundations</h3>
<p class="cc-desc">Semantic markup, the box model, and responsive layout.</p>
<div class="cc-prog"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum">100%</span></div>
</div>
</a>
<a class="card course-card" href="#">
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.585 0.233 277.117), oklch(0.606 0.25 292.717))"></div>
<div class="cc-body">
<h3 class="cc-title" style="margin-top: 26px">Getting Started with MVC</h3>
<p class="cc-desc">A standalone course on the model-view-controller pattern.</p>
<div class="cc-prog"><div class="progress progress-thin"><span style="width: 20%"></span></div><span class="p tnum">20%</span></div>
</div>
</a>
<a class="card course-card" href="#">
<div class="cc-cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))"></div>
<div class="cc-body">
<span class="badge badge-primary-soft" style="margin-bottom: 8px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Data Science · 1/4</span>
<h3 class="cc-title">Intro to Python</h3>
<p class="cc-desc">Syntax, data types, and your first scripts.</p>
<div class="cc-prog"><div class="progress progress-thin"><span style="width: 30%"></span></div><span class="p tnum">30%</span></div>
</div>
</a>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
+184
View File
@@ -0,0 +1,184 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Acme Academy — Learn frontend, data, and product</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="landing-theme.css" />
<script>
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
document.documentElement.classList.add('dark');
</script>
<style>
.paths-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }
.courses-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }
@media (max-width: 860px) { .paths-grid, .courses-grid { grid-template-columns: 1fr; } }
.view-more { display: flex; justify-content: center; margin-top: 36px; }
</style>
</head>
<body>
<!-- nav -->
<div class="lp-nav-outer">
<nav class="lp-nav">
<a class="lp-nav-brand" href="org-landing.html"><span class="lp-nav-logo">A</span>Acme Academy</a>
<div class="lp-nav-links">
<a href="public-paths.html">Learning Paths</a>
<a href="#courses">Courses</a>
<a class="lp-nav-auth" href="lms-home.html">Login</a>
</div>
</nav>
</div>
<!-- hero -->
<header class="lp-hero">
<div class="lp-hero-dots"></div>
<div class="lp-hero-inner">
<h1>Practical tech skills, taught the way work actually happens</h1>
<p class="sub">Courses and guided learning paths in engineering, data, and product — built by practitioners, finished with certificates.</p>
<div class="lp-cta-row">
<a class="lp-btn lp-btn-primary lp-btn-lg lp-btn-pill" href="public-paths.html">Explore learning paths</a>
<a class="lp-btn lp-btn-secondary lp-btn-lg lp-btn-pill" href="#courses">Browse courses</a>
</div>
</div>
</header>
<!-- ===== LEARNING PATHS (above courses) ===== -->
<section class="lp-section" id="paths">
<div class="lp-wrap">
<span class="lp-eyebrow">Guided programs</span>
<h2>Learning Paths</h2>
<p class="lead">Multi-course tracks you complete in order — one enrollment, one price, one certificate at the end.</p>
<div class="paths-grid">
<!-- Path card 1 -->
<a class="lp-card lp-course-card" href="public-path.html">
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
<h3>Frontend Engineering Bootcamp</h3>
<p class="desc">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</p>
<div class="lp-path-courses">
<div class="lp-path-course"><span class="n tnum">1</span><span class="t">HTML &amp; CSS Foundations</span><span class="d tnum">12 lessons</span></div>
<div class="lp-path-course"><span class="n tnum">2</span><span class="t">JavaScript Essentials</span><span class="d tnum">10 lessons</span></div>
<div class="lp-path-course"><span class="n tnum">3</span><span class="t">Modern Web Development with React</span><span class="d tnum">12 lessons</span></div>
<div class="lp-path-course" style="border-bottom: none"><span class="n" style="background: transparent; color: var(--landing-fg-muted)">+</span><span class="t" style="color: var(--landing-fg-muted)">2 more courses</span></div>
</div>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38 hours</span>
<span class="m"><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>Certificate</span>
<span class="price tnum">$199 <s>$280</s></span>
</div>
</a>
<!-- Path card 2 -->
<a class="lp-card lp-course-card" href="public-path.html">
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
<h3>Data Science with Python</h3>
<p class="desc">From Python basics to applied machine learning — pandas, visualization, and a real analysis project, in a fixed order that builds week over week.</p>
<div class="lp-path-courses">
<div class="lp-path-course"><span class="n tnum">1</span><span class="t">Intro to Python</span><span class="d tnum">9 lessons</span></div>
<div class="lp-path-course"><span class="n tnum">2</span><span class="t">Data Analysis with Pandas</span><span class="d tnum">11 lessons</span></div>
<div class="lp-path-course"><span class="n tnum">3</span><span class="t">Data Visualization</span><span class="d tnum">8 lessons</span></div>
<div class="lp-path-course" style="border-bottom: none"><span class="n" style="background: transparent; color: var(--landing-fg-muted)">+</span><span class="t" style="color: var(--landing-fg-muted)">1 more course</span></div>
</div>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>4 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30 hours</span>
<span class="m"><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>Certificate</span>
<span class="price tnum">$159 <s>$212</s></span>
</div>
</a>
</div>
<div class="view-more">
<a class="lp-btn lp-btn-secondary lp-btn-lg" href="public-paths.html">View all learning paths</a>
</div>
</div>
</section>
<!-- ===== COURSES ===== -->
<section class="lp-section" id="courses">
<div class="lp-wrap">
<h2>Our Courses</h2>
<p class="lead">Standalone courses you can take in any order.</p>
<div class="courses-grid">
<a class="lp-card lp-course-card" href="#">
<h3>HTML &amp; CSS Foundations</h3>
<p class="desc">Semantic markup, the box model, flexbox, and responsive layout basics for absolute beginners.</p>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>8 hours</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
<span class="price tnum">$49</span>
</div>
</a>
<a class="lp-card lp-course-card" href="#">
<h3>JavaScript Essentials</h3>
<p class="desc">Types, functions, the DOM, async/await, and fetching data from APIs — production JavaScript from day one.</p>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>9 hours</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
<span class="price tnum">$59</span>
</div>
</a>
<a class="lp-card lp-course-card" href="#">
<h3>Modern Web Development with React</h3>
<p class="desc">Components, props &amp; state, hooks, and building interactive UIs with the most-used frontend library.</p>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>10 hours</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
<span class="price tnum">$79</span>
</div>
</a>
<a class="lp-card lp-course-card" href="#">
<h3>Getting Started with MVC</h3>
<p class="desc">A standalone deep dive on the model-view-controller pattern and where it still shines today.</p>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>5 hours</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Self paced</span>
<span class="price">Free</span>
</div>
</a>
</div>
<div class="view-more">
<a class="lp-btn lp-btn-secondary lp-btn-lg" href="#">View more courses</a>
</div>
</div>
</section>
<!-- footer -->
<footer class="lp-footer">
<div class="lp-wrap lp-footer-grid">
<div>
<div class="brand"><span class="lp-nav-logo" style="width: 26px; height: 26px; font-size: 12px">A</span>Acme Academy</div>
<p class="copy" style="max-width: 34ch">Practical tech skills, taught by practitioners.</p>
<p class="copy">© 2026 Acme Academy</p>
</div>
<div>
<h4>Learn</h4>
<a href="public-paths.html">Learning Paths</a>
<a href="#courses">Courses</a>
<a href="#">Certificates</a>
</div>
<div>
<h4>Academy</h4>
<a href="#">About</a>
<a href="#">Contact</a>
<a href="lms-home.html">Login</a>
</div>
</div>
</footer>
<button class="lp-theme-btn" id="theme" 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>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
+235
View File
@@ -0,0 +1,235 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Learning Path · ClassroomIO LMS</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.path-head { overflow: hidden; }
.ph-cover { height: 110px; background:
radial-gradient(120% 150% at 10% -20%, oklch(0.623 0.214 259.815) 0%, transparent 55%),
linear-gradient(120deg, oklch(0.488 0.243 264.376), oklch(0.546 0.245 262.881)); position: relative; }
.ph-cover .badge { position: absolute; top: 14px; left: 18px; background: oklch(1 0 0 / 0.18); color: #fff; border-color: oklch(1 0 0 / 0.3); backdrop-filter: blur(4px); }
.ph-body { padding: 20px 22px 22px; }
.ph-title { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; margin: 0 0 6px; text-wrap: balance; }
.ph-desc { color: var(--muted-foreground); font-size: 14px; max-width: 64ch; margin: 0 0 16px; }
.ph-meta { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 18px; }
.ph-meta .m { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--foreground); }
.ph-meta svg { width: 15px; height: 15px; stroke-width: 2; color: var(--muted-foreground); }
.ph-progress { background: color-mix(in oklab, var(--muted) 50%, transparent); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 14px 16px; }
.pp-top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 9px; }
.pp-label { font-size: 13px; font-weight: 500; }
.pp-count { font-size: 12.5px; color: var(--muted-foreground); }
.pp-pct { font-size: 15px; font-weight: 600; color: var(--primary); }
.pp-foot { display: flex; align-items: center; gap: 7px; margin-top: 10px; font-size: 12.5px; color: var(--muted-foreground); }
.pp-foot svg { width: 14px; height: 14px; stroke-width: 2; }
.pp-foot strong { color: var(--foreground); font-weight: 500; }
.course { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 14px 16px; display: flex; gap: 14px; align-items: flex-start; box-shadow: var(--shadow-2xs); }
.step.s-current .course { border-color: var(--primary); box-shadow: var(--shadow-sm); }
.step.s-locked .course { background: color-mix(in oklab, var(--muted) 40%, transparent); box-shadow: none; }
.thumb { width: 86px; height: 62px; border-radius: var(--radius-md); flex-shrink: 0; position: relative; overflow: hidden; }
.step.s-locked .thumb { filter: grayscale(0.75) opacity(0.7); }
.c-main { min-width: 0; flex: 1; }
.c-top { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; flex-wrap: wrap; }
.c-title { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; margin: 0; }
.c-desc { font-size: 12.5px; color: var(--muted-foreground); margin: 3px 0 0; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.c-facts { display: flex; align-items: center; gap: 14px; margin-top: 9px; font-size: 12px; color: var(--muted-foreground); }
.c-facts .f { display: flex; align-items: center; gap: 5px; }
.c-facts svg { width: 13px; height: 13px; stroke-width: 2; }
.c-progress { display: flex; align-items: center; gap: 10px; margin-top: 10px; max-width: 340px; }
.c-progress .p { font-size: 12px; font-weight: 600; min-width: 34px; text-align: right; color: var(--muted-foreground); }
.c-side { display: flex; flex-direction: column; align-items: flex-end; gap: 9px; flex-shrink: 0; }
.unlock-note { font-size: 11.5px; color: var(--muted-foreground); display: flex; align-items: center; gap: 5px; text-align: right; max-width: 160px; }
.unlock-note svg { width: 12px; height: 12px; stroke-width: 2; flex-shrink: 0; }
.cert-card { border: 1px dashed var(--border); border-radius: var(--radius-lg); padding: 16px; display: flex; align-items: center; gap: 14px; }
@media (max-width: 720px) { .c-side { display: none; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
<div class="nav-label">Learn</div>
<a class="nav-item" href="lms-home.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>My Learning</a>
<a class="nav-item active" href="paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths<span class="nav-badge">2</span></a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Exercises</a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Community</a>
<a class="nav-item" href="#"><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>Certificates</a>
<div class="sidebar-foot"><div class="avatar">AO</div><div class="who"><div class="nm">Ada Okafor</div><div class="rl">Student</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="paths.html">Learning Paths</a><span class="sep">/</span>
<span class="here">Frontend Engineering Bootcamp</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
</div>
</header>
<main class="content">
<div class="wrap">
<section class="card path-head">
<div class="ph-cover">
<span class="badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
</div>
<div class="ph-body">
<h1 class="ph-title">Frontend Engineering Bootcamp</h1>
<p class="ph-desc">A guided, five-course track that takes you from markup fundamentals to shipping a production React app. Each course unlocks the next — finish in order to earn your certificate.</p>
<div class="ph-meta">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38 hours</span>
<span class="m"><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>Sequential · unlock in order</span>
<span class="m"><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>Certificate on completion</span>
</div>
<div class="ph-progress">
<div class="pp-top">
<div><div class="pp-label">Your progress</div><div class="pp-count tnum">2 of 5 courses complete</div></div>
<div class="pp-pct tnum">49%</div>
</div>
<div class="progress"><span style="width: 49%"></span></div>
<div class="pp-foot">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
Up next: continue&nbsp;<strong>Modern Web Development with React</strong>&nbsp;— 3 lessons and 2 exercises left.
</div>
</div>
</div>
</section>
<div class="sec-head">
<h2 class="sec-title">Path courses</h2>
<span class="more" style="color: var(--muted-foreground); font-weight: 400">
<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>
Finish lessons &amp; exercises to unlock the next course
</span>
</div>
<div class="journey">
<div class="step s-done">
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div></div>
<article class="course">
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.705 0.213 47.604), oklch(0.75 0.183 55.934))"></div>
<div class="c-main">
<div class="c-top"><span class="item-eyebrow">Course 1</span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Completed</span></div>
<h3 class="c-title">HTML &amp; CSS Foundations</h3>
<p class="c-desc">Semantic markup, the box model, flexbox, and responsive layout basics.</p>
<div class="c-progress"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum">100%</span></div>
</div>
<div class="c-side">
<a class="btn btn-outline btn-sm" href="course-in-path.html">Review</a>
<span class="unlock-note" style="color: var(--success)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Finished May 12</span>
</div>
</article>
</div>
<div class="step s-done">
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div></div>
<article class="course">
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.795 0.184 86.047), oklch(0.769 0.188 70.08))"></div>
<div class="c-main">
<div class="c-top"><span class="item-eyebrow">Course 2</span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Completed</span></div>
<h3 class="c-title">JavaScript Essentials</h3>
<p class="c-desc">Types, functions, the DOM, async/await, and fetching data from APIs.</p>
<div class="c-progress"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum">100%</span></div>
</div>
<div class="c-side">
<a class="btn btn-outline btn-sm" href="course-in-path.html">Review</a>
<span class="unlock-note" style="color: var(--success)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Finished Jun 3</span>
</div>
</article>
</div>
<div class="step s-current">
<div class="rail"><div class="node"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg></div></div>
<article class="course">
<a class="thumb" href="course-in-path.html" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"></a>
<div class="c-main">
<div class="c-top"><span class="item-eyebrow" style="color: var(--primary)">Course 3</span><span class="badge badge-primary-soft"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>In progress</span></div>
<h3 class="c-title"><a href="course-in-path.html">Modern Web Development with React</a></h3>
<p class="c-desc">Components, props &amp; state, hooks, and building interactive UIs.</p>
<div class="c-facts">
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>9 / 12 lessons</span>
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>2 / 4 exercises</span>
</div>
<div class="c-progress"><div class="progress progress-thin"><span style="width: 45%"></span></div><span class="p tnum">45%</span></div>
</div>
<div class="c-side">
<a class="btn btn-primary btn-sm" href="course-in-path.html">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></a>
<span class="unlock-note"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~4h left</span>
</div>
</article>
</div>
<div class="step s-locked">
<div class="rail"><div class="node"><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>
<article class="course">
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.585 0.233 277.117), oklch(0.606 0.25 292.717))"><div class="lock-veil"><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>
<div class="c-main">
<div class="c-top"><span class="item-eyebrow">Course 4</span><span class="badge badge-muted"><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>Locked</span></div>
<h3 class="c-title">State Management &amp; Data Fetching</h3>
<p class="c-desc">Context, reducers, caching, and connecting a React app to a backend.</p>
<div class="c-facts">
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>10 lessons</span>
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>3 exercises</span>
</div>
</div>
<div class="c-side">
<span class="btn btn-secondary btn-sm disabled"><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>Locked</span>
<span class="unlock-note"><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>Unlocks after Course 3</span>
</div>
</article>
</div>
<div class="step s-locked">
<div class="rail"><div class="node"><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>
<article class="course">
<div class="thumb" style="background: linear-gradient(135deg, oklch(0.645 0.246 16.439), oklch(0.586 0.253 17.585))"><div class="lock-veil"><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>
<div class="c-main">
<div class="c-top"><span class="item-eyebrow">Course 5</span><span class="badge badge-muted"><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>Locked</span></div>
<h3 class="c-title">Building &amp; Shipping a Capstone</h3>
<p class="c-desc">Plan, build, and deploy a full project — your portfolio piece.</p>
<div class="c-facts">
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>7 lessons</span>
<span class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>1 capstone project</span>
</div>
</div>
<div class="c-side">
<span class="btn btn-secondary btn-sm disabled"><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>Locked</span>
<span class="unlock-note"><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>Unlocks after Course 4</span>
</div>
</article>
</div>
<div class="step no-rail">
<div class="rail"><div class="node"><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></div></div>
<div class="cert-card">
<div class="item-media-icon item-media-lg"><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></div>
<div class="item-content">
<span class="item-title item-title-lg">Bootcamp Certificate</span>
<span class="item-desc">Complete all 5 courses to unlock and download your certificate.</span>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
+174
View File
@@ -0,0 +1,174 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Learning Paths · ClassroomIO LMS</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin-bottom: 20px; }
.tab { padding: 9px 14px; font-size: 14px; font-weight: 500; color: var(--muted-foreground); border: none; background: none; border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; display: flex; align-items: center; gap: 7px; }
.tab:hover { color: var(--foreground); }
.tab.active { color: var(--foreground); border-bottom-color: var(--primary); }
.tab .n { font-size: 11.5px; font-weight: 500; background: var(--muted); border-radius: 999px; padding: 0 7px; color: var(--muted-foreground); }
.path-list { display: flex; flex-direction: column; gap: 14px; }
.path-row { display: grid; grid-template-columns: 150px 1fr; overflow: hidden; transition: border-color 0.15s, box-shadow 0.15s; }
.path-row:hover { border-color: var(--ring); box-shadow: var(--shadow-md); }
.pr-cover { position: relative; display: grid; place-items: center; color: oklch(1 0 0 / 0.9); min-height: 120px; }
.pr-cover svg { width: 28px; height: 28px; stroke-width: 1.8; }
.pr-body { padding: 16px 18px; display: flex; flex-direction: column; gap: 11px; min-width: 0; }
.pr-head { display: flex; align-items: flex-start; gap: 12px; }
.pr-title { font-size: 15.5px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 2px; }
.pr-desc { font-size: 13px; color: var(--muted-foreground); margin: 0; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.seg-row { display: flex; align-items: center; gap: 11px; }
.seg-pct { font-size: 13.5px; font-weight: 600; min-width: 36px; text-align: right; }
.pr-foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.pr-meta { display: flex; align-items: center; gap: 16px; font-size: 12.5px; color: var(--muted-foreground); flex: 1; flex-wrap: wrap; }
.pr-meta .m { display: flex; align-items: center; gap: 5px; }
.pr-meta svg { width: 14px; height: 14px; stroke-width: 2; }
.pr-meta strong { color: var(--foreground); font-weight: 500; }
@media (max-width: 720px) { .path-row { grid-template-columns: 1fr; } .pr-cover { min-height: 72px; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
<div class="nav-label">Learn</div>
<a class="nav-item" href="lms-home.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>My Learning</a>
<a class="nav-item active" href="paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths<span class="nav-badge">2</span></a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Exercises</a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Community</a>
<a class="nav-item" href="#"><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>Certificates</a>
<div class="sidebar-foot"><div class="avatar">AO</div><div class="who"><div class="nm">Ada Okafor</div><div class="rl">Student</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<span class="top-title">Learning Paths</span>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
</div>
</header>
<main class="content">
<div class="wrap" style="max-width: 1000px">
<div class="page-head">
<div>
<h1 class="page-title">Learning Paths</h1>
<p class="page-sub">Structured tracks you're enrolled in. Complete the courses in order to finish a path and earn its certificate.</p>
</div>
</div>
<div class="tabs">
<button class="tab active">In progress <span class="n">2</span></button>
<button class="tab">Completed <span class="n">1</span></button>
<button class="tab">All <span class="n">3</span></button>
</div>
<div class="path-list">
<a class="card path-row" href="path-detail.html">
<div class="pr-cover" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
</div>
<div class="pr-body">
<div class="pr-head">
<div style="min-width: 0">
<h3 class="pr-title">Frontend Engineering Bootcamp</h3>
<p class="pr-desc">From HTML foundations to shipping a production React app.</p>
</div>
<span class="badge badge-primary-soft" style="margin-left: auto; flex-shrink: 0"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>In progress</span>
</div>
<div class="seg-row">
<div class="segs"><span class="seg done"></span><span class="seg done"></span><span class="seg half"></span><span class="seg"></span><span class="seg"></span></div>
<span class="seg-pct tnum text-primary">49%</span>
</div>
<div class="pr-foot">
<div class="pr-meta">
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>2 of 5 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38h</span>
<span class="m">Next: <strong>Modern Web Development with React</strong></span>
</div>
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</div>
</a>
<a class="card path-row" href="path-detail.html">
<div class="pr-cover" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>
</div>
<div class="pr-body">
<div class="pr-head">
<div style="min-width: 0">
<h3 class="pr-title">Data Science with Python</h3>
<p class="pr-desc">Pandas, visualization, and applied machine-learning basics.</p>
</div>
<span class="badge badge-primary-soft" style="margin-left: auto; flex-shrink: 0"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>In progress</span>
</div>
<div class="seg-row">
<div class="segs"><span class="seg half"></span><span class="seg"></span><span class="seg"></span><span class="seg"></span></div>
<span class="seg-pct tnum text-primary">8%</span>
</div>
<div class="pr-foot">
<div class="pr-meta">
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>0 of 4 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30h</span>
<span class="m">Just started: <strong>Intro to Python</strong></span>
</div>
<span class="btn btn-primary btn-sm">Continue<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</div>
</a>
<a class="card path-row" href="path-detail.html" style="opacity: 0.85">
<div class="pr-cover" style="background: linear-gradient(135deg, oklch(0.666 0.179 58.318), oklch(0.769 0.188 70.08))">
<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>
</div>
<div class="pr-body">
<div class="pr-head">
<div style="min-width: 0">
<h3 class="pr-title">Workplace Compliance 2026</h3>
<p class="pr-desc">Security awareness, data handling, and code of conduct.</p>
</div>
<span class="badge badge-success" style="margin-left: auto; flex-shrink: 0"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Completed</span>
</div>
<div class="seg-row">
<div class="segs"><span class="seg done"></span><span class="seg done"></span><span class="seg done"></span></div>
<span class="seg-pct tnum" style="color: var(--success)">100%</span>
</div>
<div class="pr-foot">
<div class="pr-meta">
<span class="m tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>3 of 3 courses</span>
<span class="m"><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>Certificate earned</span>
</div>
<span class="btn btn-outline btn-sm">View certificate<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M5 12h14M12 5l7 7-7 7"/></svg></span>
</div>
</div>
</a>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
document.querySelectorAll('.tab').forEach((tab) => {
tab.addEventListener('click', () => {
document.querySelector('.tab.active')?.classList.remove('active');
tab.classList.add('active');
});
});
</script>
</body>
</html>
+410
View File
@@ -0,0 +1,410 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Frontend Engineering Bootcamp — Acme Academy</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="landing-theme.css" />
<script>
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
document.documentElement.classList.add('dark');
</script>
<style>
.path-hero { text-align: left; padding: 56px 0 0; }
.path-hero-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: 48px; align-items: start; max-width: 1200px; margin: 0 auto; padding: 0 20px; position: relative; }
.path-hero h1 { font-size: clamp(30px, 4.5vw, 44px); text-align: left; }
.path-hero .sub { text-align: left; margin-left: 0; font-size: 17px; }
.instructors-row { display: flex; align-items: center; gap: 10px; margin-bottom: 26px; font-size: 14px; color: var(--landing-fg-muted); }
.av-stack { display: flex; }
.av-stack .av { width: 34px; height: 34px; border-radius: 999px; background: var(--landing-accent-soft); color: var(--landing-accent); display: grid; place-items: center; font-weight: 600; font-size: 12px; border: 2px solid var(--landing-bg); margin-left: -8px; }
.av-stack .av:first-child { margin-left: 0; }
.enroll-box { padding: 26px; position: sticky; top: 70px; }
.enroll-box .amt { font-size: 38px; font-weight: 600; letter-spacing: -0.03em; line-height: 1; }
.enroll-box .was { display: flex; align-items: center; gap: 10px; margin: 8px 0 16px; font-size: 14px; color: var(--landing-fg-muted); }
.enroll-note { font-size: 12.5px; color: var(--landing-fg-muted); margin-top: 12px; text-align: center; }
.hero-stats { margin-top: 44px; }
@media (max-width: 860px) { .path-hero-grid { grid-template-columns: 1fr; } .enroll-box { position: static; } }
</style>
</head>
<body>
<div class="lp-nav-outer">
<nav class="lp-nav">
<a class="lp-nav-brand" href="org-landing.html"><span class="lp-nav-logo">A</span>Acme Academy</a>
<div class="lp-nav-links">
<a class="active" href="public-paths.html">Learning Paths</a>
<a href="org-landing.html#courses">Courses</a>
<a class="lp-nav-auth" href="lms-home.html">Login</a>
</div>
</nav>
</div>
<!-- ===== HERO ===== -->
<header class="lp-hero path-hero">
<div class="lp-hero-dots"></div>
<div class="path-hero-grid">
<div>
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path · Certificate</span>
<h1>Become a job-ready frontend engineer</h1>
<p class="sub">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</p>
<div class="instructors-row">
<div class="av-stack"><span class="av">JD</span><span class="av">EO</span><span class="av">RM</span></div>
Taught by Jordan Diallo, Efe Obi + 1 more
</div>
<div class="lp-cta-row" style="justify-content: flex-start">
<a class="lp-btn lp-btn-primary lp-btn-lg" href="#pricing">Enroll · $199</a>
<span class="lp-save tnum" style="font-size: 14px; padding: 6px 12px">Save $81 vs individual courses</span>
</div>
</div>
<aside class="lp-card enroll-box">
<div class="eyebrow" style="font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; font-weight: 600; color: var(--landing-fg-muted); margin-bottom: 10px">Full path</div>
<div class="amt tnum">$199</div>
<div class="was tnum"><s>$280</s><span class="lp-save">Save $81 (29%)</span></div>
<ul class="lp-features">
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All 5 courses, unlocked in order</li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>52 lessons · 13 exercises · 1 capstone</li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Path certificate on completion</li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Lifetime access, learn at your pace</li>
</ul>
<a class="lp-btn lp-btn-primary lp-btn-lg lp-btn-block" href="lms-home.html">Enroll in this path</a>
<p class="enroll-note tnum">942 already enrolled · 4.7 ★ from 213 reviews</p>
</aside>
</div>
<div class="lp-stats hero-stats">
<div class="lp-stat"><div class="v tnum">5</div><div class="k">courses in series</div></div>
<div class="lp-stat"><div class="v tnum">~38h</div><div class="k">at your own pace</div></div>
<div class="lp-stat"><div class="v">Beginner</div><div class="k">no experience required</div></div>
<div class="lp-stat"><div class="v tnum">4.7 ★</div><div class="k tnum">213 reviews</div></div>
</div>
</header>
<!-- ===== ANCHOR NAV ===== -->
<nav class="lp-anchor-nav">
<div class="in">
<a class="active" href="#about">About</a>
<a href="#courses">Courses</a>
<a href="#certificate">Certificate</a>
<a href="#instructors">Instructors</a>
<a href="#testimonials">Testimonials</a>
<a href="#faq">FAQ</a>
</div>
</nav>
<!-- ===== ABOUT ===== -->
<section class="lp-section" id="about">
<div class="lp-wrap-narrow">
<h2>What you'll learn</h2>
<p class="lead">Practical, project-first skills — every course ends with something you built.</p>
<div class="lp-outcomes">
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Build responsive, accessible websites with semantic HTML and modern CSS</div>
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Write production JavaScript: async, APIs, and the DOM</div>
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Build and ship interactive React apps with state, hooks, and data fetching</div>
<div class="lp-outcome"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Complete a portfolio-ready capstone project, deployed to production</div>
</div>
<h2 style="margin-top: 48px">Skills you'll gain</h2>
<div class="lp-skills" style="margin-top: 18px">
<span class="lp-skill">HTML &amp; CSS</span>
<span class="lp-skill">Flexbox &amp; Grid</span>
<span class="lp-skill">JavaScript</span>
<span class="lp-skill">REST APIs</span>
<span class="lp-skill">React</span>
<span class="lp-skill">State management</span>
<span class="lp-skill">Deployment</span>
</div>
</div>
</section>
<!-- ===== COURSE SERIES ===== -->
<section class="lp-section" id="courses">
<div class="lp-wrap-narrow">
<span class="lp-eyebrow">Series · take in order</span>
<h2>5 courses in this path</h2>
<p class="lead">Each course unlocks the next once you finish its lessons and exercises.</p>
<div class="lp-series">
<!-- Course 1 -->
<div class="lp-card lp-series-card">
<div class="lp-series-head">
<span class="lp-series-n tnum">1</span>
<div>
<h3>HTML &amp; CSS Foundations</h3>
<span class="lp-series-sub tnum">Course 1 · 12 lessons · ~8 hours</span>
</div>
</div>
<div class="lp-series-body">
<div class="lbl">What you'll learn</div>
<div class="lp-series-outcomes">
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Semantic markup and document structure</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>The box model, flexbox, and grid</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Responsive layout from mobile up</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Accessibility fundamentals</span>
</div>
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-lessons">
<div class="lp-lesson"><span class="ix tnum">01</span><span>Anatomy of a web page</span><span class="prev">Preview</span><span class="dur">14m</span></div>
<div class="lp-lesson"><span class="ix tnum">02</span><span>Semantic HTML in practice</span><span class="dur">18m</span></div>
<div class="lp-lesson"><span class="ix tnum">03</span><span>The box model</span><span class="dur">16m</span></div>
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">9 more lessons</span></div>
</div>
</div>
</div>
<!-- Course 2 -->
<div class="lp-card lp-series-card">
<div class="lp-series-head">
<span class="lp-series-n tnum">2</span>
<div>
<h3>JavaScript Essentials</h3>
<span class="lp-series-sub tnum">Course 2 · 10 lessons · ~9 hours</span>
</div>
</div>
<div class="lp-series-body">
<div class="lbl">What you'll learn</div>
<div class="lp-series-outcomes">
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Types, functions, and control flow</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Working with the DOM</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>async/await and promises</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Fetching data from APIs</span>
</div>
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-lessons">
<div class="lp-lesson"><span class="ix tnum">01</span><span>Values, types, and variables</span><span class="prev">Preview</span><span class="dur">15m</span></div>
<div class="lp-lesson"><span class="ix tnum">02</span><span>Functions and scope</span><span class="dur">17m</span></div>
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">8 more lessons</span></div>
</div>
</div>
</div>
<!-- Course 3 -->
<div class="lp-card lp-series-card">
<div class="lp-series-head">
<span class="lp-series-n tnum">3</span>
<div>
<h3>Modern Web Development with React</h3>
<span class="lp-series-sub tnum">Course 3 · 12 lessons · ~10 hours</span>
</div>
</div>
<div class="lp-series-body">
<div class="lbl">What you'll learn</div>
<div class="lp-series-outcomes">
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Components, props, and JSX</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>State and event handling</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Hooks and effects</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Building interactive UIs</span>
</div>
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-lessons">
<div class="lp-lesson"><span class="ix tnum">01</span><span>What is React?</span><span class="prev">Preview</span><span class="dur">6m</span></div>
<div class="lp-lesson"><span class="ix tnum">02</span><span>JSX &amp; rendering</span><span class="dur">11m</span></div>
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">10 more lessons</span></div>
</div>
</div>
</div>
<!-- Course 4 -->
<div class="lp-card lp-series-card">
<div class="lp-series-head">
<span class="lp-series-n tnum">4</span>
<div>
<h3>State Management &amp; Data Fetching</h3>
<span class="lp-series-sub tnum">Course 4 · 10 lessons · ~7 hours</span>
</div>
</div>
<div class="lp-series-body">
<div class="lbl">What you'll learn</div>
<div class="lp-series-outcomes">
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Context and reducers</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Caching and loading states</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Connecting React to a backend</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Error handling patterns</span>
</div>
<button class="lp-lessons-toggle">Show lesson outline<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-lessons">
<div class="lp-lesson"><span class="ix tnum">01</span><span>Lifting state up</span><span class="dur">13m</span></div>
<div class="lp-lesson" style="border-bottom: none"><span class="ix tnum">…</span><span style="color: var(--landing-fg-muted)">9 more lessons</span></div>
</div>
</div>
</div>
<!-- Course 5 -->
<div class="lp-card lp-series-card">
<div class="lp-series-head">
<span class="lp-series-n tnum">5</span>
<div>
<h3>Building &amp; Shipping a Capstone</h3>
<span class="lp-series-sub tnum">Course 5 · 7 lessons + capstone project · ~4 hours</span>
</div>
</div>
<div class="lp-series-body">
<div class="lbl">What you'll learn</div>
<div class="lp-series-outcomes">
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Scoping and planning a real project</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Deploying to production</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Code review and iteration</span>
<span class="o"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Presenting your portfolio piece</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ===== CERTIFICATE ===== -->
<section class="lp-section" id="certificate">
<div class="lp-wrap-narrow">
<div class="lp-card lp-cert">
<div class="frame"><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></div>
<div>
<h3>Earn a shareable certificate</h3>
<p>Complete all five courses — every lesson and exercise — and receive the Frontend Engineering Bootcamp certificate, ready to add to LinkedIn and your CV.</p>
</div>
</div>
</div>
</section>
<!-- ===== INSTRUCTORS ===== -->
<section class="lp-section" id="instructors">
<div class="lp-wrap-narrow">
<h2>Your instructors</h2>
<p class="lead">The tutors behind the courses in this path.</p>
<div class="lp-instructors">
<div class="lp-card lp-instructor">
<span class="av">JD</span>
<span class="nm">Jordan Diallo</span>
<span class="rl">Lead Instructor · Frontend</span>
<span class="bio">10 years building web apps; previously staff engineer at a fintech scale-up.</span>
</div>
<div class="lp-card lp-instructor">
<span class="av">EO</span>
<span class="nm">Efe Obi</span>
<span class="rl">Instructor · JavaScript</span>
<span class="bio">Teaches JS to thousands of learners; maintainer of two OSS tooling projects.</span>
</div>
<div class="lp-card lp-instructor">
<span class="av">RM</span>
<span class="nm">Rita Mensah</span>
<span class="rl">Instructor · React</span>
<span class="bio">Product engineer and design-systems specialist; capstone project mentor.</span>
</div>
</div>
</div>
</section>
<!-- ===== TESTIMONIALS ===== -->
<section class="lp-section" id="testimonials">
<div class="lp-wrap-narrow">
<h2>What learners say</h2>
<p class="lead">From people who finished the path.</p>
<div class="lp-testimonials">
<div class="lp-card lp-testimonial">
<p class="q">"I went from zero to deploying my own React app in ten weeks. The order of the courses just makes sense — nothing assumed I knew things I didn't."</p>
<div class="who"><span class="av">TB</span><div><div class="nm">Tunde Bello</div><div class="loc">Lagos, Nigeria</div></div></div>
</div>
<div class="lp-card lp-testimonial">
<p class="q">"The locked courses kept me honest — no skipping ahead, and everything built on what came before. The certificate helped me land interviews."</p>
<div class="who"><span class="av">MK</span><div><div class="nm">Mariam Kone</div><div class="loc">Abidjan, Côte d'Ivoire</div></div></div>
</div>
</div>
</div>
</section>
<!-- ===== FAQ ===== -->
<section class="lp-section" id="faq">
<div class="lp-wrap-narrow">
<h2>Frequently asked questions</h2>
<div class="lp-faq" style="margin-top: 24px">
<div class="lp-faq-item open">
<button class="lp-faq-q">Do I need any prior experience?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-faq-a">No — the path starts from absolute fundamentals and each course unlocks the next, so you're never dropped into material you're not ready for.</div>
</div>
<div class="lp-faq-item">
<button class="lp-faq-q">Can I buy a single course instead of the whole path?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-faq-a">Yes, every course is also sold individually — the path bundle saves you 29% and adds the path certificate.</div>
</div>
<div class="lp-faq-item">
<button class="lp-faq-q">Do I have to take the courses in order?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-faq-a">Yes — this path is sequential. Each course unlocks after you complete the previous one's lessons and exercises. That's what makes the curriculum build properly.</div>
</div>
<div class="lp-faq-item">
<button class="lp-faq-q">How long do I have access?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-faq-a">Lifetime. Learn at your own pace — most learners finish in 8–12 weeks at 4–5 hours a week.</div>
</div>
<div class="lp-faq-item">
<button class="lp-faq-q">What do I need to earn the certificate?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></button>
<div class="lp-faq-a">Complete every lesson and submit every exercise across all five courses, including the capstone project. The certificate is issued automatically.</div>
</div>
</div>
</div>
</section>
<!-- ===== PRICING ===== -->
<section class="lp-section" id="pricing">
<div class="lp-wrap-narrow">
<div class="lp-card lp-pricing-card">
<div class="eyebrow">Enroll</div>
<div class="lp-price tnum">$199</div>
<div class="lp-price-was tnum"><s>$280</s><span class="lp-save">Save $81 (29%)</span></div>
<ul class="lp-features">
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All 5 courses, unlocked in order</li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>52 lessons, 13 exercises, 1 capstone project</li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Path certificate on completion</li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Lifetime access</li>
</ul>
<a class="lp-btn lp-btn-primary lp-btn-lg lp-btn-block" href="lms-home.html">Enroll in this path</a>
</div>
</div>
</section>
<footer class="lp-footer">
<div class="lp-wrap lp-footer-grid">
<div>
<div class="brand"><span class="lp-nav-logo" style="width: 26px; height: 26px; font-size: 12px">A</span>Acme Academy</div>
<p class="copy">© 2026 Acme Academy</p>
</div>
<div>
<h4>Learn</h4>
<a href="public-paths.html">Learning Paths</a>
<a href="org-landing.html#courses">Courses</a>
</div>
<div>
<h4>Academy</h4>
<a href="#">About</a>
<a href="lms-home.html">Login</a>
</div>
</div>
</footer>
<button class="lp-theme-btn" id="theme" 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>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
document.querySelectorAll('.lp-lessons-toggle').forEach((btn) => {
btn.addEventListener('click', () => {
const lessons = btn.nextElementSibling;
const open = lessons.classList.toggle('open');
btn.classList.toggle('open', open);
btn.firstChild.textContent = open ? 'Hide lesson outline' : 'Show lesson outline';
});
});
document.querySelectorAll('.lp-faq-q').forEach((q) => {
q.addEventListener('click', () => q.parentElement.classList.toggle('open'));
});
// highlight anchor nav on scroll
const anchors = [...document.querySelectorAll('.lp-anchor-nav a')];
const sections = anchors.map((a) => document.querySelector(a.getAttribute('href')));
addEventListener('scroll', () => {
let current = 0;
sections.forEach((sec, i) => { if (sec && sec.getBoundingClientRect().top < 120) current = i; });
anchors.forEach((a, i) => a.classList.toggle('active', i === current));
}, { passive: true });
</script>
</body>
</html>
+155
View File
@@ -0,0 +1,155 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Learning Paths — Acme Academy</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="landing-theme.css" />
<script>
if (localStorage.cioTheme === 'dark' || (!localStorage.cioTheme && matchMedia('(prefers-color-scheme: dark)').matches))
document.documentElement.classList.add('dark');
</script>
<style>
.compact-hero { padding: 52px 0 44px; }
.compact-hero h1 { font-size: clamp(28px, 4.5vw, 40px); }
.search { max-width: 560px; margin: 0 auto; position: relative; }
.search input {
width: 100%; font: inherit; font-size: 15px; padding: 12px 16px 12px 44px;
border: 1px solid var(--landing-border); background: var(--landing-card); color: var(--landing-fg);
border-radius: var(--landing-radius-button); outline: none;
}
.search input:focus { border-color: var(--landing-accent); }
.search svg { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); width: 17px; height: 17px; stroke-width: 2; color: var(--landing-fg-muted); }
.layout { display: grid; grid-template-columns: 260px 1fr; gap: 32px; padding: 40px 0 72px; }
.filters { position: sticky; top: 20px; align-self: start; padding: 20px; }
.filters h3 { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--landing-fg-muted); font-weight: 600; margin: 0 0 10px; }
.filters .grp { padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid var(--landing-border); }
.filters .grp:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.f-opt { display: flex; align-items: center; gap: 9px; border: 1px solid var(--landing-border); padding: 8px 12px; font-size: 14px; margin-bottom: 6px; cursor: pointer; border-radius: 6px; }
.f-opt:hover { background: var(--landing-card-soft); }
.f-opt input { accent-color: var(--landing-accent); margin: 0; }
.f-opt .n { margin-left: auto; font-size: 12px; color: var(--landing-fg-muted); }
.results { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
@media (max-width: 860px) { .layout { grid-template-columns: 1fr; } .filters { position: static; } }
</style>
</head>
<body>
<div class="lp-nav-outer">
<nav class="lp-nav">
<a class="lp-nav-brand" href="org-landing.html"><span class="lp-nav-logo">A</span>Acme Academy</a>
<div class="lp-nav-links">
<a class="active" href="public-paths.html">Learning Paths</a>
<a href="org-landing.html#courses">Courses</a>
<a class="lp-nav-auth" href="lms-home.html">Login</a>
</div>
</nav>
</div>
<header class="lp-hero compact-hero">
<div class="lp-hero-dots"></div>
<div class="lp-hero-inner">
<h1>Learning Paths</h1>
<p class="sub" style="margin-bottom: 26px">Guided multi-course tracks with one enrollment, ordered courses, and a certificate at the end.</p>
<div class="search">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
<input placeholder="Search learning paths…" />
</div>
</div>
</header>
<div class="lp-wrap layout">
<!-- filters -->
<aside class="lp-card filters">
<div class="grp">
<h3>Topic</h3>
<label class="f-opt"><input type="checkbox" checked />Engineering<span class="n tnum">1</span></label>
<label class="f-opt"><input type="checkbox" checked />Data<span class="n tnum">1</span></label>
<label class="f-opt"><input type="checkbox" checked />Product<span class="n tnum">1</span></label>
</div>
<div class="grp">
<h3>Pricing</h3>
<label class="f-opt"><input type="checkbox" checked />Paid<span class="n tnum">3</span></label>
<label class="f-opt"><input type="checkbox" />Free<span class="n tnum">0</span></label>
</div>
<div class="grp">
<h3>Length</h3>
<label class="f-opt"><input type="checkbox" />Under 20 hours<span class="n tnum">1</span></label>
<label class="f-opt"><input type="checkbox" />20–40 hours<span class="n tnum">2</span></label>
</div>
</aside>
<!-- results -->
<div class="results">
<a class="lp-card lp-course-card" href="public-path.html">
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
<h3>Frontend Engineering Bootcamp</h3>
<p class="desc">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</p>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~38 hours</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>942 enrolled</span>
<span class="lp-save tnum">Save $81</span>
<span class="price tnum">$199 <s>$280</s></span>
</div>
</a>
<a class="lp-card lp-course-card" href="public-path.html">
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
<h3>Data Science with Python</h3>
<p class="desc">From Python basics to applied machine learning — pandas, visualization, and a real analysis project, in a fixed order that builds week over week.</p>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>4 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~30 hours</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>418 enrolled</span>
<span class="lp-save tnum">Save $53</span>
<span class="price tnum">$159 <s>$212</s></span>
</div>
</a>
<a class="lp-card lp-course-card" href="public-path.html">
<span class="lp-chip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Path</span>
<h3>Product Management Fundamentals</h3>
<p class="desc">Discovery, prioritization, delivery, and stakeholder craft — a five-course track for new and aspiring PMs.</p>
<div class="lp-meta-row">
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5 courses</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>~18 hours</span>
<span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>207 enrolled</span>
<span class="lp-save tnum">Save $46</span>
<span class="price tnum">$129 <s>$175</s></span>
</div>
</a>
</div>
</div>
<footer class="lp-footer">
<div class="lp-wrap lp-footer-grid">
<div>
<div class="brand"><span class="lp-nav-logo" style="width: 26px; height: 26px; font-size: 12px">A</span>Acme Academy</div>
<p class="copy">© 2026 Acme Academy</p>
</div>
<div>
<h4>Learn</h4>
<a href="public-paths.html">Learning Paths</a>
<a href="org-landing.html#courses">Courses</a>
</div>
<div>
<h4>Academy</h4>
<a href="#">About</a>
<a href="lms-home.html">Login</a>
</div>
</div>
</footer>
<button class="lp-theme-btn" id="theme" 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>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
@@ -0,0 +1,154 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Path Analytics · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 24px; }
.funnel-row { display: grid; grid-template-columns: 30px 1fr; gap: 14px; align-items: center; padding: 10px 0; }
.f-ord { width: 26px; height: 26px; border-radius: 999px; background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; font-weight: 600; font-size: 12px; }
.f-top { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 6px; gap: 10px; }
.f-name { font-size: 13.5px; font-weight: 500; }
.f-nums { font-size: 12.5px; color: var(--muted-foreground); }
.f-nums b { color: var(--foreground); font-weight: 600; }
.f-bar { height: 22px; border-radius: var(--radius-sm); background: color-mix(in oklab, var(--primary) 10%, transparent); overflow: hidden; position: relative; }
.f-bar > span { position: absolute; inset: 0 auto 0 0; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: flex-end; padding-right: 8px; font-size: 11.5px; font-weight: 600; color: var(--primary-foreground); }
.drop { font-size: 12px; color: var(--muted-foreground); display: flex; align-items: center; gap: 5px; margin-top: 5px; }
.drop svg { width: 12px; height: 12px; stroke-width: 2; }
.drop.bad { color: var(--destructive); }
.stuck { display: flex; flex-direction: column; gap: 8px; }
@media (max-width: 900px) { .stats { grid-template-columns: repeat(2, 1fr); } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
<div class="path-id">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
</div>
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
<a class="nav-item active" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
<a class="nav-item" href="teacher-path-certificate.html"><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>Certificate</a>
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
<span class="here">Analytics</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
</div>
</header>
<main class="content">
<div class="wrap" style="max-width: 920px">
<div class="page-head">
<div>
<h1 class="page-title">Analytics</h1>
<p class="page-sub">How learners are moving through the path.</p>
</div>
<select class="select" style="max-width: 160px"><option>Last 90 days</option><option>Last 30 days</option><option>All time</option></select>
</div>
<div class="stats">
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Enrolled</div><div class="v tnum">48</div><div class="s">+9 this month</div></div>
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M8 5v14l11-7z"/></svg>Active learners</div><div class="v tnum">31</div><div class="s">worked in the last 14 days</div></div>
<div class="card stat-card"><div class="k"><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>Completion rate</div><div class="v tnum">27%</div><div class="s">13 of 48 finished</div></div>
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>Avg. time to finish</div><div class="v tnum">9.4 wks</div><div class="s">across completions</div></div>
</div>
<div class="card card-pad" style="margin-bottom: 20px">
<h2 class="sec-title" style="margin-bottom: 4px">Course funnel</h2>
<p class="page-sub" style="margin-bottom: 14px">How many learners have reached and completed each course, in order.</p>
<div class="funnel-row">
<span class="f-ord tnum">1</span>
<div>
<div class="f-top"><span class="f-name">HTML &amp; CSS Foundations</span><span class="f-nums tnum"><b>44</b> completed · 3 in progress</span></div>
<div class="f-bar"><span style="width: 92%; background: var(--primary)">44</span></div>
</div>
</div>
<div class="funnel-row">
<span class="f-ord tnum">2</span>
<div>
<div class="f-top"><span class="f-name">JavaScript Essentials</span><span class="f-nums tnum"><b>36</b> completed · 6 in progress</span></div>
<div class="f-bar"><span style="width: 75%; background: var(--primary)">36</span></div>
<div class="drop"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>8 learners dropped after Course 1</div>
</div>
</div>
<div class="funnel-row">
<span class="f-ord tnum">3</span>
<div>
<div class="f-top"><span class="f-name">Modern Web Development with React</span><span class="f-nums tnum"><b>22</b> completed · 9 in progress</span></div>
<div class="f-bar"><span style="width: 46%; background: var(--primary)">22</span></div>
<div class="drop bad"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>14 learners dropped after Course 2 — biggest drop-off</div>
</div>
</div>
<div class="funnel-row">
<span class="f-ord tnum">4</span>
<div>
<div class="f-top"><span class="f-name">State Management &amp; Data Fetching</span><span class="f-nums tnum"><b>16</b> completed · 4 in progress</span></div>
<div class="f-bar"><span style="width: 33%; background: var(--primary)">16</span></div>
</div>
</div>
<div class="funnel-row">
<span class="f-ord tnum">5</span>
<div>
<div class="f-top"><span class="f-name">Building &amp; Shipping a Capstone</span><span class="f-nums tnum"><b>13</b> completed · 2 in progress</span></div>
<div class="f-bar"><span style="width: 27%; background: var(--success)">13</span></div>
<div class="drop" style="color: var(--success)"><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>13 certificates awarded</div>
</div>
</div>
</div>
<div class="card card-pad">
<h2 class="sec-title" style="margin-bottom: 4px">Where learners are stuck</h2>
<p class="page-sub" style="margin-bottom: 14px">Lessons and exercises blocking the most learners right now.</p>
<div class="stuck">
<div class="item item-muted" style="padding: 12px 14px">
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></div>
<div class="item-content">
<span class="item-title">Exercise: Build a to-do app · React</span>
<span class="item-desc">7 learners have had this exercise in progress for over 2 weeks.</span>
</div>
<span class="badge badge-warning" style="background: var(--warning-soft); color: var(--warning)">7 stuck</span>
</div>
<div class="item item-muted" style="padding: 12px 14px">
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg></div>
<div class="item-content">
<span class="item-title">Lesson: The useEffect hook · React</span>
<span class="item-desc">5 learners stopped at this lesson.</span>
</div>
<span class="badge badge-warning" style="background: var(--warning-soft); color: var(--warning)">5 stuck</span>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
@@ -0,0 +1,216 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Path Courses · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.rule { display: flex; align-items: center; gap: 13px; padding: 14px 16px; margin: 18px 0; }
.rule .ico { width: 34px; height: 34px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 10%, transparent); display: grid; place-items: center; color: var(--primary); flex-shrink: 0; }
.rule .ico svg { width: 16px; height: 16px; stroke-width: 2.2; }
.rule .txt { flex: 1; }
.rule .txt b { font-size: 14px; font-weight: 600; }
.rule .txt p { margin: 1px 0 0; font-size: 13px; color: var(--muted-foreground); }
.list-head { display: flex; align-items: center; margin: 20px 2px 12px; }
.list-head h2 { font-size: 14px; font-weight: 600; margin: 0; }
.list-head .hint { margin-left: auto; font-size: 12.5px; color: var(--muted-foreground); display: flex; align-items: center; gap: 6px; }
.list-head .hint svg { width: 14px; height: 14px; stroke-width: 2; }
.courses { display: flex; flex-direction: column; gap: 8px; }
.row { display: grid; grid-template-columns: 24px 32px 60px 1fr auto; align-items: center; gap: 13px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; box-shadow: var(--shadow-2xs); transition: opacity 0.12s, border-color 0.12s, box-shadow 0.12s; }
.row.dragging { opacity: 0.4; }
.row.dragover { border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary) 15%, transparent); }
.grip { color: var(--muted-foreground); cursor: grab; display: grid; place-items: center; }
.grip:active { cursor: grabbing; }
.grip svg { width: 16px; height: 16px; stroke-width: 2; }
.ord { width: 28px; height: 28px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; font-weight: 600; font-size: 13px; }
.thumb { width: 60px; height: 42px; border-radius: var(--radius-md); }
.r-title { font-size: 14px; font-weight: 500; margin: 0; }
.r-meta { font-size: 12px; color: var(--muted-foreground); margin: 2px 0 0; display: flex; align-items: center; gap: 12px; }
.r-meta .m { display: flex; align-items: center; gap: 4px; }
.r-meta svg { width: 12px; height: 12px; stroke-width: 2; }
.r-actions { display: flex; align-items: center; gap: 2px; }
.mini { width: 30px; height: 30px; border-radius: var(--radius-md); border: none; background: transparent; display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; }
.mini:hover { background: var(--accent); color: var(--foreground); }
.mini.danger:hover { color: var(--destructive); background: color-mix(in oklab, var(--destructive) 10%, transparent); }
.mini svg { width: 15px; height: 15px; stroke-width: 2; }
.add-course { display: flex; align-items: center; justify-content: center; gap: 8px; border: 1px dashed var(--border); border-radius: var(--radius-md); padding: 13px; color: var(--muted-foreground); font-weight: 500; font-size: 13.5px; cursor: pointer; margin-top: 8px; background: transparent; width: 100%; }
.add-course:hover { border-color: var(--primary); color: var(--primary); background: color-mix(in oklab, var(--primary) 5%, transparent); }
.add-course svg { width: 16px; height: 16px; stroke-width: 2.2; }
.cert-row { display: grid; grid-template-columns: 24px 32px 60px 1fr auto; align-items: center; gap: 13px; padding: 12px 14px; border: 1px dashed var(--border); border-radius: var(--radius-md); margin-top: 8px; color: var(--muted-foreground); }
.cert-row .ord { background: var(--muted); color: var(--muted-foreground); border-radius: 999px; }
.cert-row .ord svg { width: 14px; height: 14px; stroke-width: 2; }
@media (max-width: 720px) { .row, .cert-row { grid-template-columns: 22px 28px 1fr auto; } .thumb { display: none; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
<div class="path-id">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
</div>
<a class="nav-item active" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
<a class="nav-item" href="teacher-path-certificate.html"><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>Certificate</a>
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
<span class="here">Frontend Engineering Bootcamp</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
<a class="btn btn-outline btn-sm" href="teacher-path-setup.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>Finish setup · 33%</a>
<a class="btn btn-outline btn-sm" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>Preview as student</a>
</div>
</header>
<main class="content">
<div class="wrap-narrow" style="max-width: 820px">
<div class="page-head" style="margin-bottom: 4px">
<div>
<h1 class="page-title">Courses</h1>
<p class="page-sub">Add courses and drag to set the order students move through them.</p>
</div>
</div>
<div class="card rule">
<div class="ico"><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="txt">
<b>Unlock courses in order</b>
<p>Each course stays locked until a student completes the previous one's lessons and exercises. Turn off to allow any order.</p>
</div>
<label class="switch"><input type="checkbox" checked aria-label="Unlock courses in order" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="list-head">
<h2>5 courses in this path</h2>
<span class="hint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg>Drag to reorder</span>
</div>
<div class="courses" id="courses">
<div class="row" draggable="true">
<span class="grip" aria-label="Drag to reorder"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
<span class="ord tnum">1</span>
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.705 0.213 47.604), oklch(0.75 0.183 55.934))"></span>
<div>
<h3 class="r-title">HTML &amp; CSS Foundations</h3>
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>12 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>2 exercises</span><span class="m">$49</span></p>
</div>
<div class="r-actions">
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
</div>
</div>
<div class="row" draggable="true">
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
<span class="ord tnum">2</span>
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.795 0.184 86.047), oklch(0.769 0.188 70.08))"></span>
<div>
<h3 class="r-title">JavaScript Essentials</h3>
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>10 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>3 exercises</span><span class="m">$59</span></p>
</div>
<div class="r-actions">
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
</div>
</div>
<div class="row" draggable="true">
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
<span class="ord tnum">3</span>
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.685 0.169 237.323), oklch(0.488 0.243 264.376))"></span>
<div>
<h3 class="r-title">Modern Web Development with React</h3>
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>12 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>4 exercises</span><span class="m">$79</span></p>
</div>
<div class="r-actions">
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
</div>
</div>
<div class="row" draggable="true">
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
<span class="ord tnum">4</span>
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.585 0.233 277.117), oklch(0.606 0.25 292.717))"></span>
<div>
<h3 class="r-title">State Management &amp; Data Fetching</h3>
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>10 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>3 exercises</span><span class="m">$59</span></p>
</div>
<div class="r-actions">
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
</div>
</div>
<div class="row" draggable="true">
<span class="grip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></span>
<span class="ord tnum">5</span>
<span class="thumb" style="background: linear-gradient(135deg, oklch(0.645 0.246 16.439), oklch(0.586 0.253 17.585))"></span>
<div>
<h3 class="r-title">Building &amp; Shipping a Capstone</h3>
<p class="r-meta"><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>7 lessons</span><span class="m"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>1 capstone</span><span class="m">$34</span></p>
</div>
<div class="r-actions">
<button class="mini" title="Open course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg></button>
<button class="mini danger" title="Remove from path"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button>
</div>
</div>
</div>
<button class="add-course"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add course to path</button>
<div class="cert-row">
<span></span>
<span class="ord"><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></span>
<span></span>
<div><h3 class="r-title" style="color: var(--foreground)">Path certificate</h3><p class="r-meta">Awarded automatically when a student completes all 5 courses.</p></div>
<div class="r-actions"><a class="mini" href="teacher-path-certificate.html" title="Configure certificate"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2"/></svg></a></div>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
const listEl = document.getElementById('courses');
let dragEl = null;
listEl.querySelectorAll('.row').forEach((row) => {
row.addEventListener('dragstart', () => { dragEl = row; row.classList.add('dragging'); });
row.addEventListener('dragend', () => {
row.classList.remove('dragging');
listEl.querySelectorAll('.row').forEach((r) => r.classList.remove('dragover'));
listEl.querySelectorAll('.row .ord').forEach((el, i) => { el.textContent = i + 1; });
});
row.addEventListener('dragover', (e) => {
e.preventDefault();
if (row === dragEl) return;
const rect = row.getBoundingClientRect();
const after = e.clientY > rect.top + rect.height / 2;
listEl.querySelectorAll('.row').forEach((r) => r.classList.remove('dragover'));
row.classList.add('dragover');
listEl.insertBefore(dragEl, after ? row.nextSibling : row);
});
});
</script>
</body>
</html>
@@ -0,0 +1,127 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Path Certificate · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.fset { margin-top: 16px; }
.fset-head { display: flex; align-items: center; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.fset-head h2 { font-size: 14.5px; font-weight: 600; margin: 0; }
.fset-head p { font-size: 12.5px; color: var(--muted-foreground); margin: 2px 0 0; }
.fset-body { padding: 18px 20px; }
/* certificate preview */
.cert-frame { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 28px; background: var(--background); position: relative; }
.cert-frame::before { content: ''; position: absolute; inset: 8px; border: 1px solid color-mix(in oklab, var(--primary) 30%, transparent); border-radius: var(--radius-sm); pointer-events: none; }
.cert-inner { text-align: center; padding: 12px 8px; }
.cert-org { font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted-foreground); margin-bottom: 14px; }
.cert-title { font-size: 20px; font-weight: 600; letter-spacing: -0.01em; margin: 0 0 4px; }
.cert-sub { font-size: 12.5px; color: var(--muted-foreground); margin: 0 0 14px; }
.cert-name { font-size: 17px; font-weight: 500; border-bottom: 1px solid var(--border); display: inline-block; padding: 0 24px 6px; margin-bottom: 14px; }
.cert-meta { display: flex; justify-content: center; gap: 28px; font-size: 11.5px; color: var(--muted-foreground); }
.cert-seal { width: 44px; height: 44px; border-radius: 999px; background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; margin: 0 auto 12px; }
.cert-seal svg { width: 22px; height: 22px; stroke-width: 2; }
.req { display: flex; align-items: center; gap: 8px; font-size: 13px; margin-bottom: 8px; }
.req svg { width: 15px; height: 15px; stroke-width: 2.2; color: var(--success); flex-shrink: 0; }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
<div class="path-id">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
</div>
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
<a class="nav-item active" href="teacher-path-certificate.html"><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>Certificate</a>
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
<span class="here">Certificate</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
</div>
</header>
<main class="content">
<div class="wrap-narrow">
<div class="page-head" style="margin-bottom: 6px">
<div>
<h1 class="page-title">Certificate</h1>
<p class="page-sub">Award a path-level certificate when a learner completes every course.</p>
</div>
</div>
<section class="card fset">
<div class="fset-head">
<div style="flex: 1"><h2>Award a path certificate</h2><p>Issued automatically on completion and shown in the learner's Certificates page.</p></div>
<label class="switch"><input type="checkbox" checked aria-label="Award a path certificate" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="fset-body">
<div class="req"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All 5 courses completed — every lesson finished</div>
<div class="req"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>All exercises submitted or passed in each course</div>
<p class="hint" style="margin-top: 10px">Completion rules follow the path's unlock rule (lessons + exercises). 13 certificates awarded so far.</p>
</div>
</section>
<section class="card fset">
<div class="fset-head"><div><h2>Certificate details</h2><p>What appears on the issued certificate.</p></div></div>
<div class="fset-body">
<div class="field">
<label class="label" for="ct">Certificate title</label>
<input class="input" id="ct" value="Frontend Engineering Bootcamp Certificate" />
</div>
<div class="field">
<label class="label" for="cs">Issued by</label>
<input class="input" id="cs" value="Acme Academy" />
</div>
<div class="field">
<span class="label">Preview</span>
<div class="cert-frame">
<div class="cert-inner">
<div class="cert-seal"><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></div>
<div class="cert-org">Acme Academy</div>
<h3 class="cert-title">Frontend Engineering Bootcamp Certificate</h3>
<p class="cert-sub">This certifies that</p>
<div class="cert-name">Ada Okafor</div>
<p class="cert-sub">has successfully completed all 5 courses in the Frontend Engineering Bootcamp learning path.</p>
<div class="cert-meta tnum"><span>Issued · Jul 25, 2026</span><span>ID · LP-8F42-19AC</span></div>
</div>
</div>
</div>
<div style="display: flex; gap: 8px; justify-content: flex-end">
<button class="btn btn-ghost btn-sm">Discard</button>
<button class="btn btn-primary btn-sm">Save changes</button>
</div>
</div>
</section>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
@@ -0,0 +1,227 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Path Landing Page · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.fset { margin-top: 16px; }
.fset-head { display: flex; align-items: center; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.fset-head h2 { font-size: 14.5px; font-weight: 600; margin: 0; flex: 1; }
.fset-head p { font-size: 12.5px; color: var(--muted-foreground); margin: 2px 0 0; }
.fset-body { padding: 18px 20px; }
.bullet-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.bullet-row svg { width: 15px; height: 15px; color: var(--success); stroke-width: 2.2; flex-shrink: 0; }
.bullet-row .mini { margin-left: auto; }
.tag-row { display: flex; flex-wrap: wrap; gap: 8px; }
.tag { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); border-radius: 999px; padding: 4px 12px; font-size: 13px; }
.tag button { border: none; background: none; color: var(--muted-foreground); cursor: pointer; display: grid; place-items: center; padding: 0; }
.tag button svg { width: 12px; height: 12px; stroke-width: 2.4; }
.mini { width: 28px; height: 28px; border-radius: var(--radius-md); border: none; background: transparent; display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; flex-shrink: 0; }
.mini:hover { background: var(--accent); color: var(--foreground); }
.mini svg { width: 14px; height: 14px; stroke-width: 2; }
.add-inline { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; color: var(--primary); background: none; border: none; cursor: pointer; padding: 6px 0 0; }
.add-inline svg { width: 14px; height: 14px; stroke-width: 2.2; }
.radio-card { display: flex; align-items: flex-start; gap: 12px; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; cursor: pointer; margin-bottom: 8px; }
.radio-card:hover { background: color-mix(in oklab, var(--accent) 50%, transparent); }
.radio-card.sel { border-color: var(--primary); background: color-mix(in oklab, var(--primary) 5%, transparent); }
.rdot { width: 16px; height: 16px; border-radius: 999px; border: 1.5px solid var(--input); flex-shrink: 0; margin-top: 2px; display: grid; place-items: center; }
.radio-card.sel .rdot { border-color: var(--primary); }
.radio-card.sel .rdot::after { content: ''; width: 8px; height: 8px; border-radius: 999px; background: var(--primary); }
.rt { font-size: 13.5px; font-weight: 500; }
.rd { font-size: 12.5px; color: var(--muted-foreground); margin-top: 1px; }
.savebar { position: sticky; bottom: 12px; margin-top: 20px; background: color-mix(in oklab, var(--background) 94%, transparent); backdrop-filter: blur(8px); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 10px 14px; display: flex; align-items: center; gap: 12px; box-shadow: var(--shadow-md); }
.savebar .msg { font-size: 13px; color: var(--muted-foreground); }
.savebar .actions { margin-left: auto; display: flex; gap: 8px; }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
<div class="path-id">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
</div>
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
<a class="nav-item active" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
<a class="nav-item" href="teacher-path-certificate.html"><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>Certificate</a>
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
<span class="here">Landing page</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
<a class="btn btn-outline btn-sm" href="public-path.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></svg>View live page</a>
</div>
</header>
<main class="content">
<div class="wrap-narrow">
<div class="page-head" style="margin-bottom: 6px">
<div>
<h1 class="page-title">Landing page</h1>
<p class="page-sub">Control what visitors see on the public path page at <span style="color: var(--foreground)">/path/frontend-engineering-bootcamp</span>.</p>
</div>
</div>
<!-- Hero -->
<section class="card fset">
<div class="fset-head"><div><h2>Hero</h2><p>The headline visitors see first.</p></div></div>
<div class="fset-body">
<div class="field">
<label class="label" for="hl">Headline</label>
<input class="input" id="hl" value="Become a job-ready frontend engineer" />
</div>
<div class="field">
<label class="label" for="sub">Subheadline</label>
<textarea class="textarea" id="sub">Five courses, one path — from your first HTML tag to a deployed React capstone. Learn in order, build real projects, earn a certificate.</textarea>
</div>
</div>
</section>
<!-- Visitor access -->
<section class="card fset">
<div class="fset-head"><div><h2>Visitor access</h2><p>How much of the path a non-enrolled visitor can explore.</p></div></div>
<div class="fset-body">
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Teaser only</span><span class="rd" style="display: block">Path description, course titles, and price — no lesson detail.</span></span></label>
<label class="radio-card sel"><span class="rdot"></span><span><span class="rt">Full syllabus</span><span class="rd" style="display: block">Visitors see every course and its lesson outline, but no content.</span></span></label>
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Syllabus + preview lessons</span><span class="rd" style="display: block">Full outline, plus lessons marked as previews are free to open.</span></span></label>
</div>
</section>
<!-- What you'll learn -->
<section class="card fset">
<div class="fset-head"><div><h2>What you'll learn</h2><p>Outcome bullets shown near the top of the page.</p></div></div>
<div class="fset-body">
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Build responsive, accessible websites with semantic HTML and modern CSS" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Write production JavaScript: async, APIs, and the DOM" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Build and ship interactive React apps with state, hooks, and data fetching" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
<div class="bullet-row"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg><input class="input" value="Complete a portfolio-ready capstone project, deployed to production" /><button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></div>
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add outcome</button>
</div>
</section>
<!-- Skills -->
<section class="card fset">
<div class="fset-head"><div><h2>Skills</h2><p>Tags shown as "Skills you'll gain".</p></div></div>
<div class="fset-body">
<div class="tag-row">
<span class="tag">HTML &amp; CSS<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
<span class="tag">Flexbox &amp; Grid<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
<span class="tag">JavaScript<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
<span class="tag">REST APIs<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
<span class="tag">React<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
<span class="tag">State management<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
<span class="tag">Deployment<button><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
</div>
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add skill</button>
</div>
</section>
<!-- Instructors -->
<section class="card fset">
<div class="fset-head">
<div style="flex: 1"><h2>Instructors</h2><p>Pulled from the tutors of the courses in this path.</p></div>
<label class="switch"><input type="checkbox" checked aria-label="Show instructors" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="fset-body" style="display: flex; gap: 10px; flex-wrap: wrap">
<span class="badge badge-outline" style="padding: 6px 12px"><span class="avatar" style="width: 20px; height: 20px; font-size: 9px">JD</span>Jordan Diallo</span>
<span class="badge badge-outline" style="padding: 6px 12px"><span class="avatar" style="width: 20px; height: 20px; font-size: 9px">EO</span>Efe Obi</span>
<span class="badge badge-outline" style="padding: 6px 12px"><span class="avatar" style="width: 20px; height: 20px; font-size: 9px">RM</span>Rita Mensah</span>
</div>
</section>
<!-- Testimonials -->
<section class="card fset">
<div class="fset-head">
<div style="flex: 1"><h2>Testimonials</h2><p>Learner quotes shown on the public page.</p></div>
<label class="switch"><input type="checkbox" checked aria-label="Show testimonials" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="fset-body">
<div class="item item-outline" style="padding: 12px 14px; margin-bottom: 8px">
<span class="avatar">TB</span>
<div class="item-content">
<span class="item-title">Tunde Bello</span>
<span class="item-desc">"I went from zero to deploying my own React app in ten weeks. The order of the courses just makes sense."</span>
</div>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
</div>
<div class="item item-outline" style="padding: 12px 14px">
<span class="avatar">MK</span>
<div class="item-content">
<span class="item-title">Mariam Kone</span>
<span class="item-desc">"The locked courses kept me honest — no skipping ahead, and everything built on what came before."</span>
</div>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
</div>
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add testimonial</button>
</div>
</section>
<!-- FAQ -->
<section class="card fset">
<div class="fset-head">
<div style="flex: 1"><h2>FAQ</h2><p>Collapsible questions at the bottom of the page.</p></div>
<label class="switch"><input type="checkbox" checked aria-label="Show FAQ" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="fset-body">
<div class="item item-outline" style="padding: 12px 14px; margin-bottom: 8px">
<div class="item-content">
<span class="item-title">Do I need any prior experience?</span>
<span class="item-desc">No — the path starts from absolute fundamentals and each course unlocks the next.</span>
</div>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
</div>
<div class="item item-outline" style="padding: 12px 14px">
<div class="item-content">
<span class="item-title">Can I buy a single course instead?</span>
<span class="item-desc">Yes, every course is also sold individually — the path bundle saves you 29%.</span>
</div>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></svg></button>
</div>
<button class="add-inline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Add question</button>
</div>
</section>
<div class="savebar">
<span class="msg">Unsaved changes</span>
<div class="actions">
<button class="btn btn-ghost btn-sm">Discard</button>
<button class="btn btn-primary btn-sm">Save changes</button>
</div>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
document.querySelectorAll('.radio-card').forEach((r) => {
r.addEventListener('click', () => {
document.querySelector('.radio-card.sel')?.classList.remove('sel');
r.classList.add('sel');
});
});
</script>
</body>
</html>
@@ -0,0 +1,139 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Path People · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.toolbar { display: flex; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
.toolbar .input { max-width: 280px; }
.grid-cols { grid-template-columns: 1.8fr 1.4fr 1.1fr 0.8fr 36px; }
.person { display: flex; align-items: center; gap: 10px; min-width: 0; }
.person .nm { font-size: 14px; font-weight: 500; }
.person .em { font-size: 12px; color: var(--muted-foreground); }
.prog-cell { display: flex; align-items: center; gap: 10px; }
.prog-cell .p { font-size: 12.5px; font-weight: 600; min-width: 34px; text-align: right; }
.cur { font-size: 13px; color: var(--foreground); display: flex; align-items: center; gap: 6px; min-width: 0; }
.cur .n { width: 20px; height: 20px; border-radius: 999px; background: color-mix(in oklab, var(--primary) 10%, transparent); color: var(--primary); display: grid; place-items: center; font-size: 11px; font-weight: 600; flex-shrink: 0; }
.cur span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mini { width: 30px; height: 30px; border-radius: var(--radius-md); border: none; background: transparent; display: grid; place-items: center; color: var(--muted-foreground); cursor: pointer; }
.mini:hover { background: var(--accent); color: var(--foreground); }
.mini svg { width: 15px; height: 15px; stroke-width: 2; }
.note-banner { display: flex; align-items: center; gap: 10px; padding: 11px 14px; border-radius: var(--radius-md); background: color-mix(in oklab, var(--primary) 7%, transparent); border: 1px solid color-mix(in oklab, var(--primary) 20%, transparent); font-size: 13px; color: var(--foreground); margin-bottom: 16px; }
.note-banner svg { width: 15px; height: 15px; stroke-width: 2; color: var(--primary); flex-shrink: 0; }
@media (max-width: 860px) { .thead { display: none; } .trow.grid-cols { grid-template-columns: 1fr auto; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
<div class="path-id">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
</div>
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
<a class="nav-item active" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
<a class="nav-item" href="teacher-path-certificate.html"><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>Certificate</a>
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
<span class="here">People</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
</div>
</header>
<main class="content">
<div class="wrap" style="max-width: 980px">
<div class="page-head">
<div>
<h1 class="page-title">People</h1>
<p class="page-sub">48 learners enrolled in this path.</p>
</div>
<a class="btn btn-primary"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M19 8v6M22 11h-6"/></svg>Add learners</a>
</div>
<div class="note-banner">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg>
Adding a learner to this path automatically enrolls them in all 5 courses. Removing them preserves their course access and progress.
</div>
<div class="toolbar">
<input class="input" placeholder="Search by name or email…" />
<select class="select" style="max-width: 180px">
<option>All progress</option><option>Not started</option><option>In progress</option><option>Completed</option>
</select>
</div>
<div class="card" style="overflow: hidden">
<div class="thead grid-cols"><span>Learner</span><span>Path progress</span><span>Current course</span><span>Enrolled</span><span></span></div>
<div class="trow grid-cols">
<div class="person"><span class="avatar">AO</span><div style="min-width: 0"><div class="nm">Ada Okafor</div><div class="em">a•••@gmail.com</div></div></div>
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 49%"></span></div><span class="p tnum">49%</span></div>
<span class="cur"><span class="n tnum">3</span><span>React</span></span>
<span class="text-muted tnum" style="font-size: 13px">May 2</span>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
</div>
<div class="trow grid-cols">
<div class="person"><span class="avatar">TB</span><div style="min-width: 0"><div class="nm">Tunde Bello</div><div class="em">t•••@yahoo.com</div></div></div>
<div class="prog-cell"><div class="progress progress-thin progress-success"><span style="width: 100%"></span></div><span class="p tnum" style="color: var(--success)">100%</span></div>
<span class="badge badge-success-soft"><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>Certificate earned</span>
<span class="text-muted tnum" style="font-size: 13px">Mar 18</span>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
</div>
<div class="trow grid-cols">
<div class="person"><span class="avatar">MK</span><div style="min-width: 0"><div class="nm">Mariam Kone</div><div class="em">m•••@outlook.com</div></div></div>
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 74%"></span></div><span class="p tnum">74%</span></div>
<span class="cur"><span class="n tnum">4</span><span>State &amp; Data</span></span>
<span class="text-muted tnum" style="font-size: 13px">Apr 11</span>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
</div>
<div class="trow grid-cols">
<div class="person"><span class="avatar">SD</span><div style="min-width: 0"><div class="nm">Sam Diallo</div><div class="em">s•••@gmail.com</div></div></div>
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 12%"></span></div><span class="p tnum">12%</span></div>
<span class="cur"><span class="n tnum">1</span><span>HTML &amp; CSS</span></span>
<span class="text-muted tnum" style="font-size: 13px">Jul 8</span>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
</div>
<div class="trow grid-cols">
<div class="person"><span class="avatar">LN</span><div style="min-width: 0"><div class="nm">Lara Nwosu</div><div class="em">l•••@proton.me</div></div></div>
<div class="prog-cell"><div class="progress progress-thin"><span style="width: 0%"></span></div><span class="p tnum">0%</span></div>
<span class="badge badge-muted">Not started</span>
<span class="text-muted tnum" style="font-size: 13px">Jul 21</span>
<button class="mini"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></button>
</div>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
@@ -0,0 +1,216 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Path Settings · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.fset { margin-top: 16px; }
.fset-head { padding: 16px 20px; border-bottom: 1px solid var(--border); }
.fset-head h2 { font-size: 14.5px; font-weight: 600; margin: 0; }
.fset-head p { font-size: 12.5px; color: var(--muted-foreground); margin: 2px 0 0; }
.fset-body { padding: 18px 20px; }
.cover-pick { display: flex; gap: 14px; align-items: center; }
.cover-prev { width: 150px; height: 84px; border-radius: var(--radius-md); flex-shrink: 0; background: radial-gradient(120% 150% at 10% -20%, oklch(0.623 0.214 259.815) 0%, transparent 55%), linear-gradient(120deg, oklch(0.488 0.243 264.376), oklch(0.546 0.245 262.881)); }
.trow2 { display: flex; align-items: center; gap: 14px; padding: 4px 0; }
.trow2 .tt { font-size: 14px; font-weight: 500; }
.trow2 .td { font-size: 12.5px; color: var(--muted-foreground); margin-top: 2px; }
.trow2 .grow { flex: 1; }
.sep { height: 1px; background: var(--border); margin: 14px 0; }
.price-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.save-note { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 10px 12px; border-radius: var(--radius-md); background: var(--success-soft); color: var(--success); font-size: 13px; font-weight: 500; }
.save-note svg { width: 15px; height: 15px; stroke-width: 2.2; flex-shrink: 0; }
.radio-card { display: flex; align-items: flex-start; gap: 12px; border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; cursor: pointer; margin-bottom: 8px; }
.radio-card.sel { border-color: var(--primary); background: color-mix(in oklab, var(--primary) 5%, transparent); }
.rdot { width: 16px; height: 16px; border-radius: 999px; border: 1.5px solid var(--input); flex-shrink: 0; margin-top: 2px; display: grid; place-items: center; }
.radio-card.sel .rdot { border-color: var(--primary); }
.radio-card.sel .rdot::after { content: ''; width: 8px; height: 8px; border-radius: 999px; background: var(--primary); }
.rt { font-size: 13.5px; font-weight: 500; display: flex; align-items: center; gap: 8px; }
.rd { font-size: 12.5px; color: var(--muted-foreground); margin-top: 1px; display: block; }
.danger-zone { border-color: color-mix(in oklab, var(--destructive) 35%, transparent); }
.danger-zone .fset-head h2 { color: var(--destructive); }
.savebar { position: sticky; bottom: 12px; margin-top: 20px; background: color-mix(in oklab, var(--background) 94%, transparent); backdrop-filter: blur(8px); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 10px 14px; display: flex; align-items: center; gap: 12px; box-shadow: var(--shadow-md); }
.savebar .msg { font-size: 13px; color: var(--muted-foreground); }
.savebar .actions { margin-left: auto; display: flex; gap: 8px; }
@media (max-width: 680px) { .price-row { grid-template-columns: 1fr; } .cover-pick { flex-direction: column; align-items: stretch; } .cover-prev { width: 100%; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
<div class="path-id">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-active"><span class="dot"></span>Active</div></div>
</div>
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">48</span></a>
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
<a class="nav-item" href="teacher-path-certificate.html"><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>Certificate</a>
<a class="nav-item active" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
<span class="here">Settings</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
<a class="btn btn-outline btn-sm" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>Preview as student</a>
</div>
</header>
<main class="content">
<div class="wrap-narrow">
<div class="page-head" style="margin-bottom: 6px">
<div>
<h1 class="page-title">Settings</h1>
<p class="page-sub">Manage how this path appears, is priced, and behaves for learners.</p>
</div>
</div>
<!-- General -->
<section class="card fset">
<div class="fset-head"><h2>General</h2><p>The name, summary, and cover learners see across the LMS.</p></div>
<div class="fset-body">
<div class="field">
<label class="label" for="nm">Path name</label>
<input class="input" id="nm" value="Frontend Engineering Bootcamp" />
</div>
<div class="field">
<label class="label" for="ds">Description</label>
<textarea class="textarea" id="ds">A guided, five-course track that takes you from markup fundamentals to shipping a production React app. Finish in order to earn your certificate.</textarea>
</div>
<div class="field">
<span class="label">Cover image</span>
<div class="cover-pick">
<div class="cover-prev"></div>
<div style="display: flex; flex-direction: column; gap: 8px; align-items: flex-start">
<button class="btn btn-outline btn-sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8l-5-5-5 5M12 3v12"/></svg>Upload image</button>
<span class="hint">PNG or JPG, at least 1200×480px.</span>
</div>
</div>
</div>
</div>
</section>
<!-- Pricing -->
<section class="card fset">
<div class="fset-head"><h2>Pricing</h2><p>One bundle price for the whole path. Enrolling unlocks every course.</p></div>
<div class="fset-body">
<div class="price-row">
<div class="field" style="margin-bottom: 0">
<label class="label" for="pr">Path price</label>
<input class="input tnum" id="pr" value="$199" />
</div>
<div class="field" style="margin-bottom: 0">
<label class="label" for="cur">Currency</label>
<select class="select" id="cur"><option>USD</option><option>EUR</option><option>NGN</option></select>
</div>
</div>
<div class="sep"></div>
<div class="trow2">
<div class="grow">
<div class="tt">Show savings vs individual courses</div>
<div class="td tnum">Courses sum to $280 — the page will show "Save $81 (29%)".</div>
</div>
<label class="switch"><input type="checkbox" checked aria-label="Show savings" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="save-note tnum">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
Learners see: $199 <s style="opacity: 0.7">$280</s> · Save $81 vs buying each course
</div>
</div>
</section>
<!-- Enrollment & flow -->
<section class="card fset">
<div class="fset-head"><h2>Enrollment &amp; flow</h2><p>How learners join and move through the path.</p></div>
<div class="fset-body">
<div class="trow2">
<div class="grow">
<div class="tt">Self-enrollment from the landing page</div>
<div class="td">Visitors can buy or join this path from your public site. Turn off for admin-managed enrollment only.</div>
</div>
<label class="switch"><input type="checkbox" checked aria-label="Self-enrollment" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="sep"></div>
<div class="trow2">
<div class="grow">
<div class="tt">Unlock courses in order</div>
<div class="td">Each course unlocks after the previous one's lessons and exercises are complete.</div>
</div>
<label class="switch"><input type="checkbox" checked aria-label="Unlock in order" /><span class="track"></span><span class="knob"></span></label>
</div>
<div class="sep"></div>
<div class="trow2">
<div class="grow">
<div class="tt">Auto-enroll in path courses</div>
<div class="td">Joining the path enrolls the learner in every course it contains.</div>
</div>
<label class="switch"><input type="checkbox" checked aria-label="Auto-enroll" /><span class="track"></span><span class="knob"></span></label>
</div>
</div>
</section>
<!-- Status -->
<section class="card fset">
<div class="fset-head"><h2>Status &amp; visibility</h2><p>Controls whether learners can see and join this path.</p></div>
<div class="fset-body">
<label class="radio-card sel"><span class="rdot"></span><span><span class="rt">Active <span class="badge badge-success-soft">Visible</span></span><span class="rd">Live on your landing page and in the LMS for enrolled learners.</span></span></label>
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Draft <span class="badge badge-muted">Hidden</span></span><span class="rd">Hidden from visitors and learners while you build it.</span></span></label>
<label class="radio-card"><span class="rdot"></span><span><span class="rt">Archived <span class="badge badge-muted">Off catalog</span></span><span class="rd">Removed everywhere. Learner progress and course access are preserved.</span></span></label>
</div>
</section>
<!-- Danger -->
<section class="card fset danger-zone">
<div class="fset-head"><h2>Danger zone</h2></div>
<div class="fset-body">
<div class="trow2">
<div class="grow">
<div class="tt">Delete this path</div>
<div class="td">Permanently removes the path and its landing page. Courses, enrollments, and learner progress are not deleted.</div>
</div>
<button class="btn btn-destructive btn-sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg>Delete path</button>
</div>
</div>
</section>
<div class="savebar">
<span class="msg">Unsaved changes</span>
<div class="actions">
<button class="btn btn-ghost btn-sm">Discard</button>
<button class="btn btn-primary btn-sm">Save changes</button>
</div>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
document.querySelectorAll('.radio-card').forEach((r) => {
r.addEventListener('click', () => {
document.querySelector('.radio-card.sel')?.classList.remove('sel');
r.classList.add('sel');
});
});
</script>
</body>
</html>
@@ -0,0 +1,157 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Set up your path · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.gs-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin: 8px 0 20px; }
.list { display: flex; flex-direction: column; gap: 8px; }
.summary-cnt { display: flex; align-items: center; gap: 10px; }
.launch { margin-top: 20px; display: flex; align-items: center; gap: 14px; padding: 16px 18px; flex-wrap: wrap; }
.launch .txt { flex: 1; min-width: 220px; }
.launch .txt b { font-size: 14px; font-weight: 600; }
.launch .txt p { margin: 1px 0 0; font-size: 13px; color: var(--muted-foreground); }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<a class="back-link" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>All Learning Paths</a>
<div class="path-id">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></div>
<div><div class="nm">Frontend Engineering Bootcamp</div><div class="st st-draft"><span class="dot"></span>Draft</div></div>
</div>
<a class="nav-item" href="teacher-path-builder.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses<span class="nav-tail tnum">5</span></a>
<a class="nav-item" href="teacher-path-people.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>People<span class="nav-tail tnum">0</span></a>
<a class="nav-item" href="teacher-path-analytics.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>Analytics</a>
<a class="nav-item" href="teacher-path-landing-editor.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>Landing page</a>
<a class="nav-item" href="teacher-path-certificate.html"><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>Certificate</a>
<a class="nav-item" href="teacher-path-settings.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4 7 17M17 7l1.4-1.4"/></svg>Settings</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<nav class="crumbs">
<a href="teacher-paths.html">Learning Paths</a><span class="sep">/</span>
<a href="teacher-path-builder.html">Frontend Engineering Bootcamp</a><span class="sep">/</span>
<span class="here">Set up</span>
</nav>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
<a class="btn btn-outline btn-sm" href="path-detail.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>Preview as student</a>
</div>
</header>
<main class="content">
<div class="wrap-narrow">
<div class="gs-head">
<div>
<h1 class="page-title">Set up your path</h1>
<p class="page-sub">Finish these steps to launch <strong style="color: var(--foreground); font-weight: 500">Frontend Engineering Bootcamp</strong> to your learners.</p>
</div>
<div class="ring">
<svg viewBox="0 0 100 100">
<circle class="track" cx="50" cy="50" r="45" fill="none" stroke-width="8" />
<circle class="arc" cx="50" cy="50" r="45" fill="none" stroke-width="8" stroke-linecap="round" stroke-dasharray="282.7" stroke-dashoffset="188.5" />
</svg>
<span class="lbl tnum">33%</span>
</div>
</div>
<div class="item item-outline" style="margin-bottom: 16px; cursor: default">
<div class="item-content">
<span class="item-desc" style="margin-bottom: 10px">A path goes live once its courses are ordered, priced, and set to Active.</span>
<div class="summary-cnt">
<span class="item-desc tnum" style="color: var(--foreground)">2 of 6 completed</span>
<span class="dots"><span class="dot on"></span><span class="dot on"></span><span class="dot"></span><span class="dot"></span><span class="dot"></span><span class="dot"></span></span>
</div>
</div>
</div>
<div class="list">
<div class="item item-muted item-done">
<div class="item-media-icon is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div>
<div class="item-content">
<span class="item-title">Name &amp; describe your path</span>
<span class="item-desc">Give the path a clear, outcome-based name and a short summary.</span>
</div>
<div class="item-actions"><span class="btn btn-secondary btn-sm disabled">Done</span></div>
</div>
<div class="item item-muted item-done">
<div class="item-media-icon is-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg></div>
<div class="item-content">
<span class="item-title">Add courses</span>
<span class="item-desc">Pick the courses that make up this learning path.</span>
</div>
<div class="item-actions"><span class="btn btn-secondary btn-sm disabled">Done</span></div>
</div>
<div class="item item-current">
<div class="item-media-icon is-current"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="9" cy="6" r="1"/><circle cx="15" cy="6" r="1"/><circle cx="9" cy="12" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="9" cy="18" r="1"/><circle cx="15" cy="18" r="1"/></svg></div>
<div class="item-content">
<span class="item-title">Set the course order</span>
<span class="item-desc">Drag courses into the order learners should complete them.</span>
</div>
<div class="item-actions"><a class="btn btn-primary btn-sm" href="teacher-path-builder.html">Set order<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
</div>
<div class="item item-muted">
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg></div>
<div class="item-content">
<span class="item-title">Set your price</span>
<span class="item-desc">Price the path as a bundle — learners see the savings vs individual courses.</span>
</div>
<div class="item-actions"><a class="btn btn-outline btn-sm" href="teacher-path-settings.html">Set price<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
</div>
<div class="item item-muted">
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div>
<div class="item-content">
<span class="item-title">Customize your landing page</span>
<span class="item-desc">Outcomes, skills, instructors, testimonials, and FAQs on the public path page.</span>
</div>
<div class="item-actions"><a class="btn btn-outline btn-sm" href="teacher-path-landing-editor.html">Customize<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
</div>
<div class="item item-muted">
<div class="item-media-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="M22 4 12 14.01l-3-3"/></svg></div>
<div class="item-content">
<span class="item-title">Activate the path</span>
<span class="item-desc">Set the status to Active so it appears on your landing page and LMS.</span>
</div>
<div class="item-actions"><a class="btn btn-outline btn-sm" href="teacher-path-settings.html">Activate<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9 18l6-6-6-6"/></svg></a></div>
</div>
</div>
<div class="card launch">
<div class="ring ring-sm">
<svg viewBox="0 0 100 100"><circle class="track" cx="50" cy="50" r="45" fill="none" stroke-width="10" /><circle class="arc" cx="50" cy="50" r="45" fill="none" stroke-width="10" stroke-linecap="round" stroke-dasharray="282.7" stroke-dashoffset="188.5" /></svg>
</div>
<div class="txt">
<b>4 steps left to launch</b>
<p>Order the courses, set a price, polish the landing page, and activate.</p>
</div>
<a class="btn btn-primary" href="teacher-path-settings.html">Activate now</a>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
@@ -0,0 +1,131 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Learning Paths (Admin) · ClassroomIO</title>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@300..800&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>
<style>
.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 24px; }
.grid-cols { grid-template-columns: 2.4fr 0.8fr 0.9fr 1fr 40px; }
.p-ico { width: 38px; height: 38px; border-radius: var(--radius-md); display: grid; place-items: center; color: #fff; flex-shrink: 0; }
.p-ico svg { width: 18px; height: 18px; stroke-width: 2; }
.p-name { display: flex; align-items: center; gap: 12px; min-width: 0; }
.p-name .t { font-size: 14px; font-weight: 500; }
.p-name .d { font-size: 12.5px; color: var(--muted-foreground); display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.cell { display: flex; align-items: center; gap: 6px; color: var(--foreground); }
.cell svg { width: 14px; height: 14px; stroke-width: 2; color: var(--muted-foreground); }
.row-more { color: var(--muted-foreground); display: grid; place-items: center; }
.row-more svg { width: 16px; height: 16px; stroke-width: 2; }
.org-pill { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border: 1px solid var(--sidebar-border); border-radius: var(--radius-md); margin-bottom: 6px; background: var(--background); }
.org-pill .l { width: 22px; height: 22px; border-radius: var(--radius-sm); background: oklch(0.596 0.145 163.225); color: #fff; display: grid; place-items: center; font-size: 11px; font-weight: 600; }
.org-pill .n { font-size: 13px; font-weight: 500; }
.org-pill svg { margin-left: auto; width: 14px; height: 14px; color: var(--muted-foreground); stroke-width: 2; }
@media (max-width: 900px) { .stats { grid-template-columns: 1fr; } .thead { display: none; } .trow.grid-cols { grid-template-columns: 1fr auto; } }
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<div class="brand"><div class="brand-mark">C</div><div class="brand-name">ClassroomIO</div></div>
<div class="org-pill"><span class="l">A</span><span class="n">Acme Academy</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="m6 9 6 6 6-6"/></svg></div>
<div class="nav-label">Workspace</div>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>Dashboard</a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>Courses</a>
<a class="nav-item active" href="teacher-paths.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Learning Paths</a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/></svg>Audience</a>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M14 9V5a3 3 0 0 0-6 0v4"/><rect x="4" y="9" width="16" height="12" rx="2"/></svg>Community</a>
<div class="nav-label">Settings</div>
<a class="nav-item" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="3"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2"/></svg>Organization</a>
<div class="sidebar-foot"><div class="avatar">JD</div><div class="who"><div class="nm">Jordan Diallo</div><div class="rl">Admin</div></div></div>
</aside>
<div class="main">
<header class="topbar">
<span class="top-title">Learning Paths</span>
<div class="top-actions">
<button class="icon-btn" id="theme" 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>
</div>
</header>
<main class="content">
<div class="wrap" style="max-width: 1000px">
<div class="page-head">
<div>
<h1 class="page-title">Learning Paths</h1>
<p class="page-sub">Group your courses into ordered tracks your learners complete step by step.</p>
</div>
<a class="btn btn-primary" href="teacher-path-setup.html"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>Create path</a>
</div>
<div class="stats">
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg>Active paths</div><div class="v tnum">3</div></div>
<div class="card stat-card"><div class="k"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>Enrolled learners</div><div class="v tnum">126</div></div>
<div class="card stat-card"><div class="k"><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>Completions</div><div class="v tnum">54</div></div>
</div>
<div class="card" style="overflow: hidden">
<div class="thead grid-cols"><span>Path</span><span>Courses</span><span>Learners</span><span>Status</span><span></span></div>
<a class="trow grid-cols" href="teacher-path-builder.html">
<div class="p-name">
<span class="p-ico" style="background: linear-gradient(135deg, oklch(0.488 0.243 264.376), oklch(0.623 0.214 259.815))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
<div style="min-width: 0"><div class="t">Frontend Engineering Bootcamp</div><div class="d">HTML foundations through shipping a React app.</div></div>
</div>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5</span>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>48</span>
<span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Active</span></span>
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
</a>
<a class="trow grid-cols" href="teacher-path-builder.html">
<div class="p-name">
<span class="p-ico" style="background: linear-gradient(135deg, oklch(0.596 0.145 163.225), oklch(0.696 0.17 162.48))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
<div style="min-width: 0"><div class="t">Data Science with Python</div><div class="d">Pandas, visualization, and applied ML basics.</div></div>
</div>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>4</span>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>61</span>
<span><span class="badge badge-success-soft"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M20 6 9 17l-5-5"/></svg>Active</span></span>
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
</a>
<a class="trow grid-cols" href="teacher-path-setup.html">
<div class="p-name">
<span class="p-ico" style="background: linear-gradient(135deg, oklch(0.666 0.179 58.318), oklch(0.769 0.188 70.08))"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
<div style="min-width: 0"><div class="t">Product Management Fundamentals</div><div class="d">Discovery, prioritization, and roadmap craft.</div></div>
</div>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>5</span>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>0</span>
<span><span class="badge badge-warning" style="background: var(--warning-soft); color: var(--warning)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>Draft</span></span>
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
</a>
<a class="trow grid-cols" href="teacher-path-builder.html" style="opacity: 0.7">
<div class="p-name">
<span class="p-ico" style="background: var(--muted); color: var(--muted-foreground)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3v12"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/></svg></span>
<div style="min-width: 0"><div class="t">Workplace Compliance 2026</div><div class="d">Security awareness, data handling, code of conduct.</div></div>
</div>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>3</span>
<span class="cell tnum"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>17</span>
<span><span class="badge badge-muted">Inactive</span></span>
<span class="row-more"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="5" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="12" cy="19" r="1"/></svg></span>
</a>
</div>
</div>
</main>
</div>
</div>
<script>
document.getElementById('theme').onclick = () => {
const dark = document.documentElement.classList.toggle('dark');
localStorage.cioTheme = dark ? 'dark' : 'light';
};
</script>
</body>
</html>
+66
View File
@@ -0,0 +1,66 @@
---
name: write-prd
description: Write a product PRD for ClassroomIO the house way — clarify all features with the user first, research the codebase, write the PRD under prd/<feature>/, then build clickable HTML prototypes under prototypes/<feature>/ that become the UX source of truth. Use when the user asks to "write a PRD", "spec a feature", "plan a new product/feature", or "prototype a feature end to end".
---
# Write a PRD
A PRD here is two artifacts that ship together:
1. `prd/<feature>/README.md` — the written spec.
2. `prototypes/<feature>/` — clickable HTML prototypes of every surface, with an `index.html` map. **The prototypes are the UX source of truth**; when prose and prototype disagree on a UI detail, the prototype wins, and the PRD must say so.
Work in this order. Do not write the PRD before the decisions are locked, and do not build prototypes before the PRD scope is clear.
## Phase 1 — Get clear on all the features first
Never start writing from a one-line request. Close every open fork with the user via `AskUserQuestion` (option-based, 3–4 questions per round, 2–3 rounds max):
- **Relationship to existing features** — new entity vs extension of something shipped? (Check `prd/` for overlapping PRDs first; e.g. "learning paths" nearly collided with the shipped Programs feature.)
- **Who touches it** — enumerate the personas and confirm each surface: public visitor (org landing site), learner (LMS), teacher/admin (dashboard). Most features need all three; ask which are in scope.
- **The business mechanics** — pricing, enrollment/self-serve vs admin-managed, gating/completion rules, certificates, statuses (Active/Draft/Archived).
- **Scope cuts** — what's explicitly v1 vs later. Every "maybe" becomes a Non-Goal or a decision.
- **References** — if the user points at a competitor page or screenshot, fetch/read it and mirror its structure deliberately.
Every answer becomes a numbered entry in the PRD's **Confirmed Decisions** section. If the user answers with a note instead of an option, treat it as a lead to chase (fetch the URL, read the screenshot), not a checkbox.
## Phase 2 — Research the codebase before writing
- Read the closest existing PRD in `prd/` and match its format.
- Audit current state: what tables, services, routes, and UI patterns already exist that this feature reuses or must not break. Capture it as a **Current-State Audit** table (capability → current state → notes).
- Find the real UI patterns to mirror (use an Explore agent for breadth): the component primitives in `packages/ui`, the sibling feature's routes/sidebar/pages, the landing-page theme system. Name the actual files in the PRD.
## Phase 3 — Write the PRD
Location: `prd/<feature>/README.md`. House structure (match `prd/programs [DONE]/README.md`):
1. **Status** — Draft / In review / Done.
2. **Prototypes — the UX source of truth** — state that UX comes from the prototype folder, show the start page in a code block (`prototypes/<feature>/index.html`), and include a surface → files table.
3. **Purpose** — one paragraph; name the reference experience if there is one.
4. **Problem Statement** — bullets of what's impossible or painful today.
5. **Confirmed Decisions** — numbered; this is the contract from Phase 1.
6. **Current-State Audit** — the table from Phase 2.
7. **Product Goals** / **Non-Goals (v1)**.
8. **Functional Requirements** — one subsection per surface (public / learner / teacher), each referencing its prototype file and describing states, not just happy paths (locked, empty, draft…).
9. **Technical Design** — data model as schema code blocks (follow repo rules: no relational IDs in jsonb, computed values never stored), core logic in pseudocode, an API route table, and a frontend plan that follows CLAUDE.md layering (validation → queries → services → routes → feature types/API classes).
10. **Implementation Order** — numbered phases an engineer can execute top to bottom, with build verification commands.
11. **Acceptance Criteria** — testable, numbered; always include a "zero regression on existing features" criterion and "all copy uses translation keys".
12. **Risks and Mitigations** — each risk paired with a concrete mitigation.
Keep it scannable: tables for routes and audits, code blocks for schemas, prose only where judgment is needed.
## Phase 4 — Build the prototypes
Location: `prototypes/<feature>/` — standalone HTML files, one per screen, plus shared CSS:
- **Use the real design tokens, not invented ones.** App screens: a shared `app-theme.css` mirroring `packages/ui/src/index.css` (OKLCH vars, Geist, radii, shadows, Button/Badge/Item/Progress recipes, `.dark` class). Public screens: a `landing-theme.css` mirroring the default org-landing theme (`--landing-*` vars). Read the actual component variants (`tv()` blocks) before styling.
- **Match shipped UI, don't redesign it.** If a screen wraps an existing view (course page, setup checklist, settings form), replicate that view's real structure — sidebar, header, states — and add only the feature-specific chrome. Screenshots from the user override everything.
- **`index.html` is the start page**: a map of every screen grouped by persona/journey, each card linking in. All pages cross-link so each journey clicks through end to end.
- Every page: light/dark toggle, realistic data (no lorem), all states shown (done / in progress / locked / empty / draft). Small vanilla-JS interactions (drag reorder, accordions, tabs) are worth the effort — they sell the flow.
- Open pages with `open <file>` as you finish them so the user can react early; iterate on their feedback per screen. Expect header/sidebar nitpicks — fidelity to the real app is the bar.
## Phase 5 — Close the loop
- Re-check the PRD against the final prototypes (files renamed? screens added/removed? decisions changed mid-build?) and fix drift.
- Tell the user the start page path and the PRD path in your summary.
- Flag the one or two product calls you made without an explicit answer so they can veto them.