Lab website design language.
This document describes the visual and interaction patterns used across the Kifuliiru Lab website. It reflects what is implemented today in src/app/globals.css and shared React components under src/components/.
Goals: readable, research-lab tone; calm surfaces with accent color for action; responsive layouts; light/dark themes; accessible motion defaults.
| Principle | How it shows up | |-----------|-----------------| | Editorial clarity | Strong hierarchy (kicker → title → lede → body). Generous line-height (~1.65–1.8 for prose). | | Surface-based layout | Content lives on layered cards/panels (--bg-secondary, borders, soft shadows), not flat full-bleed blocks everywhere. | | Accent as signal | Blue accent marks links, active states, icons, and CTAs—not large decorative fills (except the homepage hero). | | Illustration as context | SVG PageIllustration variants reinforce page topic (research, language, platforms, etc.). | | Motion with restraint | Hover lifts, slide fades, marquees; all respect prefers-reduced-motion. | | i18n-first | Copy comes from LanguageContext; layout must tolerate longer FR/SW strings. |
Defined in :root and [data-theme="dark"] in globals.css.
| Token | Role | |-------|------| | --bg-primary | Page background | | --bg-secondary | Cards, panels | | --bg-tertiary | Muted cards, hover fills | | --text-primary | Headings, primary body | | --text-secondary | Descriptions, prose | | --text-muted | Meta, labels, placeholders | | --accent-color | Links, buttons, active filters, icon tints | | --accent-hover | Hover on accent elements | | --accent-light | Secondary button hover fill | | --border-color | Default borders | | --border-light | Subtle dividers |
Light accent: #3b82f6 → hover #2563eb
Dark accent: #60a5fa → hover #3b82f6
Use color-mix(in srgb, var(--accent-color) N%, …) for tinted borders and backgrounds (filters, icon wells, hover outlines).
| Token | Use | |-------|-----| | --shadow-sm … --shadow-xl | Card elevation steps | | --gradient-accent | Accent bars, emphasis | | --gradient-subtle | Panel backgrounds | | --gradient-card | CTA band overlay | | --glass-* | Glassmorphism (limited use) |
Inter, system UI sans-serif (body in globals.css).18px on body; section prose often 1.03rem (.body-prose).--font-mono for code/technical snippets.Scale (common patterns):
| Element | Typical size | |---------|----------------| | Page H1 (.page-hero__title) | clamp(1.85rem … 2.65rem) | | Section H2 (.section-heading, .surface-panel__title) | clamp(1.15rem … 1.65rem) | | Kicker / label | 0.72–0.8rem, uppercase, letter-spacing 0.04–0.08em | | Body / card description | 0.9–1.03rem | | Compact UI (filters, meta) | 0.62–0.82rem |
Weight: 600 for headings; 500–550 for UI labels; 600–700 for emphasis.
Letter-spacing: Slightly tight on large titles (-0.02em to -0.03em).
max-width: 1280px, horizontal padding 20px.margin-bottom: clamp(2.5rem, 5vw, 4rem) (.page-content-section).clamp(1.35rem, 3vw, 1.85rem).1.25rem standard; filter chips 5–6px.16–20px cards/panels; 14px nested links; 999px pills/chips.--ill-*)Used by PageIllustration SVG scenes. Separate light/dark overrides. Includes canvas gradients, strokes, glow, success/warm accents. Do not hardcode illustration colors in components—use CSS variables.
data-theme="light" | "dark" on the document root..homepage-hero): full-width blue band #2563eb, light text—intentionally not token-driven..organization-page): separate parchment/serif sub-system (--org-* tokens, Georgia/Palatino stack).<div class="container"> … </div>
```text
Centers content at 1280px. First child heroes (`.homepage-hero`, `.page-hero`) can use negative top margin to align with header.
### 4.2 Page sections
| Class | Purpose | |-------|---------| | `.page-content-section` | Standard vertical section spacing | | `.surface-panel` | Bordered panel with title (e.g. Explore Our Work) | | `.surface-card-grid` | Responsive `auto-fit` grid, `minmax(260px, 1fr)` |
---
## 5. Core components
### 5.1 `PageHero`
**File:** `src/components/PageHero.tsx`
Inner-page hero: kicker, H1, lede, optional actions, illustration on the right (≥768px).
**Classes:** `.page-hero`, `.page-hero__grid`, `.page-hero__kicker`, `.page-hero__title`, `.page-hero__lede`
**When to use:** Top of About, Research, Resources, etc.
### 5.2 `PageIllustration`
**File:** `src/components/PageIllustration.tsx`
**Variants:** `lab`, `research`, `language`, `heritage`, `community`, `platforms`, `resources`, `contact`, `team`, `projects`, `motto`, `products`
**Size modifiers:** default, `.page-illustration--compact`, `.page-illustration--mini`
### 5.3 `IllustratedSection` & `IllustratedCard`
**Files:** `IllustratedSection.tsx`, `IllustratedCard.tsx`
Wrap content in `.surface-card` with optional side/top illustration.
- **Section:** large illustration + body grid.
- **Card:** mini illustration strip + `.illustrated-card__body`.
Use `.body-prose` for paragraph text inside cards.
### 5.4 Surface cards
| Class | Behavior | |-------|----------| | `.surface-card` | Default card; hover: `-2px` lift, `--shadow-md`, accent-tinted border | | `.surface-card--muted` | `--bg-tertiary` background | | `.surface-card-link` | Accent inline link with arrow gap animation |
### 5.5 Section headings
```html
<h2 class="section-heading">
<span class="section-heading__icon">…icon…</span>
Title
</h2>
```text
Icon sits in a rounded accent-tinted well (`2rem` square, `10px` radius).
### 5.6 `PageCta`
**File:** `src/components/PageCta.tsx`
Closing band on inner pages: centered title, description, primary/secondary buttons.
**Classes:** `.page-cta-section`, `.page-cta-primary`, `.page-cta-secondary`
Gradient panel with `--gradient-card` overlay. Do not duplicate section titles elsewhere on the same page.
---
## 6. Homepage-specific patterns
### 6.1 Hero (`.homepage-hero`)
- Full-bleed blue editorial hero—not a card.
- Two columns at ≥900px: copy + `HomepageHeroResults` viz.
- Stats: `HomepageHeroStatsSlider` (3 items per slide, auto-advance, dots).
- Actions: `.homepage-hero__btn--primary` / `--secondary`, tertiary text link.
### 6.2 Current Work
Three `IllustratedCard` items in `.surface-card-grid`.
### 6.3 Explore Our Work (single section)
One `.surface-panel` containing:
1. **Title** — `.surface-panel__title`
2. **Intro** — `.homepage-explore-intro` (short centered helper text)
3. **Carousel** — `HomepageExploreWorkSlider` (continuous marquee; pauses on hover/focus; static grid if reduced motion)
4. **Extra links** — `.homepage-explore-footer` with pill buttons (Resources, Blog, Contact)
**Quick-link cards:** `.surface-panel__link` + `.homepage-quick-link-icon` (4rem circle, 32px icon) + title + description.
---
## 7. Blog & discovery UI
### 7.1 Discovery panel (`.blog-discovery-panel`)
Compact panel wrapping filters + search.
- Label: `.blog-discovery-panel__label` — small uppercase muted text.
- Search separated by top border (`.blog-discovery-panel__search`).
### 7.2 Category filters (`.blog-category-filter`)
Small pill chips—not large buttons.
| State | Style | |-------|--------| | Default | `--bg-primary`, visible accent-tinted border, light shadow | | Hover | `--bg-tertiary`, stronger border | | Active | `--accent-color` fill, light inset highlight |
Icons: Lucide, ~11px. Count badge with its own border.
**Font:** `0.7rem` (mobile `0.68rem`). Keep chips compact.
### 7.3 Blog cards & related posts
- Index: `.blog-post-card` with `.blog-post-card-image` (16:9).
- Article footer: `.blog-related-posts` with image + title + excerpt cards.
---
## 8. Organization documents (separate sub-system)
**Scope:** Constitution, Declaration, Foundation, Manifesto pages.
- Wrapper: `.organization-page` with `--org-*` tokens (parchment / dark parchment).
- **Typography:** Serif (`--org-serif`), not Inter.
- **Layout:** Side nav shell (`.organization-page-nav-shell`) + document hero + long-form content.
- **Do not** mix org serif styles into main lab pages without explicit reason.
---
## 9. Interactive elements
### 9.1 Primary / secondary CTAs
Shared utilities:
- `.interactive-cta-primary` — accent fill, white text
- `.interactive-cta-secondary` — accent border, transparent fill
Homepage hero uses bespoke `.homepage-hero__btn` variants.
### 9.2 Inline links
- `.homepage-link-inline` — accent, semibold, arrow gap on hover
- `.surface-card-link` — same pattern for cards
### 9.3 Buttons (explore footer, filters)
- **Pill buttons:** `border-radius: 999px`, visible border by default, subtle shadow.
- **Filter chips:** smaller than footer pills; no lift on hover.
### 9.4 Icons
- **Library:** [Lucide React](https://lucide.dev)
- **Stroke:** typically `strokeWidth={2}`; smaller UI uses `size={11–18}`
- **Icon wells:** circular or rounded square with `color-mix(accent 10–12%, transparent)` background
---
## 10. Motion & accessibility
| Pattern | Rule | |---------|------| | Card hover | `translateY(-2px)`, 0.25s ease | | Slide enter | ~0.45s cubic-bezier fade + slight Y | | Marquee | Linear infinite; pause on `:hover` / `:focus-within` | | Reduced motion | Disable auto-advance and marquee; prefer static layouts |
- Use `aria-label`, `aria-live="polite"` on sliders where content changes.
- Duplicate marquee items should be `aria-hidden` + `tabIndex={-1}`.
- Focus rings: `outline: 2px solid var(--accent-color); outline-offset: 2px`.
---
## 11. Responsive breakpoints (informal)
| Breakpoint | Typical behavior | |------------|------------------| | `< 640px` | Single-column; smaller filter chips | | `≥ 640px` | 2-column grids emerge | | `≥ 768px` | Page hero two columns | | `≥ 900px` | Homepage hero two columns | | `≥ 1024px` | Blog grids 3-column; explore slider card sizing |
Prefer `clamp()` and `minmax()` over fixed breakpoints when possible.
---
## 12. Content & i18n
- All user-facing strings go through `useLanguage()` / `t('key')` in `LanguageContext.tsx`.
- When adding UI labels, extend the `TranslationKey` union and all four locales: `en`, `fr`, `sw`, `flr`.
- Write short helper text for constrained widths (filters, explore intro, card excerpts ~1 sentence).
---
## 13. File reference
| Concern | Location | |---------|----------| | Global tokens & classes | `src/app/globals.css` | | Page hero | `src/components/PageHero.tsx` | | Illustrations | `src/components/PageIllustration.tsx` | | Illustrated layouts | `src/components/IllustratedSection.tsx`, `IllustratedCard.tsx` | | Page closing CTA | `src/components/PageCta.tsx` | | Homepage | `src/components/Homepage.tsx` | | Explore carousel | `src/components/HomepageExploreWorkSlider.tsx` | | Blog filters | `src/components/BlogCategoryFilters.tsx` | | Org document layout | `src/components/OrganizationPlainPage.tsx` | | Translations | `src/contexts/LanguageContext.tsx` |
---
## 14. Checklist for new UI
1. Use CSS variables and existing classes before inventing new patterns.
2. Prefer `PageHero` + `IllustratedSection` / `surface-card-grid` for inner pages.
3. Keep filter/chip UI **small** with **visible default borders**.
4. One section = one H2; avoid repeating the same section title (e.g. Explore Our Work + PageCta).
5. Test light and dark themes.
6. Test with `prefers-reduced-motion: reduce`.
7. Add translation keys for all locales.
8. Use Lucide icons consistently with section heading wells or circular quick-link icons.
---
*Last updated to reflect homepage Explore Our Work carousel, blog discovery panel, and filter chip styling.*