mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Initial Commit
This commit is contained in:
+126
@@ -0,0 +1,126 @@
|
||||
# Theming & Motion Guide
|
||||
|
||||
How color, light/dark mode, section tone, and animation work on this site.
|
||||
|
||||
---
|
||||
|
||||
## Palette
|
||||
|
||||
From the spec, exposed as CSS variables in `src/styles/themes.css` and mapped to
|
||||
Tailwind utilities in `src/styles/global.css`:
|
||||
|
||||
| Token | Value | Meaning |
|
||||
|---|---|---|
|
||||
| `--color-slate` | `#1E293B` | Professional confidence (primary) |
|
||||
| `--color-amber` | `#F59E0B` | Warm accent (the making/creative side) |
|
||||
| `--color-teal` | `#699a94` | Soft teal (secondary, favorite) |
|
||||
| `--color-ink` | `#0F172A` | Near-black text on light |
|
||||
| `--color-cream` | `#FFFBEB` | Cream-white text on dark |
|
||||
|
||||
Brand colors are fixed. **Semantic** tokens (`--surface`, `--text`, `--accent`,
|
||||
`--secondary`, `--border`, ...) resolve differently per theme + section, and are
|
||||
what components actually use.
|
||||
|
||||
---
|
||||
|
||||
## Two theming axes
|
||||
|
||||
### Axis 1 — Global light/dark
|
||||
|
||||
Set on `<html data-theme="light|dark">`:
|
||||
|
||||
- A blocking inline script (`src/scripts/theme-init.ts`, inlined in `<head>`)
|
||||
reads `localStorage['gk-theme']`, falling back to the OS
|
||||
`prefers-color-scheme`. This runs **before first paint**, so there is no flash.
|
||||
- The nav `ThemeToggle` island flips it and persists the choice.
|
||||
- If the user has never chosen, the site follows OS changes live.
|
||||
|
||||
### Axis 2 — Section tone
|
||||
|
||||
Set on `<body data-surface="neutral|professional|interest">` via the `surface`
|
||||
prop on `<BaseLayout>`:
|
||||
|
||||
| Surface | Used on | Tone |
|
||||
|---|---|---|
|
||||
| `neutral` | Home, About, Contact | Balanced — clean in light, calm in dark |
|
||||
| `professional` | Professional page | Dark slate, polished, amber accents |
|
||||
| `interest` | Interests pages | Warm cream/amber, inviting |
|
||||
|
||||
The Professional surface leans dark even in light mode (it is the "polished
|
||||
wing"). The Interest surface is warm in both modes. This is what gives the two
|
||||
wings their distinct feel while sharing the same typography and spacing.
|
||||
|
||||
Each `(data-theme, data-surface)` combination redefines the semantic tokens in
|
||||
`themes.css`. Add or adjust a combination there to change any section's palette.
|
||||
|
||||
---
|
||||
|
||||
## Changing colors
|
||||
|
||||
1. **Tweak a brand color:** edit the fixed values in `global.css` under `@theme`
|
||||
(e.g. `--color-amber`).
|
||||
2. **Tweak a section's tone:** edit the relevant `[data-surface="..."]` block in
|
||||
`themes.css`. Each block lists `--surface`, `--surface-raised`,
|
||||
`--surface-sunken`, `--text`, `--text-muted`, `--text-subtle`, `--border`,
|
||||
`--accent`, `--accent-contrast`, `--secondary`.
|
||||
3. Components use utilities like `bg-surface`, `text-text`, `text-accent`
|
||||
(mapped from these variables), so they update automatically.
|
||||
|
||||
### Contrast
|
||||
|
||||
Verify WCAG AA (4.5:1 for body text) whenever you change a token pair. The
|
||||
current combinations were chosen for AA compliance. The `--accent` on the neutral
|
||||
light surface uses a deeper amber (`#b45309`) specifically to meet AA on white.
|
||||
|
||||
---
|
||||
|
||||
## Motion
|
||||
|
||||
Motion is layered and **always** respects `prefers-reduced-motion`:
|
||||
|
||||
1. **Hero background** (`AnimatedBackground.tsx`):
|
||||
- A CSS mesh-gradient layer (GPU-friendly, animated via the
|
||||
`animate-gradient-shift` keyframes in `animations.css`).
|
||||
- An optional `<canvas>` particle field (slow drifting dots) on the home hero
|
||||
only. It renders at devicePixelRatio (capped at 2), pauses when off-screen,
|
||||
and is **skipped entirely** under reduced motion.
|
||||
2. **Scroll reveals** (`Reveal.astro` + the `.reveal` class):
|
||||
- IntersectionObserver toggles `.is-visible`, triggering a CSS fade-up. Zero
|
||||
framework cost. The reduced-motion media query in `global.css` forces these
|
||||
to their final state instantly.
|
||||
3. **Page transitions**: Astro `<ClientRouter />` (View Transitions API) morphs
|
||||
between pages and persists the nav.
|
||||
4. **Nav blur on scroll**: a tiny inline script adds `.scrolled` after a few px,
|
||||
enabling backdrop-blur + a hairline border + shadow.
|
||||
5. **Hover micro-interactions**: Tailwind transitions on cards/buttons (lift,
|
||||
accent glow, arrow nudge).
|
||||
|
||||
### Disabling motion
|
||||
|
||||
Everything is gated by the global reduced-motion rule in `global.css`:
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.001ms !important;
|
||||
transition-duration: 0.001ms !important;
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The canvas island additionally checks `matchMedia('(prefers-reduced-motion:
|
||||
reduce)')` before drawing, so even JS-driven motion is skipped.
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
Self-hosted variable fonts via Fontsource (woff2, no external requests):
|
||||
|
||||
- **Headings / UI:** Plus Jakarta Sans Variable (geometric sans)
|
||||
- **Body:** Inter Variable
|
||||
- **Mono / kickers / quotes:** JetBrains Mono Variable
|
||||
|
||||
Font sizes use `clamp()` for fluid scaling (see the `h1`-`h4` rules in
|
||||
`global.css`).
|
||||
Reference in New Issue
Block a user