feat(pulse): spacing pass + council section header + 7-item roadmap seed
Spacing — explicit per-section margins on /pulse rather than a single
gap. Page is padding: 40px 36px 80px now. Transitions match the spec:
greeting ─ 48px ─ below nav
greeting ─ 56px ─ hero
hero ─ 18px ─ also coming up (intentionally tight; related)
also ─ 72px ─ editorial row
editorial ─ 72px ─ roadmap
roadmap ─ 72px ─ council
The hero, editorial, roadmap and council transitions all sit at 72px so
the page reads as four distinct registers rather than a slab stack. The
hero → also-coming-up gap stays deliberately tight at 18px because the
two are a pair (the strip is the lighter outro to the indigo card).
Council section restructured to match the roadmap carousel framing:
- Outer card chrome dropped — no more single white surface wrapping the
grid. Section is just a header row + a 4-column grid of tiles.
- Header row: 22px serif 'The council' on the left, 11px terracotta
tracked uppercase 'See who our council is made up of →' on the right.
Same pattern as the roadmap header.
- Tiles: 38px avatar (down from 56), 15px serif name, 11px title,
10px tracked organisation. No background, no border. 24px grid gap.
- First 4 members render; if more, a 5th tile replaces the would-be
fifth member with a right-aligned 'See all N council members →' link.
With the current 4-member seed this case isn't exercised but the
branch is in place for when the council grows.
- 2-up on tablets, 1-up below 520px.
Seed update: roadmap now has 7 items spanning all four statuses (2
shipping / 1 in_beta / 2 exploring / 2 considering) ordered by
display_order 1..7. Traceability layer carries the 'Shaped by Lars'
attribution; Agentic query mode is attributed to Anna; Contextual memory
to Henriette. The rest are unattributed so the attribution trailer's
hidden case is exercised too. With 7 items the carousel arrows engage
and the right-edge fade is visible at start.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7bd3997564
commit
cde98f9454
2 changed files with 103 additions and 40 deletions
|
|
@ -169,12 +169,15 @@ db.prepare('INSERT INTO votes (pulse_id, user_id, option_index, voted_at) VALUES
|
|||
db.prepare('INSERT INTO votes (pulse_id, user_id, option_index, voted_at) VALUES (?,?,?,?)')
|
||||
.run(decisionPulseId, cabs[1].id, 1, nowIso(-30 * 60));
|
||||
|
||||
// ── Roadmap: 1 shipping / 1 beta / 2 exploring, attributions ───────
|
||||
// ── Roadmap: 7 items spanning shipping → considering, admin-ordered ──
|
||||
const roadmap = [
|
||||
{ title: 'Traceability layer', description: 'Every response cites its sources with structured provenance.', status: 'shipping', target: 'Live now', display_order: 10, shipped_at: nowIso(-2 * 24 * 3600), attributed: [cabs[0].id] },
|
||||
{ title: 'Document ingestion pipeline', description: 'Upload PDF, Word, plain text. Chunked, indexed, retrievable.', status: 'beta', target: null, display_order: 10, shipped_at: null, attributed: [cabs[1].id, cabs[2].id] },
|
||||
{ title: 'Contextual memory', description: 'The system learns the regulatory and organisational context over time.', status: 'exploring', target: 'Q3 2026', display_order: 10, shipped_at: null, attributed: [cabs[3].id] },
|
||||
{ title: 'Agentic query mode', description: 'Multi-step retrieval and synthesis with full provenance.', status: 'exploring', target: 'Q4 2026', display_order: 20, shipped_at: null, attributed: [] },
|
||||
{ title: 'Traceability layer', description: 'Every response cites its sources with structured provenance.', status: 'shipping', target: 'Live now', display_order: 1, shipped_at: nowIso(-2 * 24 * 3600), attributed: [cabs[0].id] },
|
||||
{ title: 'Audit log export', description: 'One-click export of every model call, source, and reviewer action.', status: 'shipping', target: 'Next week', display_order: 2, shipped_at: nowIso(-1 * 24 * 3600), attributed: [] },
|
||||
{ title: 'Agentic query mode', description: 'Multi-step retrieval and synthesis with full provenance.', status: 'in_beta', target: 'July', display_order: 3, shipped_at: null, attributed: [cabs[1].id] },
|
||||
{ title: 'Contextual memory', description: 'The system learns the regulatory and organisational context over time.', status: 'exploring', target: 'Q3 2026', display_order: 4, shipped_at: null, attributed: [cabs[3].id] },
|
||||
{ title: 'Multi-tenant isolation', description: 'Strict per-organisation data boundaries for shared deployments.', status: 'exploring', target: 'Q4 2026', display_order: 5, shipped_at: null, attributed: [] },
|
||||
{ title: 'Federated learning hooks', description: 'Train shared models across council members without moving data.', status: 'considering', target: '2027', display_order: 6, shipped_at: null, attributed: [] },
|
||||
{ title: 'Open evaluation framework', description: 'A public benchmark suite for sovereign AI deployments.', status: 'considering', target: '2027', display_order: 7, shipped_at: null, attributed: [] },
|
||||
];
|
||||
|
||||
const insertRoad = db.prepare(`
|
||||
|
|
@ -341,7 +344,7 @@ insertActivity.run(cabs[1].id,'voted', 'pulse', decisionPulseId, no
|
|||
insertActivity.run(cabs[0].id,'rsvped', 'event', db.prepare("SELECT id FROM events WHERE slug = ?").get(dinnerSlug).id, nowIso(-8 * 3600));
|
||||
|
||||
console.log(' pulse #' + decisionPulseId + ' open, 2 of 4 voted');
|
||||
console.log(' roadmap: 1 shipping / 1 beta / 2 exploring');
|
||||
console.log(' roadmap: 7 items (2 shipping / 1 in_beta / 2 exploring / 2 considering)');
|
||||
console.log(' contributions: 3 (most recent has 3 reactions)');
|
||||
console.log(' dispatches: 4 published (2/5/9/12 days ago)');
|
||||
console.log(' events: dinner + studio hours + working session, 2 past');
|
||||
|
|
|
|||
|
|
@ -227,27 +227,38 @@ const members = getAllCabMembers();
|
|||
|
||||
<!-- ── Roadmap — horizontal snap-scrolling carousel ─────────── -->
|
||||
{roadmapItems.length > 0 && (
|
||||
<div class="cascade">
|
||||
<div class="cascade roadmap-wrap">
|
||||
<RoadmapCarousel items={roadmapItems} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<!-- ── Council members — single background, no per-member boxes - -->
|
||||
<!-- ── Council — matches roadmap section framing ─────────────── -->
|
||||
{members.length > 0 && (
|
||||
<section class="cascade council-section" aria-label="The council">
|
||||
<header class="council-header">
|
||||
<h2 class="council-title">The council</h2>
|
||||
<a href="/members" class="council-all">See who our council is made up of →</a>
|
||||
</header>
|
||||
|
||||
<ul class="council-grid">
|
||||
{members.map(m => (
|
||||
<li class="council-cell">
|
||||
<Avatar id={m.id} name={m.name} size={56} />
|
||||
<div class="council-cell-text">
|
||||
<span class="council-cell-name">{m.name}</span>
|
||||
{m.title && <span class="council-cell-title">{m.title}</span>}
|
||||
<span class="council-cell-org">{m.organisation}</span>
|
||||
{members.slice(0, 4).map(m => (
|
||||
<li class="council-tile">
|
||||
<Avatar id={m.id} name={m.name} size={38} />
|
||||
<div class="council-tile-text">
|
||||
<span class="council-tile-name">{m.name}</span>
|
||||
{m.title && <span class="council-tile-title">{m.title}</span>}
|
||||
<span class="council-tile-org">{m.organisation}</span>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
{members.length > 4 && (
|
||||
<li class="council-tile council-tile--more">
|
||||
<a href="/members" class="council-tile-link">
|
||||
See all {members.length} council members →
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
<a href="/members" class="section-link">See who our council is made up of</a>
|
||||
</section>
|
||||
)}
|
||||
|
||||
|
|
@ -256,14 +267,22 @@ const members = getAllCabMembers();
|
|||
|
||||
<style>
|
||||
.page {
|
||||
padding: var(--space-12) var(--space-16) var(--space-16);
|
||||
padding: 40px 36px 80px;
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-12);
|
||||
}
|
||||
|
||||
/* Per-section spacing table (no shared gap — each transition is tuned).
|
||||
Read top-down: greeting → hero → also → editorial → roadmap → council. */
|
||||
.greeting { margin-top: 48px; } /* below nav */
|
||||
.hero-slot { margin-top: 56px; } /* greeting → hero */
|
||||
.also-coming-up { margin-top: 18px; } /* hero → also (tight; related) */
|
||||
.editorial-row { margin-top: 72px; } /* also → editorial */
|
||||
.roadmap-wrap { margin-top: 72px; } /* editorial → roadmap */
|
||||
.council-section{ margin-top: 72px; } /* roadmap → council */
|
||||
|
||||
/* ── Cascade entry (first paint only) ─────────────────────────── */
|
||||
.cascade {
|
||||
opacity: 0;
|
||||
|
|
@ -603,58 +622,99 @@ const members = getAllCabMembers();
|
|||
.pulse-option.chosen .pulse-option-letter { color: var(--pigment-terracotta); }
|
||||
.pulse-option-text { flex: 1; }
|
||||
|
||||
/* ── Council — one outer surface, no per-member boxes ─────────── */
|
||||
/* ── Council — section framing matches the roadmap carousel ──── */
|
||||
.council-section {
|
||||
background: var(--surface-card);
|
||||
border: 0.5px solid var(--surface-card-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-8) var(--space-8) var(--space-7);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-6);
|
||||
gap: 24px;
|
||||
}
|
||||
.council-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
}
|
||||
.council-title {
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 400;
|
||||
font-size: 22px;
|
||||
line-height: 1.2;
|
||||
color: var(--on-surface);
|
||||
margin: 0;
|
||||
}
|
||||
.council-all {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 11px;
|
||||
letter-spacing: var(--tracking-wider);
|
||||
text-transform: uppercase;
|
||||
color: var(--pigment-terracotta);
|
||||
text-decoration: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
.council-all:hover { opacity: 0.8; border-bottom: none; }
|
||||
|
||||
.council-grid {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: var(--space-6) var(--space-8);
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 24px;
|
||||
}
|
||||
.council-cell {
|
||||
.council-tile {
|
||||
display: flex;
|
||||
gap: var(--space-4);
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
.council-cell-text {
|
||||
.council-tile-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
.council-cell-name {
|
||||
.council-tile-name {
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 400;
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.2;
|
||||
font-size: 15px;
|
||||
line-height: 1.15;
|
||||
color: var(--on-surface);
|
||||
}
|
||||
.council-cell-title {
|
||||
.council-tile-title {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-body-sm);
|
||||
font-size: 11px;
|
||||
color: var(--on-surface-variant);
|
||||
line-height: 1.35;
|
||||
}
|
||||
.council-tile-org {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 10px;
|
||||
letter-spacing: var(--tracking-wide);
|
||||
text-transform: uppercase;
|
||||
color: var(--on-surface-variant);
|
||||
}
|
||||
.council-cell-org {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-label-sm);
|
||||
letter-spacing: var(--tracking-wide);
|
||||
color: var(--on-surface-muted);
|
||||
.council-tile--more {
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.council-tile-link {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 11px;
|
||||
letter-spacing: var(--tracking-wider);
|
||||
text-transform: uppercase;
|
||||
color: var(--pigment-terracotta);
|
||||
text-decoration: none;
|
||||
border-bottom: none;
|
||||
text-align: right;
|
||||
}
|
||||
.council-tile-link:hover { opacity: 0.8; border-bottom: none; }
|
||||
|
||||
/* ── Responsive ───────────────────────────────────────────────── */
|
||||
@media (max-width: 880px) {
|
||||
.editorial-row { grid-template-columns: 1fr; gap: var(--space-8); }
|
||||
.also-coming-up { flex-direction: column; align-items: flex-start; gap: var(--space-3); }
|
||||
.council-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
@media (max-width: 520px) {
|
||||
.council-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue