Skip to content

Commit 3de9e53

Browse files
committed
Tighten responsive library hero
1 parent 54b5fd9 commit 3de9e53

3 files changed

Lines changed: 82 additions & 20 deletions

File tree

apps/dev-preview/src/styles.css

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ h3 {
439439

440440
.library-hero {
441441
width: 100%;
442-
margin-bottom: clamp(3.5rem, 7vw, 6rem);
442+
margin-bottom: clamp(2.5rem, 4vw, 4rem);
443443
}
444444

445445
.library-masthead {
@@ -475,10 +475,10 @@ h3 {
475475

476476
.library-hero-content {
477477
display: grid;
478-
grid-template-columns: minmax(0, 1.25fr) minmax(18rem, 0.75fr);
479-
gap: clamp(2rem, 7vw, 6.5rem);
480-
align-items: end;
481-
padding: clamp(3rem, 7vw, 5.75rem) 0 2.25rem;
478+
grid-template-columns: minmax(0, 1.35fr) minmax(19rem, 0.65fr);
479+
gap: clamp(2rem, 4vw, 4rem);
480+
align-items: center;
481+
padding: clamp(2.25rem, 4vw, 3.5rem) 0 clamp(1.75rem, 3vw, 2.5rem);
482482
}
483483

484484
.library-eyebrow {
@@ -487,14 +487,14 @@ h3 {
487487

488488
.library-title {
489489
margin: 0;
490-
max-width: 12ch;
491-
font-size: clamp(2.85rem, 6vw, 4.8rem);
490+
max-width: none;
491+
font-size: clamp(2.85rem, 5vw, 4.5rem);
492492
line-height: 0.98;
493-
text-wrap: balance;
493+
text-wrap: pretty;
494494
}
495495

496496
.library-introduction {
497-
padding-left: 1.5rem;
497+
padding-left: clamp(1rem, 2vw, 1.5rem);
498498
border-left: 1px solid var(--border-strong);
499499
}
500500

@@ -1237,6 +1237,26 @@ pre code {
12371237
padding: 2rem;
12381238
}
12391239

1240+
@media (max-width: 70rem) {
1241+
.library-hero-content {
1242+
grid-template-columns: minmax(0, 1fr);
1243+
gap: 1.5rem;
1244+
align-items: start;
1245+
}
1246+
1247+
.library-title {
1248+
max-width: 16ch;
1249+
}
1250+
1251+
.library-introduction {
1252+
max-width: 46rem;
1253+
padding-top: 1.35rem;
1254+
padding-left: 0;
1255+
border-top: 1px solid var(--border-strong);
1256+
border-left: 0;
1257+
}
1258+
}
1259+
12401260
@media (max-width: 62rem) {
12411261
.course-layout {
12421262
display: block;
@@ -1353,13 +1373,12 @@ pre code {
13531373
}
13541374

13551375
.library-hero {
1356-
margin-bottom: 3.25rem;
1376+
margin-bottom: 2.5rem;
13571377
}
13581378

13591379
.library-hero-content {
1360-
grid-template-columns: minmax(0, 1fr);
13611380
gap: 1.5rem;
1362-
padding: 2.5rem 0 1.75rem;
1381+
padding: 2.25rem 0 1.75rem;
13631382
}
13641383

13651384
.library-title {
@@ -1368,8 +1387,7 @@ pre code {
13681387
}
13691388

13701389
.library-introduction {
1371-
padding-left: 0;
1372-
border-left: 0;
1390+
padding-top: 1.1rem;
13731391
}
13741392

13751393
.library-section + .library-section {

docs/implementation-status.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Implementation status
22

3-
Updated: 19 August 2026
3+
Updated: 20 August 2026
44

55
## Completed
66

@@ -35,6 +35,7 @@ Updated: 19 August 2026
3535
- Reworked the local course library and lesson shell as a quiet, editorial learning interface with accessible pastel color roles, lesson-first hierarchy, explicit navigation states, compact course contents below 992px, and visually consistent sandbox controls. The course shell now reflows at 320px without putting the full lesson list ahead of the active lesson.
3636
- Reframed the local collection home as a product-general, status-first course library. Available courses now lead the page, planned AI courses are subordinate roadmap content, and the visible display name is `Explorables` while lowercase technical identifiers remain stable.
3737
- Added an explicit, persistent light/dark theme control to the course library and lesson shell, including live theme synchronization into already-mounted sandboxed explorables. Retuned the dark pastel roles, restored the library hero and local-data notice to the full responsive content width, and corrected title casing while preserving the lowercase `explorables` wordmark.
38+
- Tightened the course-library hero into a compact responsive composition: wide screens use a smaller, content-filled column gutter, while Codex-sized panes stack the introduction below a two-line headline before the layout becomes squeezed. Reduced the masthead and section whitespace so the available-course section begins within the first compact-browser viewport.
3839
- Retained Node.js 24/pnpm 11 as the default toolchain while adding an enforced, CI-tested compatibility floor of Node.js 22.22.2 and pnpm 10.26.0.
3940
- Refreshed the planned `Inside DeepSeek` course through DeepSeek V4 Pro/Flash while retaining V3/R1 as lineage, and refreshed `Inside GLM` through GLM 5.2 while retaining GLM 5 as the available architecture/post-training lineage. The revised briefs add hybrid long-context attention, mHC, Muon, mixed precision and policy consolidation for DeepSeek, plus DSA/IndexShare, multi-token prediction, serving ablations, and long-horizon evaluation for GLM.
4041
- Recorded exact reviewed official model-artifact commits, report revisions, and code/weight licence signals for DeepSeek V4 and GLM 5.2 in the candidate source register without misrepresenting them as immutable course-local source freezes.
@@ -51,7 +52,7 @@ Updated: 19 August 2026
5152

5253
The v0.1 runtime MVP remains verified. Course-session continuity now provides a framework-owned resume surface, lesson-level local state for persistent courses, Guided checkpoint resume and confirmed rollback, page-exit flushing, storage-failure messaging, host-neutral state attributes, shared lifecycle language, and a stable strict development origin. Model Atlas implementation, local hardening, clean-checkout verification, and pull-request CI are complete.
5354

54-
`AI from First Principles` `0.4.0-foundations.1`, Guided Course Mode, Agent Plugins v1 packaging, and the local course-library milestone are implemented. The course UI redesign and its responsive/theme follow-up are complete. The library presents the shared frontier core and DeepSeek, Kimi, Qwen, MiniMax, and GLM specializations as planned rather than runnable. Its DeepSeek and GLM cards now reflect the V4 and 5.2 endpoints. The next implementation increment remains the shared-core source freeze and its five research/comparison lessons, followed by the pinned model-specific courses. External DNS and learner-study evidence also remain.
55+
`AI from First Principles` `0.4.0-foundations.1`, Guided Course Mode, Agent Plugins v1 packaging, and the local course-library milestone are implemented. The course UI redesign and its responsive/theme follow-up are complete, including compact embedded-browser hero spacing. The library presents the shared frontier core and DeepSeek, Kimi, Qwen, MiniMax, and GLM specializations as planned rather than runnable. Its DeepSeek and GLM cards now reflect the V4 and 5.2 endpoints. The next implementation increment remains the shared-core source freeze and its five research/comparison lessons, followed by the pinned model-specific courses. External DNS and learner-study evidence also remain.
5556

5657
## Decisions
5758

@@ -71,6 +72,7 @@ The v0.1 runtime MVP remains verified. Course-session continuity now provides a
7172
## Latest verification
7273

7374
```text
75+
20 Aug compact library hero pass (16 browser tests; 320×700, 720×800, 900×700, 1100×760, and 1427×900 geometry; light/dark in-app Codex visual QA; scoped format/lint, typecheck, 33 suites/102 tests, validation, and all builds)
7476
19 Aug foundations + PRD v0.4 pass (clean worktree: format/lint/typecheck, 33 suites/102 tests, 17 course suites/54 tests, 14 starter/reference pairs, all builds, 16 browser tests, axe, 320px overflow check, and in-app visual QA)
7577
19 Aug general library redesign pass (typecheck, 7 suites/29 targeted tests, collection validation/build, 15 browser tests, 2 site tests, axe, light/dark visual QA at 843px and 320px)
7678
18 Aug Model Atlas unit/integration pass (33 suites/100 tests; strict descriptors, exact traces, comparisons, renderer lifecycle, validator, and real catalogue bundle)

tests/browser/course.spec.ts

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,14 @@ test("follows the system theme, syncs explorables, and persists an override", as
159159
});
160160

161161
test("keeps the general course library responsive", async ({ page }) => {
162-
for (const width of [320, 720, 1156, 1427]) {
163-
await page.setViewportSize({ width, height: 900 });
162+
for (const viewport of [
163+
{ width: 320, height: 700 },
164+
{ width: 720, height: 800 },
165+
{ width: 900, height: 700 },
166+
{ width: 1100, height: 760 },
167+
{ width: 1427, height: 900 },
168+
]) {
169+
await page.setViewportSize(viewport);
164170
await page.goto("/");
165171
await expect(page.locator("h1.library-title")).toHaveText(
166172
"Learn by exploring, coding, and testing.",
@@ -170,24 +176,60 @@ test("keeps the general course library responsive", async ({ page }) => {
170176
const hero = document.querySelector<HTMLElement>(".library-hero");
171177
const note = document.querySelector<HTMLElement>(".local-note");
172178
const title = document.querySelector<HTMLElement>(".library-title");
179+
const masthead = document.querySelector<HTMLElement>(".library-masthead");
180+
const eyebrow = document.querySelector<HTMLElement>(".library-eyebrow");
181+
const introduction = document.querySelector<HTMLElement>(".library-introduction");
173182
const available = document.querySelector<HTMLElement>(".available-courses");
174-
if (!library || !hero || !note || !title || !available)
183+
if (
184+
!library ||
185+
!hero ||
186+
!note ||
187+
!title ||
188+
!masthead ||
189+
!eyebrow ||
190+
!introduction ||
191+
!available
192+
)
175193
throw new Error("Expected library header elements");
194+
const titleStyles = getComputedStyle(title);
195+
const titleLineHeight = Number.parseFloat(titleStyles.lineHeight);
196+
const titleRect = title.getBoundingClientRect();
197+
const introductionRect = introduction.getBoundingClientRect();
176198
return {
177199
overflow:
178200
document.documentElement.scrollWidth > document.documentElement.clientWidth,
179201
libraryWidth: library.getBoundingClientRect().width,
180202
heroWidth: hero.getBoundingClientRect().width,
181203
noteWidth: note.getBoundingClientRect().width,
182-
titleWidth: title.getBoundingClientRect().width,
204+
titleWidth: titleRect.width,
183205
availableWidth: available.getBoundingClientRect().width,
206+
mastheadToContentGap:
207+
eyebrow.getBoundingClientRect().top - masthead.getBoundingClientRect().bottom,
208+
heroToCoursesGap:
209+
available.getBoundingClientRect().top - note.getBoundingClientRect().bottom,
210+
titleLines: titleRect.height / titleLineHeight,
211+
introductionTop: introductionRect.top,
212+
introductionLeft: introductionRect.left,
213+
titleBottom: titleRect.bottom,
214+
titleLeft: titleRect.left,
215+
titleRight: titleRect.right,
184216
};
185217
});
186218
expect(metrics.overflow).toBe(false);
187219
expect(Math.abs(metrics.heroWidth - metrics.libraryWidth)).toBeLessThan(1);
188220
expect(Math.abs(metrics.availableWidth - metrics.libraryWidth)).toBeLessThan(1);
189221
expect(metrics.noteWidth).toBeLessThanOrEqual(metrics.heroWidth);
190222
expect(metrics.titleWidth).toBeLessThanOrEqual(metrics.heroWidth);
223+
expect(metrics.mastheadToContentGap).toBeLessThanOrEqual(70);
224+
expect(metrics.heroToCoursesGap).toBeLessThanOrEqual(70);
225+
if (viewport.width >= 720) expect(metrics.titleLines).toBeLessThanOrEqual(3.1);
226+
if (viewport.width <= 1120) {
227+
expect(metrics.introductionTop).toBeGreaterThan(metrics.titleBottom);
228+
expect(Math.abs(metrics.introductionLeft - metrics.titleLeft)).toBeLessThan(1);
229+
} else {
230+
expect(metrics.introductionLeft).toBeGreaterThan(metrics.titleLeft);
231+
expect(metrics.introductionLeft - metrics.titleRight).toBeLessThan(200);
232+
}
191233
}
192234
});
193235

0 commit comments

Comments
 (0)