feat(ui): mobile responsive pass, larger type, pulse vote background, header

- Mobile: a hamburger nav with a dropdown, and ≤767/720px breakpoints
  across pages that collapse multi-column grids to one column and cut the
  112px desktop side padding down for phones; admin gets a phone pass too.
- Readability: bump the type-scale tokens and the small hardcoded sizes
  across user-facing pages (roadmap route excepted — already enlarged).
- Pulse votes now sit in a warm terracotta-tinted panel so they stand out.
- Header: 50% larger Fenja AI logo, the dot vertically centred to it, and a
  rebalanced "Project Bifrost" lockup (smaller, matched cap heights).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonathan Hvid 2026-06-10 17:18:48 +02:00
parent c509dc66ed
commit 50d5922dcd
21 changed files with 260 additions and 79 deletions

View file

@ -1416,3 +1416,17 @@
transition: opacity var(--duration-fast) var(--ease-standard); transition: opacity var(--duration-fast) var(--ease-standard);
} }
.bs-copy-btn:hover { opacity: 0.88; } .bs-copy-btn:hover { opacity: 0.88; }
/* Phone (600px)
The 767px breakpoint already stacks the sidebar + two-pane and the list
grid. This pass keeps the chrome from overflowing on a real phone:
lighter padding, a search box that can shrink, stacked summary rows and
panel footer buttons. Admin is fenja-only, so this is a "fit, don't
overflow" pass rather than a native mobile redesign. */
@media (max-width: 600px) {
.bs-topbar { padding: 0 var(--space-4); }
.bs-main { padding: var(--space-4) var(--space-4); }
.bs-search-form { min-width: 0; }
.bs-summary-row { grid-template-columns: 1fr; gap: var(--space-1); }
.bs-panel-foot { flex-direction: column; align-items: stretch; gap: var(--space-2); }
}

View file

@ -85,14 +85,14 @@ const authorRole = latest?.author_title ?? 'team';
} }
.rr-dispatch-eyebrow { .rr-dispatch-eyebrow {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 10px; font-size: 11px;
letter-spacing: 1.6px; letter-spacing: 1.6px;
text-transform: uppercase; text-transform: uppercase;
color: var(--on-surface-variant); color: var(--on-surface-variant);
} }
.rr-dispatch-kind { .rr-dispatch-kind {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 9px; font-size: 10px;
letter-spacing: 0.8px; letter-spacing: 0.8px;
padding: 2px 8px; padding: 2px 8px;
border-radius: 3px; border-radius: 3px;
@ -106,7 +106,7 @@ const authorRole = latest?.author_title ?? 'team';
.rr-dispatch-all { .rr-dispatch-all {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: 1px; letter-spacing: 1px;
color: var(--on-surface-variant); color: var(--on-surface-variant);
text-transform: uppercase; text-transform: uppercase;
@ -132,13 +132,13 @@ const authorRole = latest?.author_title ?? 'team';
} }
.rr-dispatch-text { max-width: 720px; } .rr-dispatch-text { max-width: 720px; }
.rr-dispatch-p1 { .rr-dispatch-p1 {
font-size: 14px; font-size: 15px;
line-height: 1.7; line-height: 1.7;
color: var(--on-surface); color: var(--on-surface);
margin: 0 0 10px; margin: 0 0 10px;
} }
.rr-dispatch-p2 { .rr-dispatch-p2 {
font-size: 14px; font-size: 15px;
line-height: 1.7; line-height: 1.7;
color: var(--on-surface-variant); color: var(--on-surface-variant);
margin: 0; margin: 0;
@ -158,12 +158,12 @@ const authorRole = latest?.author_title ?? 'team';
} }
.rr-dispatch-author-text { text-align: right; } .rr-dispatch-author-text { text-align: right; }
.rr-dispatch-author-name { .rr-dispatch-author-name {
font-size: 13px; font-size: 14px;
margin: 0; margin: 0;
color: var(--on-surface); color: var(--on-surface);
} }
.rr-dispatch-author-role { .rr-dispatch-author-role {
font-size: 11px; font-size: 12px;
margin: 1px 0 0; margin: 1px 0 0;
color: var(--on-surface-variant); color: var(--on-surface-variant);
} }
@ -178,12 +178,12 @@ const authorRole = latest?.author_title ?? 'team';
justify-content: center; justify-content: center;
font-family: var(--font-serif); font-family: var(--font-serif);
font-style: italic; font-style: italic;
font-size: 14px; font-size: 15px;
flex-shrink: 0; flex-shrink: 0;
} }
.rr-dispatch-cta { .rr-dispatch-cta {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: 1.2px; letter-spacing: 1.2px;
color: var(--pigment-terracotta); color: var(--pigment-terracotta);
text-transform: uppercase; text-transform: uppercase;

View file

@ -78,7 +78,7 @@ const tags = readFocusTags(member.focus_tags);
font-family: var(--font-serif); font-family: var(--font-serif);
font-style: italic; font-style: italic;
font-weight: 700; font-weight: 700;
font-size: 13px; font-size: 14px;
line-height: 1; line-height: 1;
flex-shrink: 0; flex-shrink: 0;
} }

View file

@ -149,7 +149,7 @@ const hasArrows = items.length > 3;
} }
.roadmap-all { .roadmap-all {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--pigment-terracotta); color: var(--pigment-terracotta);
@ -233,7 +233,7 @@ const hasArrows = items.length > 3;
} }
.card-status-label { .card-status-label {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 10px; font-size: 11px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
font-weight: 600; font-weight: 600;
} }
@ -246,7 +246,7 @@ const hasArrows = items.length > 3;
margin: 0; margin: 0;
} }
.card-desc { .card-desc {
font-size: 12px; font-size: 13px;
line-height: 1.55; line-height: 1.55;
color: var(--on-surface-variant); color: var(--on-surface-variant);
margin: 0; margin: 0;

View file

@ -31,7 +31,21 @@ const year = new Date().getFullYear();
<span class="wordmark-project">Project <em class="wordmark-bifrost">Bifrost</em></span> <span class="wordmark-project">Project <em class="wordmark-bifrost">Bifrost</em></span>
</a> </a>
<nav class="nav-right" aria-label="Main navigation"> <button
type="button"
class="nav-toggle"
id="nav-toggle"
aria-label="Menu"
aria-controls="nav-menu"
aria-expanded="false"
>
<svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true">
<path class="nav-toggle-bars" d="M3 6h18M3 12h18M3 18h18" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
<path class="nav-toggle-x" d="M5 5l14 14M19 5L5 19" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
</svg>
</button>
<nav class="nav-right" id="nav-menu" aria-label="Main navigation">
{navLinks.map(({ href, label }) => ( {navLinks.map(({ href, label }) => (
<a <a
href={href} href={href}
@ -121,40 +135,41 @@ const year = new Date().getFullYear();
color: var(--on-surface); color: var(--on-surface);
} }
.wordmark { .wordmark {
height: 20px; height: 30px; /* 50% larger than the prior 20px lockup */
width: auto; width: auto;
display: block; display: block;
} }
.wordmark-sep { .wordmark-sep {
/* Flex-centred against the logo height so the dot sits on the vertical
middle of the "Fenja AI" logo. */
display: inline-flex;
align-items: center;
height: 30px;
color: var(--on-surface-muted); color: var(--on-surface-muted);
font-family: var(--font-serif); font-family: var(--font-serif);
font-size: 18px; font-size: 22px;
line-height: 1; line-height: 1;
/* Optical kern — the bullet's typographic centre sits slightly above
its baseline in Newsreader; this nudges it onto the visual midline. */
transform: translateY(-2px);
} }
/* Italic Newsreader renders ~10% visually taller than regular at the /* Project (regular) + Bifrost (italic) share a baseline. Italic Newsreader
same font-size — the cursive B has a flourish extending past the renders a touch taller at the same size, so Bifrost is set 1px smaller so
cap line. Drop Bifrost to 16px so its cap+flourish optical height the two words read at the same cap height. inline-block + small symmetric
matches Project's 18px cap, and use inline-block + tiny vertical padding keeps the gradient-clip bbox from chopping the italic flourish. */
padding so the gradient-clip bbox doesn't chop the flourish off. */
.wordmark-project, .wordmark-project,
.wordmark-bifrost { .wordmark-bifrost {
font-family: var(--font-serif); font-family: var(--font-serif);
font-weight: 400; font-weight: 400;
letter-spacing: var(--tracking-snug); letter-spacing: var(--tracking-snug);
line-height: 1.4; line-height: 1;
} }
.wordmark-project { .wordmark-project {
font-size: 18px; font-size: 20px;
color: var(--on-surface); color: var(--on-surface);
} }
.wordmark-bifrost { .wordmark-bifrost {
display: inline-block; display: inline-block;
font-size: 16px; font-size: 19px;
font-style: italic; font-style: italic;
padding: 3px 0 1px; padding: 2px 0;
vertical-align: baseline; vertical-align: baseline;
background-image: linear-gradient( background-image: linear-gradient(
90deg, 90deg,
@ -169,6 +184,23 @@ const year = new Date().getFullYear();
color: transparent; color: transparent;
} }
/* ── Mobile menu toggle (hidden on desktop) ─────────────────────── */
.nav-toggle {
display: none;
margin-left: auto;
width: 40px;
height: 40px;
align-items: center;
justify-content: center;
background: none;
border: none;
padding: 0;
cursor: pointer;
color: var(--on-surface);
border-radius: var(--radius-sm);
}
.nav-toggle .nav-toggle-x { display: none; }
/* ── Nav links ──────────────────────────────────────────────────── */ /* ── Nav links ──────────────────────────────────────────────────── */
.nav-right { .nav-right {
display: flex; display: flex;
@ -302,4 +334,80 @@ const year = new Date().getFullYear();
color: var(--on-surface-variant); color: var(--on-surface-variant);
border-bottom: none; border-bottom: none;
} }
/* ── Mobile (≤767px) ────────────────────────────────────────────── */
@media (max-width: 767px) {
.nav-inner { padding: 0 var(--space-5); gap: var(--space-3); }
.nav-toggle { display: inline-flex; }
.nav.open .nav-toggle-bars { display: none; }
.nav.open .nav-toggle-x { display: inline; }
/* Right-hand nav becomes a full-width dropdown under the bar. */
.nav-right {
position: absolute;
top: 56px;
left: 0;
right: 0;
margin-left: 0;
flex-direction: column;
align-items: stretch;
gap: 0;
padding: var(--space-2) var(--space-5) var(--space-4);
background: var(--glass-surface);
backdrop-filter: var(--glass-blur);
-webkit-backdrop-filter: var(--glass-blur);
border-bottom: var(--ghost-border);
box-shadow: var(--shadow-float);
display: none;
}
.nav.open .nav-right { display: flex; }
/* Comfortable tap targets in the dropdown. */
.nav-right .nav-link,
.nav-right .nav-user-name,
.nav-right .logout-btn {
display: flex;
align-items: center;
min-height: 44px;
width: 100%;
padding: var(--space-2) var(--space-2);
font-size: var(--text-body-md);
border-radius: var(--radius-sm);
}
.nav-divider {
width: auto;
height: 1px;
margin: var(--space-2) 0;
transform: scaleY(0.5);
}
.nav-logout-form { width: 100%; }
.logout-btn { justify-content: flex-start; }
/* Footer stacks. */
.footer-inner {
flex-direction: column;
align-items: flex-start;
gap: var(--space-4);
padding: 0 var(--space-5);
}
}
</style> </style>
<script>
// Mobile nav: toggle the dropdown, keep aria in sync, close on link tap or
// when the viewport grows back to desktop.
const nav = document.querySelector<HTMLElement>('.nav');
const toggle = nav?.querySelector<HTMLButtonElement>('#nav-toggle');
const menu = nav?.querySelector<HTMLElement>('#nav-menu');
function setOpen(open: boolean) {
if (!nav || !toggle) return;
nav.classList.toggle('open', open);
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
}
toggle?.addEventListener('click', () => setOpen(!nav!.classList.contains('open')));
menu?.querySelectorAll('a').forEach((a) => a.addEventListener('click', () => setOpen(false)));
window.addEventListener('resize', () => { if (window.innerWidth > 767) setOpen(false); });
</script>

View file

@ -293,4 +293,8 @@ const saved = Astro.url.searchParams.get('saved') === '1';
color: var(--on-surface-muted); color: var(--on-surface-muted);
margin: 0; margin: 0;
} }
@media (max-width: 767px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
}
</style> </style>

View file

@ -524,4 +524,10 @@ const typeColors: Record<ContributionType, string> = {
white-space: nowrap; white-space: nowrap;
border-width: 0; border-width: 0;
} }
@media (max-width: 767px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
/* Filter + sort tab groups wrap instead of overflowing. */
.feed-controls { flex-wrap: wrap; gap: var(--space-3); }
}
</style> </style>

View file

@ -191,4 +191,8 @@ if (Astro.request.method === 'POST') {
transition: opacity var(--duration-fast) var(--ease-standard); transition: opacity var(--duration-fast) var(--ease-standard);
} }
.btn-primary:hover { opacity: 0.9; } .btn-primary:hover { opacity: 0.9; }
@media (max-width: 767px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
}
</style> </style>

View file

@ -38,4 +38,8 @@ const user = Astro.locals.user;
.page-title { margin: 0; } .page-title { margin: 0; }
.reading-col { max-width: var(--reading-max); } .reading-col { max-width: var(--reading-max); }
.lead { color: var(--on-surface-variant); } .lead { color: var(--on-surface-variant); }
@media (max-width: 767px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
}
</style> </style>

View file

@ -268,8 +268,8 @@ const bodyHtml = renderMd(d.body);
/* ── Inline poll attached to the dispatch ──────────────────────── */ /* ── Inline poll attached to the dispatch ──────────────────────── */
.inline-poll { .inline-poll {
margin-top: var(--space-7); margin-top: var(--space-7);
background: var(--surface-card); background: rgba(185, 107, 88, 0.08);
border: 0.5px solid var(--surface-card-border); border: none;
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
padding: var(--space-6); padding: var(--space-6);
display: flex; display: flex;
@ -399,6 +399,7 @@ const bodyHtml = renderMd(d.body);
.adj-empty {} /* placeholder for missing prev/next slot */ .adj-empty {} /* placeholder for missing prev/next slot */
@media (max-width: 640px) { @media (max-width: 640px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
.adjacent { grid-template-columns: 1fr; } .adjacent { grid-template-columns: 1fr; }
.adj-next { text-align: left; align-items: flex-start; } .adj-next { text-align: left; align-items: flex-start; }
.adj-next .adj-kind-pill { align-self: flex-start; } .adj-next .adj-kind-pill { align-self: flex-start; }

View file

@ -170,6 +170,7 @@ function fmt(iso: string): string {
} }
@media (max-width: 720px) { @media (max-width: 720px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
.d-link { .d-link {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: var(--space-3); gap: var(--space-3);

View file

@ -504,6 +504,7 @@ const heroAudience = hero?.audience ?? 'Members only';
} }
@media (max-width: 720px) { @media (max-width: 720px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
.hero-body { grid-template-columns: 1fr; } .hero-body { grid-template-columns: 1fr; }
.hero-body::after { display: none; } .hero-body::after { display: none; }
.past-grid { grid-template-columns: 1fr; } .past-grid { grid-template-columns: 1fr; }

View file

@ -154,6 +154,7 @@ function fmt(part: Intl.DateTimeFormatOptions, iso: string): string {
} }
@media (max-width: 720px) { @media (max-width: 720px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
.past-list { grid-template-columns: 1fr; } .past-list { grid-template-columns: 1fr; }
} }
</style> </style>

View file

@ -563,4 +563,12 @@ const innofoundarLogoExists = existsSync(join(process.cwd(), 'public/innofounder
margin: 0; margin: 0;
line-height: var(--leading-relaxed); line-height: var(--leading-relaxed);
} }
/* ── Mobile (≤767px) ────────────────────────────────────────────── */
@media (max-width: 767px) {
.page { padding: 0 var(--space-5) var(--space-12); }
/* Stack the two-column rows. */
.fenja-row,
.ask-grid { grid-template-columns: 1fr; }
}
</style> </style>

View file

@ -199,6 +199,7 @@ function memberSinceLabel(member: { cab_joined_date: string | null; created_at:
} }
@media (max-width: 720px) { @media (max-width: 720px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
.m-row { grid-template-columns: 52px 1fr; } .m-row { grid-template-columns: 52px 1fr; }
.m-tags { .m-tags {
grid-column: 1 / -1; grid-column: 1 / -1;

View file

@ -421,4 +421,13 @@ const tiers = [
margin: 0; margin: 0;
line-height: var(--leading-relaxed); line-height: var(--leading-relaxed);
} }
/* ── Mobile (≤767px) ────────────────────────────────────────────── */
@media (max-width: 767px) {
.page { padding: 0 var(--space-5) var(--space-12); }
/* Stack the label / content / tag rows. */
.arch-row,
.tier-row,
.extends-item { grid-template-columns: 1fr; gap: var(--space-2); }
}
</style> </style>

View file

@ -110,26 +110,16 @@ const members = getAllCabMembers();
<AppLayout title="Pulse" user={user}> <AppLayout title="Pulse" user={user}>
<div class="page"> <div class="page">
<!-- ── Greeting ─────────────────────────────────────────────── --> <!-- ── Hero event card (--ink) — greeting now lives inside it ──── -->
<section class="cascade greeting">
<div class="greeting-left">
<h1 class="greeting-line">{greetingPrefix}<em class="greeting-first">{firstName}</em>.</h1>
</div>
{memberNumberLabel && (
<div class="greeting-right">
<p class="greeting-member">{memberNumberLabel}</p>
<p class="greeting-circle">Founding circle</p>
</div>
)}
</section>
<!-- ── Hero event card (--ink) ──────────────────────────────── -->
<section class="cascade hero-slot" aria-label="Next gathering"> <section class="cascade hero-slot" aria-label="Next gathering">
<EventHeroCard <EventHeroCard
event={hero} event={hero}
attendees={heroAttendees} attendees={heroAttendees}
confirmedCount={heroConfirmedCount} confirmedCount={heroConfirmedCount}
myRsvp={heroMyRsvp} myRsvp={heroMyRsvp}
greetingPrefix={greetingPrefix}
firstName={firstName}
memberLabel={memberNumberLabel}
/> />
</section> </section>
@ -291,8 +281,7 @@ const members = getAllCabMembers();
(96px between editorial / roadmap / council); editorial-row internal (96px between editorial / roadmap / council); editorial-row internal
dispatch → 'Earlier' gap stays tight at the original 48px because dispatch → 'Earlier' gap stays tight at the original 48px because
they're the same story. */ they're the same story. */
.greeting { margin-top: 64px; } /* below nav */ .hero-slot { margin-top: 24px; } /* first section, below nav */
.hero-slot { margin-top: 80px; } /* greeting → hero */
.also-coming-up { margin-top: 18px; } /* hero → also (tight; pair) */ .also-coming-up { margin-top: 18px; } /* hero → also (tight; pair) */
.editorial-row { margin-top: 96px; } /* also → editorial */ .editorial-row { margin-top: 96px; } /* also → editorial */
.roadmap-wrap { margin-top: 96px; } /* editorial → roadmap */ .roadmap-wrap { margin-top: 96px; } /* editorial → roadmap */
@ -344,7 +333,7 @@ const members = getAllCabMembers();
.greeting-first { font-style: italic; } .greeting-first { font-style: italic; }
.greeting-member { .greeting-member {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--on-surface-variant); color: var(--on-surface-variant);
@ -352,14 +341,19 @@ const members = getAllCabMembers();
} }
.greeting-circle { .greeting-circle {
font-family: var(--font-serif); font-family: var(--font-serif);
font-size: 14px; font-size: 15px;
color: var(--on-surface); color: var(--on-surface);
margin: 0; margin: 0;
} }
@media (max-width: 720px) { @media (max-width: 720px) {
.page { padding: 32px 20px 64px; }
.greeting { grid-template-columns: 1fr; align-items: start; } .greeting { grid-template-columns: 1fr; align-items: start; }
.greeting-right { align-items: flex-start; } .greeting-right { align-items: flex-start; }
/* "Also coming up" strip stacks and wraps instead of overflowing. */
.also-coming-up { flex-direction: column; align-items: flex-start; gap: var(--space-3); }
.also-list { flex-wrap: wrap; gap: 12px 18px; }
.also-title { max-width: 70vw; }
} }
/* ── 'Also coming up' strip (plain text on cream) ─────────────── */ /* ── 'Also coming up' strip (plain text on cream) ─────────────── */
@ -403,7 +397,7 @@ const members = getAllCabMembers();
} }
.also-eyebrow { .also-eyebrow {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 9px; font-size: 10px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--pigment-terracotta); color: var(--pigment-terracotta);
@ -411,13 +405,13 @@ const members = getAllCabMembers();
} }
.also-month-kind { .also-month-kind {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 9px; font-size: 10px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--on-surface-variant); color: var(--on-surface-variant);
} }
.also-title { .also-title {
font-size: 13px; font-size: 14px;
color: var(--on-surface); color: var(--on-surface);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
@ -426,7 +420,7 @@ const members = getAllCabMembers();
} }
.also-link { .also-link {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--pigment-terracotta); color: var(--pigment-terracotta);
@ -452,13 +446,13 @@ const members = getAllCabMembers();
} }
.dispatch-byline-name { .dispatch-byline-name {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 12px; font-size: 13px;
font-weight: 600; font-weight: 600;
color: var(--on-surface); color: var(--on-surface);
} }
.dispatch-byline-time { .dispatch-byline-time {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
color: var(--on-surface-variant); color: var(--on-surface-variant);
} }
.dispatch-kind-pill { .dispatch-kind-pill {
@ -467,7 +461,7 @@ const members = getAllCabMembers();
padding: 2px 8px; padding: 2px 8px;
border-radius: 3px; border-radius: 3px;
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 9px; font-size: 10px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
font-weight: 600; font-weight: 600;
margin-left: auto; margin-left: auto;
@ -483,7 +477,7 @@ const members = getAllCabMembers();
} }
.dispatch-para-lead { .dispatch-para-lead {
margin: var(--space-2) 0 0; margin: var(--space-2) 0 0;
font-size: 14px; font-size: 15px;
line-height: 1.7; line-height: 1.7;
color: var(--on-surface); color: var(--on-surface);
} }
@ -491,7 +485,7 @@ const members = getAllCabMembers();
margin-top: var(--space-2); margin-top: var(--space-2);
align-self: flex-start; align-self: flex-start;
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--pigment-terracotta); color: var(--pigment-terracotta);
@ -511,7 +505,7 @@ const members = getAllCabMembers();
} }
.earlier-label { .earlier-label {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--on-surface-variant); color: var(--on-surface-variant);
@ -537,26 +531,34 @@ const members = getAllCabMembers();
.earlier-link:hover { border-bottom: none; opacity: 0.7; } .earlier-link:hover { border-bottom: none; opacity: 0.7; }
.earlier-title { .earlier-title {
font-family: var(--font-serif); font-family: var(--font-serif);
font-size: 15px; font-size: 16px;
line-height: 1.3; line-height: 1.3;
} }
.earlier-meta { .earlier-meta {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 10px; font-size: 11px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--on-surface-variant); color: var(--on-surface-variant);
white-space: nowrap; white-space: nowrap;
} }
/* Pulse column */ /* Pulse column — tinted panel so the vote clearly stands apart from the
.pulse-col { display: flex; flex-direction: column; gap: 14px; } dispatch beside it. Tonal colour shift, no border (per design system). */
.pulse-col {
display: flex;
flex-direction: column;
gap: 14px;
background: rgba(185, 107, 88, 0.08);
border-radius: var(--radius-lg);
padding: var(--space-5) var(--space-5) var(--space-6);
}
.pulse-eyebrow { .pulse-eyebrow {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 10px; font-size: 11px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--pigment-terracotta); color: var(--pigment-terracotta);
@ -578,7 +580,7 @@ const members = getAllCabMembers();
} }
.pulse-status { .pulse-status {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--on-surface-variant); color: var(--on-surface-variant);
@ -599,7 +601,7 @@ const members = getAllCabMembers();
border: none; border: none;
border-left: 2px solid rgba(0, 0, 0, 0.1); border-left: 2px solid rgba(0, 0, 0, 0.1);
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 13px; font-size: 14px;
color: var(--on-surface); color: var(--on-surface);
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
@ -619,7 +621,7 @@ const members = getAllCabMembers();
.pulse-option-letter { .pulse-option-letter {
color: var(--on-surface-variant); color: var(--on-surface-variant);
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 10px; font-size: 11px;
font-weight: 600; font-weight: 600;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
@ -633,7 +635,7 @@ const members = getAllCabMembers();
.pulse-option-pct { .pulse-option-pct {
margin-left: auto; margin-left: auto;
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 10px; font-size: 11px;
font-weight: 600; font-weight: 600;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
color: var(--on-surface-variant); color: var(--on-surface-variant);
@ -663,7 +665,7 @@ const members = getAllCabMembers();
.council-title em { font-style: italic; } .council-title em { font-style: italic; }
.council-all { .council-all {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
letter-spacing: var(--tracking-wider); letter-spacing: var(--tracking-wider);
text-transform: uppercase; text-transform: uppercase;
color: var(--pigment-terracotta); color: var(--pigment-terracotta);
@ -724,21 +726,21 @@ const members = getAllCabMembers();
.council-tile-name { .council-tile-name {
font-family: var(--font-serif); font-family: var(--font-serif);
font-weight: 400; font-weight: 400;
font-size: 15px; font-size: 16px;
line-height: 1.15; line-height: 1.15;
color: var(--on-surface); color: var(--on-surface);
white-space: nowrap; white-space: nowrap;
} }
.council-tile-title { .council-tile-title {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 11px; font-size: 12px;
color: var(--on-surface-variant); color: var(--on-surface-variant);
line-height: 1.35; line-height: 1.35;
white-space: nowrap; white-space: nowrap;
} }
.council-tile-org { .council-tile-org {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 10px; font-size: 11px;
letter-spacing: var(--tracking-wide); letter-spacing: var(--tracking-wide);
text-transform: uppercase; text-transform: uppercase;
color: var(--on-surface-variant); color: var(--on-surface-variant);

View file

@ -240,4 +240,8 @@ const next = sorted[currentIndex - 1] ?? null;
.post-nav-link:hover .nav-title { .post-nav-link:hover .nav-title {
color: var(--on-surface); color: var(--on-surface);
} }
@media (max-width: 767px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
}
</style> </style>

View file

@ -168,4 +168,11 @@ const updates = allUpdates.sort(
color: var(--on-surface-variant); color: var(--on-surface-variant);
border-bottom: none; border-bottom: none;
} }
/* ── Mobile (≤720px) ────────────────────────────────────────────── */
@media (max-width: 720px) {
.page { padding: var(--space-8) var(--space-5) var(--space-12); }
/* Date stacks above the content instead of a cramped 9rem column. */
.update-item { grid-template-columns: 1fr; gap: var(--space-2); }
}
</style> </style>

View file

@ -289,4 +289,10 @@ const user = Astro.locals.user;
color: var(--on-surface-variant); color: var(--on-surface-variant);
margin: 0; margin: 0;
} }
/* ── Mobile (≤767px) ────────────────────────────────────────────── */
@media (max-width: 767px) {
.page { padding: 0 var(--space-5) var(--space-12); }
.bifrost-context-section { grid-template-columns: 1fr; gap: var(--space-3); }
}
</style> </style>

View file

@ -71,14 +71,14 @@
--text-display-md: clamp(2.5rem, 4vw, 3.5rem); --text-display-md: clamp(2.5rem, 4vw, 3.5rem);
--text-headline-lg: 2.25rem; --text-headline-lg: 2.25rem;
--text-headline-md: 1.75rem; --text-headline-md: 1.75rem;
--text-headline-sm: 1.375rem; --text-headline-sm: 1.4375rem; /* 23px (was 22) */
--text-title-lg: 1.125rem; --text-title-lg: 1.1875rem; /* 19px (was 18) */
--text-title-md: 1rem; --text-title-md: 1.0625rem; /* 17px (was 16) */
--text-body-lg: 1.0625rem; --text-body-lg: 1.125rem; /* 18px (was 17) */
--text-body-md: 1rem; --text-body-md: 1.0625rem; /* 17px (was 16) — base body */
--text-body-sm: 0.875rem; --text-body-sm: 0.9375rem; /* 15px (was 14) */
--text-label-md: 0.8125rem; --text-label-md: 0.875rem; /* 14px (was 13) */
--text-label-sm: 0.75rem; --text-label-sm: 0.8125rem; /* 13px (was 12) */
/* --- Tracking --- */ /* --- Tracking --- */
--tracking-tight: -0.02em; --tracking-tight: -0.02em;