/events:
- Header: EVENTS · 'Where the council gathers.' · one-line subtitle
- Hero invitation card on --ink for the soonest non-office_hours event:
NEXT UP · MEMBERS ONLY / INVITATION BY HAND eyebrow strip, two-column
date/detail body separated by a 0.5px vertical line, foot strip with
'{capacity} seats · {confirmed} confirmed' + AvatarPile of confirmed
attendees and the RSVP CTA. The RSVP button toggles between cream-on-ink
'Save your seat →' and outlined 'You're confirmed ✓ Change'. Empty-state
card retains the visual weight when no upcoming non-office_hours event.
- ALSO COMING UP — every other upcoming event including office_hours.
Three-column rows; the right column uses event.action_label or falls back
to defaultActionLabel(kind). Studio hours surfaces with 'Book a slot →'.
- PAST GATHERINGS — two-column grid. Each card has a 56px thumb: photo_url
if set, else a copper-tinted notes square when notes_url is present, else
a deterministic two-pigment gradient block. View all → links to /events/past.
/events/past — same card component, full list of starts_at < now() events.
No boolean past flag column; filter is purely date-based.
AvatarPile (src/components/AvatarPile.astro) — reusable. Overlapping circle
slots with a 1.5px border in a caller-provided colour (defaults to surface,
the hero card overrides to --ink so circles read on dark). Stacks z-index
so leftmost is on top; +N overflow chip at the end.
format.ts: adds eventKindLabel (office_hours → 'Studio hours') and
defaultActionLabel per kind.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>