mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
35c09f2854
- Store domain shown as Store.GregKilmer.com (no uppercase transform) - Cards and panels 10px corners; buttons pill-shaped - Canvas star/circuit violet switched to brand violet #6A2FE0 - Nav, store nav and footer seal at the brand's 72px minimum (nav 80px tall) - Faint seals on contact, store cards, deck boxes, order and professional Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
162 lines
6.8 KiB
Markdown
162 lines
6.8 KiB
Markdown
# Theming & Motion Guide
|
|
|
|
How color, light/dark mode, section tone, and animation work on this site.
|
|
|
|
---
|
|
|
|
## Palette
|
|
|
|
The site uses the Patiun LLC brand palette (shared by Patiun and Greg Kilmer),
|
|
exposed as CSS variables in `src/styles/global.css` under `@theme`:
|
|
|
|
| Token | Value | Meaning |
|
|
|---|---|---|
|
|
| `--color-teal` | `#14A39A` | Patiun Teal, primary: buttons, fills, the glyph |
|
|
| `--color-teal-bright` | `#2BC2B7` | Teal text and links on dark grounds |
|
|
| `--color-teal-deep` | `#0F8C84` | Teal marks on light grounds |
|
|
| `--color-slate-teal` | `#2D4A58` | Dark end of the Tide gradient |
|
|
| `--color-gold` | `#C9A24A` | Alchemist Gold: stars, rules, seal lines (never a large fill) |
|
|
| `--color-gold-bright` | `#D8B35A` | Gold text on dark grounds |
|
|
| `--color-gold-deep` | `#8A6516` | Gold text under 24px on Starlight |
|
|
| `--color-violet` / `--color-indigo` | `#6A2FE0` / `#3B1F8F` | Nebula light only, never text |
|
|
| `--color-midnight` | `#131C2B` | Panels, tiles, browser theme color |
|
|
| `--color-sky` | `#0E1522` | Night-sky ground |
|
|
| `--color-starlight` | `#F4F2ED` | Text on dark; paper ground |
|
|
|
|
The semantic Tailwind tokens (`--color-accent`, `--color-surface`, ...) resolve
|
|
at `:root`, so content sections render with the Starlight values in
|
|
`themes.css`. Night-sky bands (the nav and page heroes) carry the `.on-sky`
|
|
class, which re-points accent and gold to their on-dark values.
|
|
|
|
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, names, card titles:** Cinzel Variable (`font-display`, used by
|
|
`h1`-`h4` automatically). Open tracking, never for paragraphs.
|
|
- **Body and UI:** Montserrat Variable (`font-sans`, `font-body`).
|
|
- **Eyebrows / kickers:** Montserrat uppercase with wide tracking (`font-eyebrow`).
|
|
- **Code-like blocks only:** JetBrains Mono Variable (`font-mono`).
|
|
|
|
Font sizes use `clamp()` for fluid scaling (see the `h1`-`h4` rules in
|
|
`global.css`).
|
|
|
|
---
|
|
|
|
## Icons and motifs
|
|
|
|
- **Icons:** `<Icon name="..." />` (Astro) and `<BrandIcon name="..." />` (React
|
|
islands) render the Patiun stroke icon set in `src/lib/brand-icons.ts`. Call
|
|
sites can use either the brand name (`dice`) or the mdi name (`dice-multiple`);
|
|
`brandIconAliases` maps one to the other. Only third-party logos (GitHub,
|
|
LinkedIn, Steam, ...) fall back to mdi. The gold star accent uses
|
|
`--icon-gold` (deep gold on Starlight, flat gold inside `.on-sky`). The file is
|
|
generated from the brand source (`newicons.py`); add icons there.
|
|
- **Motifs:** `<Motif name="..." />` shows a brand motif from `public/motifs/`,
|
|
copied from the brand files with ring text outlined to paths. `-light` files
|
|
are the Starlight recolor. One focal motif per surface, kept faint. Every
|
|
page carries at least one seal: night-sky heroes have the turning layered
|
|
seal, and pages without a hero use `<PageSeal name="..." />` behind the header.
|
|
- **Shape:** cards and panels have 10px corners (`--radius-xl`/`2xl`/`3xl` are
|
|
pinned to 10px); buttons and tags are pills. The Patiun seal is never shown
|
|
below 72px (nav and footer use 72px).
|
|
- **Gold accents:** image frames, quote bars, dividers and rules use
|
|
`--color-gold`; teal stays for links, buttons and icons.
|