project-bifrost-platform/src/pages/events/past.astro
Jonathan Hvid 66c3f6492f style: drop eyebrows + body italics across editorial pages
Applies the v3 rules globally: italics reserved for the Bifrost wordmark
and section-links; uppercase tracked eyebrows removed from page heads
and content sections.

Pages updated:
- /members: drops the 'MEMBERS' eyebrow + italic on h1 + italic on member
  name + italic on pull-quote.
- /events: drops the head eyebrow + 'Next up · Members only' /
  'Invitation by hand' hero eyebrows + 'Also coming up' / 'Past
  gatherings' sub-section eyebrows + italics on hero day, hero title,
  also-row titles, past-card titles. The past-gatherings header-row
  'View all →' link migrates to the bottom of the section as a
  section-link.
- /events/past: drops the eyebrow + italic h1; back-link uses
  .section-link.
- /dispatches/: drops the 'DISPATCHES' eyebrow + italic h1 + dispatch-row
  title italic + date column italic.
- /dispatches/[slug]: drops italic on the article title + h2/h3 inside
  rendered markdown + blockquote italic + adjacent prev/next title
  italic. Back-link migrates to .section-link.
- /roadmap: drops the 'ROADMAP' eyebrow and the .lead class on the
  subtitle.

Orphaned eyebrow class rules left in place; harmless and the next
visual pass can sweep them with the rest of the unused CSS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 09:52:29 +02:00

159 lines
4.8 KiB
Text

---
import AppLayout from '../../layouts/AppLayout.astro';
import { getPastEvents, getEventRsvpCount } from '../../lib/db';
import { pigmentForId } from '../../lib/format';
const user = Astro.locals.user;
const past = getPastEvents(500);
function parseUtc(s: string): Date {
if (/T.*[Zz]$/.test(s) || /[+-]\d{2}:?\d{2}$/.test(s)) return new Date(s);
return new Date(s.replace(' ', 'T') + 'Z');
}
function fmt(part: Intl.DateTimeFormatOptions, iso: string): string {
return new Intl.DateTimeFormat('en-GB', { ...part, timeZone: 'Europe/Copenhagen' }).format(parseUtc(iso));
}
---
<AppLayout title="Past gatherings" user={user}>
<div class="page">
<header class="head">
<h1 class="head-title">The archive.</h1>
<p class="head-sub">Everything the council has gathered around so far.</p>
<a href="/events" class="section-link back-link">← Back to upcoming</a>
</header>
{past.length === 0 ? (
<p class="body-md empty">No past events yet.</p>
) : (
<ul class="past-list">
{past.map(ev => {
const monthCode = fmt({ month: 'short' }, ev.starts_at).toUpperCase();
const attended = getEventRsvpCount(ev.slug).going;
const hasNotes = !!ev.notes_url;
const pigA = pigmentForId(ev.id);
const pigB = pigmentForId(ev.id + 1);
return (
<li class="past-card">
{ev.photo_url ? (
<img class="past-thumb" src={ev.photo_url} alt="" loading="lazy" />
) : hasNotes ? (
<a href={ev.notes_url!} class="past-thumb past-thumb--notes" aria-label="Read the notes">
<span class="past-thumb-month">{monthCode}</span>
</a>
) : (
<div
class="past-thumb past-thumb--gradient"
style={`background: linear-gradient(135deg, ${pigA.hex}, ${pigB.hex});`}
aria-hidden="true"
>
<span class="past-thumb-month">{monthCode}</span>
</div>
)}
<div class="past-text">
<h3 class="past-title">{ev.title}</h3>
<p class="past-meta">
{fmt({ day: 'numeric', month: 'long', year: 'numeric' }, ev.starts_at)}
{ev.location && ` · ${ev.location}`}
</p>
<p class="past-foot label-sm">
{attended} attended · {hasNotes ? 'Notes shared' : 'No notes'}
</p>
</div>
</li>
);
})}
</ul>
)}
</div>
</AppLayout>
<style>
.page {
padding: var(--space-12) var(--space-20) var(--space-16);
max-width: var(--content-max);
margin: 0 auto;
display: flex;
flex-direction: column;
gap: var(--space-8);
}
.head { max-width: 46rem; }
.head-eyebrow {
letter-spacing: var(--tracking-wider);
text-transform: uppercase;
color: var(--on-surface-variant);
margin-bottom: var(--space-3);
}
.head-title {
font-family: var(--font-serif);
font-weight: 400;
font-size: var(--text-display-md);
letter-spacing: var(--tracking-tight);
line-height: var(--leading-tight);
color: var(--on-surface);
margin: 0;
}
.head-sub { color: var(--on-surface-variant); margin-top: var(--space-3); max-width: 32rem; }
.back-link { margin-top: var(--space-4); }
.empty { color: var(--on-surface-muted); }
.past-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-5);
}
.past-card {
display: grid;
grid-template-columns: 56px 1fr;
gap: var(--space-4);
align-items: start;
}
.past-thumb {
width: 56px;
height: 56px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
text-decoration: none;
border: none;
}
.past-thumb--notes {
background: color-mix(in oklab, var(--pigment-copper) 18%, transparent);
color: var(--pigment-copper);
}
.past-thumb-month {
font-family: var(--font-sans);
font-size: var(--text-label-sm);
letter-spacing: var(--tracking-wider);
text-transform: uppercase;
font-weight: 600;
color: rgba(250, 246, 238, 0.6);
}
.past-thumb--notes .past-thumb-month { color: var(--pigment-copper); }
.past-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.past-title {
font-family: var(--font-serif);
font-weight: 400;
font-size: 1.0625rem;
color: var(--on-surface);
margin: 0;
}
.past-meta { font-size: 0.75rem; color: var(--on-surface-variant); margin: 0; }
.past-foot {
color: var(--on-surface-muted);
letter-spacing: var(--tracking-wide);
margin: 0;
}
@media (max-width: 720px) {
.past-list { grid-template-columns: 1fr; }
}
</style>