Skip to content

Align the homepage and events with the adopted CMP visual system #130

Description

@alexeygrigorev

Parent umbrella: #129

Depends on #128, which restores and protects the exact copied CMP course composition that this slice uses as its visual reference. This issue is implementation-ready once #128 is merged.

Product outcome

Make the first public vertical slice—/, its non-redirecting /unified/ alias, /events, and /events/<slug>—read unmistakably as the same product as the adopted Course Management Platform (CMP), without changing what the pages say or do. The shared shell, typography, colors, spacing rhythm, headings, divided rows, controls, responsive behavior, dark mode, and accessibility treatment come from CMP; this slice must not invent another public-site theme.

This slice also closes the structural escape hatch that could silently restore the obsolete standalone public shell: all rendered pages continue to resolve base.html from the adopted CMP directory, and the unused project-level templates/base.html / core/site.css design is removed or otherwise proven unable to render.

Normative authority and visual provenance

Reference files at that commit:

  • templates/base.html, source SHA-256 f51666391e33aec905f43312215bfd82094bfb0088414594f40bcbdfc21560b8, for shell/header/footer/content width, typography, theme control, and account navigation composition;
  • courses/static/courses.css, source SHA-256 282ed7b15df2502a8d4c2e9cd45ef1f8e92771835243d3cbc590f78db9ed5f8f, for the token and component implementation;
  • courses/templates/courses/course_list.html and _course_list_card.html for hero, section-heading, divided-row, metadata, action, empty, and responsive patterns;
  • courses/templates/courses/course.html for a representative detail-page hierarchy.

The website’s adopted course_platform_templates/base.html and courses/static/courses.css include documented DTC integration overlays. Their current target hashes are evidence in integration-patched-files.tsv, not a new design authority. #125, #126, and later accepted overlays extend the pinned CMP system rather than superseding it.

CMP token and component contract

Use the existing CMP implementation rather than restating lookalike literal values in a new stylesheet:

  • Typography: Inter, then CMP’s system sans fallback; normal tracking; the restrained CMP catalogue scale (hero up to md:text-5xl, section headings text-2xl/md:text-3xl, body text-base/md:text-lg) unless semantic content proves a narrower existing CMP pattern.
  • Color: --page-bg, --surface-bg, --surface-muted, --border-muted, --text-primary, --text-heading, --text-muted, --link-color, --link-hover, input/status tokens, and --focus-ring; dark mode changes these tokens on body.dark-mode.
  • Shell: the CMP app-content-shell (56rem) and the recorded wider header-navigation integration only; the base uses px-4/md:px-8 and py-5/md:py-10.
  • Composition: semantic headings and landmarks; restrained sections separated by app-border; full-width app-divide rows for discovery lists; app-heading, app-text, app-muted, and app-link for text roles. Cards/panels are used only where CMP uses a real bounded object, form, alert, or grouped detail—not as a default marketing grid.
  • Controls: existing primer-button variants, CMP form controls, badges, alerts, breadcrumbs, pagination, user menu, and theme control. No parallel .button, .card, .hero, color palette, radius scale, or shadow language.
  • Interaction: server-rendered links and forms work without JavaScript; JavaScript only enhances the CMP shell. Dark mode, reduced motion, keyboard focus, touch targets, and reflow are shared behaviors rather than page-specific patches.

First prefer existing CMP classes and readable template partials. If a missing primitive is genuinely required, make it token-backed and narrowly reusable in the adopted integration layer, document its rationale, and add a contract test. Do not add public.css, inline style blocks, raw page-specific color values, or a second reset/framework.

Confirmed current rendering audit

website/settings/base.py searches templates in this order: course_platform_templates/, project templates/, then app templates. Therefore:

  • templates/core/home.html, every templates/public/*.html page, and every templates/review/*.html page reach course_platform_templates/base.html through core/base.html;
  • adopted account/course pages extend that same CMP base directly;
  • custom templates/studio/*.html reaches it through studio/base.html;
  • copied Studio Courses reaches it through studio_courses/base.html.

The homepage and events already use many CMP tokens and utilities, so this work is a controlled alignment, not a wholesale rewrite. The material divergence is structural duplication: the unused lower-precedence templates/base.html loads core/site.css, whose independent #0b5fff palette, large marketing hero, card grids, .button controls, header/footer, and orange focus treatment form a competing design language. core/studio.css is another custom composition but is deferred to the custom-Studio child; this slice must not globally restyle Studio.

Scoped implementation

  1. Capture deterministic before evidence for home and events and compare it with pages rendered from the exact pinned CMP source, using the reference files above rather than subjective memory.
  2. Align templates/core/home.html, templates/public/events.html, templates/public/_event.html, templates/public/_event_meta.html, and templates/public/event_detail.html where the audit shows drift. Reuse the existing event partial so homepage and event discovery cannot diverge.
  3. Keep one restrained CMP catalogue-style hero and section rhythm. Homepage and event collections use semantic full-width divided rows; event detail uses the CMP detail hierarchy and existing controls. Do not introduce a marketing card grid.
  4. Prove every page in scope resolves the adopted base and adopted CSS. Remove the dormant project shell/stylesheet if the usage audit confirms they are unreachable; otherwise convert the remaining consumer explicitly and then remove them. Add a fail-closed origin/reference contract so a second visual base or stylesheet cannot silently return.
  5. Preserve readable, indented, non-minified Django templates and a useful no-JavaScript rendering.
  6. Add focused Django/template-source/browser coverage for the exact route, content, SEO, responsive, theme, and visual-system contracts below.

Required non-overlap

#125/#126 are coordination boundaries, not interface dependencies: this issue must not duplicate their work. If their accepted candidates change shared-shell output before implementation begins, start from the merged result and keep their focused contracts green.

Acceptance criteria

  • /, /unified/, /events, and a representative /events/<slug> render through course_platform_templates/base.html, load the adopted courses.css, and contain no reference to the obsolete standalone core/site.css design.
  • No live project-level base.html, stylesheet, selector, inline style block, or higher-precedence template can silently replace the CMP shell/tokens for pages in scope; a fail-closed repository/template-origin contract catches regression.
  • The homepage retains its established title, H1, community subtitle, one featured course plus Browse-all path, real event/podcast/book/article previews, and every current internal/external destination. /unified/ remains a non-redirecting equivalent with its existing canonical behavior.
  • /events retains the event-type explanation, calendar guidance, stable upcoming/past ordering, truthful empty states, internal event links, speaker links, dates/times/types, and current canonical/SEO metadata.
  • /events/<slug> retains title, type/time, aggregate registration count when present, speakers, current safe links, breadcrumb, canonical/SEO/JSON-LD behavior, and all empty/optional-field branches. No Populate internal event pages and replace Luma registration CTAs #127 registration/content behavior is preempted.
  • Visual hierarchy uses the CMP shell, font stack, tokens, restrained heading scale, spacing rhythm, divided rows, link roles, buttons, borders, radii, and shadows. There is no competing palette, oversized marketing composition, default card grid, or new CSS framework.
  • Light and dark mode both use CMP tokens with legible text, borders, links, controls, icons, hover/current states, empty states, and event metadata; switching and persistence behavior do not regress.
  • Keyboard order, skip link, visible keyboard focus, pointer focus behavior from Remove pointer-click orange outlines from header controls #126 when merged, semantic landmarks/headings/lists, accessible icon treatment, external-link labels, 44×44 mobile targets where applicable, reduced motion, and 200% zoom/reflow remain usable.
  • At 1440×900 and 390×844 there is no horizontal overflow, clipping, overlap, unexpected card/grid collapse, missing local font/icon/style asset, console/page/request error, debug page, or error page. Content remains useful with JavaScript disabled.
  • Templates remain readable, line-broken Django/HTML. URLs, redirects, status codes, content values/order, canonical/robots/OG/Twitter/JSON-LD/sitemap contracts, cache policy, and functionality are unchanged.
  • Focused Django/template/adoption tests and make test-playwright-core pass, along with applicable uv-backed lint, format, type, migration-drift, Django, content/SEO/link, and CMP provenance checks.
  • [HUMAN] The product owner compares the final home/events evidence with the exact pinned CMP reference and accepts the typography, density, hierarchy, row treatment, responsive composition, and dark-mode result as one design family. Automated similarity alone cannot satisfy this criterion.

Browser and screenshot scenarios

Use deterministic synthetic public records and no PII. Store all evidence below .tmp/screenshots/issue-<number>/, record the exact pinned CMP commit/reference paths, and open every image during independent testing.

  1. Capture / and /events at 1440×900 and 390×844 in both light and dark mode (eight primary screenshots).
  2. Capture one representative event detail with speakers, safe external links, and aggregate registration total at desktop and mobile in light mode; exercise dark mode in browser assertions.
  3. Exercise /unified/ for structural/content/canonical equivalence without duplicating screenshots unless it differs.
  4. Exercise homepage/event empty and optional-field states, keyboard traversal, pointer activation, theme switching/persistence, 200% zoom/reflow, 320 px overflow, reduced motion, JavaScript-disabled usefulness, and local asset/network/console failures.
  5. Compare against deterministic screenshots rendered from the exact pinned CMP source catalogue/detail patterns. Record allowed DTC shell/content differences explicitly; “looks similar” is not a verdict.

Process handoff

Implement from current main after #128 is merged, in an isolated worktree. The engineer implements and tests without committing. A separate tester freezes the candidate, runs the focused and core gates, captures and reads the browser evidence, and reports every criterion. Product management then evaluates the visitor experience and the [HUMAN] owner criterion. Commit with Closes #<this issue> and Refs #129 only after both gates; merge locally without a pull request. Do not close #129 until every planned surface family is accepted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Must-have or release-blockingaccessibilityArea: accessibilityenhancementNew feature or requesteventsArea: eventsfoundationArea: foundationfrontendArea: frontendhumanCode complete; manual verification requiredintegrationArea: integrationseoArea: seotestingArea: testing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions