diff --git a/scripts/seed-demo.js b/scripts/seed-demo.js index a73d996..9676b76 100644 --- a/scripts/seed-demo.js +++ b/scripts/seed-demo.js @@ -61,6 +61,9 @@ const newCabs = [ { name: 'Anna Kjær', email: 'anna@virk3.dk', org: 'Virksomhed 3' }, { name: 'Søren Vedel', email: 'soren@virk4.dk', org: 'Virksomhed 4' }, { name: 'Henriette Rask',email: 'henriette@virk5.dk',org: 'Virksomhed 5' }, + { name: 'Mads Lindberg', email: 'mads@virk6.dk', org: 'Virksomhed 6' }, + { name: 'Camilla Storm', email: 'camilla@virk7.dk', org: 'Virksomhed 7' }, + { name: 'Frederik Lund', email: 'frederik@virk8.dk', org: 'Virksomhed 8' }, ]; const insertUser = db.prepare(` @@ -75,7 +78,15 @@ for (const c of newCabs) { // We backdate cab_joined_date first, then let allocateMemberNumber pick it up. // Lars: 0 weeks ago (most senior), then 2 / 4 / 6 weeks for the others. const cabRows = db.prepare("SELECT id, email, name FROM users WHERE role = 'cab' AND active = 1 ORDER BY id").all(); -const tenureWeeks = { 'lars@virk2.dk': 24, 'anna@virk3.dk': 6, 'soren@virk4.dk': 4, 'henriette@virk5.dk': 2 }; +const tenureWeeks = { + 'lars@virk2.dk': 24, + 'anna@virk3.dk': 14, + 'soren@virk4.dk': 12, + 'henriette@virk5.dk': 10, + 'mads@virk6.dk': 8, + 'camilla@virk7.dk': 6, + 'frederik@virk8.dk': 3, +}; const setCabMeta = db.prepare(` UPDATE users @@ -108,6 +119,21 @@ const cabMeta = { pull_quote: 'I\'ve never trusted a system I couldn\'t cross-examine.', focus_tags: ['Legal', 'Policy', 'EU AI Act'], }, + 'mads@virk6.dk': { + title: 'Chief Strategy Officer', + pull_quote: 'Healthcare runs on consent — and consent runs on trust.', + focus_tags: ['Healthcare', 'Consent', 'Governance'], + }, + 'camilla@virk7.dk': { + title: 'Head of Cyber Resilience', + pull_quote: 'Cyber resilience is not a feature — it is the substrate.', + focus_tags: ['Defence', 'Resilience'], + }, + 'frederik@virk8.dk': { + title: 'Director of Public Innovation', + pull_quote: 'Public innovation succeeds when it is measurably better, not just newer.', + focus_tags: ['Public sector', 'Measurement'], + }, }; for (const u of cabRows) { @@ -343,7 +369,7 @@ insertActivity.run(cabs[0].id,'voted', 'pulse', decisionPulseId, no insertActivity.run(cabs[1].id,'voted', 'pulse', decisionPulseId, nowIso(-30 * 60)); 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(` pulse #${decisionPulseId} open, 2 of ${cabs.length} voted`); 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)'); diff --git a/src/pages/pulse.astro b/src/pages/pulse.astro index 25c43c3..557245d 100644 --- a/src/pages/pulse.astro +++ b/src/pages/pulse.astro @@ -229,7 +229,7 @@ const members = getAllCabMembers(); )} - + {members.length > 0 && (
@@ -237,25 +237,20 @@ const members = getAllCabMembers(); See who our council is made up of →
- +
+ +
)} @@ -648,19 +643,48 @@ const members = getAllCabMembers(); } .council-all:hover { opacity: 0.8; border-bottom: none; } - .council-grid { + /* Marquee — list is rendered twice so translateX(-50%) wraps seamlessly. + The duration is set via --marquee-duration on the inline style so the + loop speed scales with member count. Paused on hover and for users + with reduced-motion preferences. */ + .council-marquee { + position: relative; + overflow: hidden; + -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%); + mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%); + } + .council-marquee-track { list-style: none; padding: 0; margin: 0; - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 24px; + display: flex; + gap: 48px; + width: max-content; + animation: council-scroll var(--marquee-duration, 40s) linear infinite; + will-change: transform; } + .council-marquee:hover .council-marquee-track { + animation-play-state: paused; + } + @keyframes council-scroll { + from { transform: translateX(0); } + to { transform: translateX(-50%); } + } + @media (prefers-reduced-motion: reduce) { + .council-marquee-track { animation: none; } + .council-marquee { + overflow-x: auto; + scrollbar-width: none; + } + .council-marquee::-webkit-scrollbar { display: none; } + } + .council-tile { display: flex; align-items: center; gap: 12px; - min-width: 0; + flex: 0 0 auto; + min-width: 220px; } .council-tile-text { display: flex; @@ -674,12 +698,14 @@ const members = getAllCabMembers(); font-size: 15px; line-height: 1.15; color: var(--on-surface); + white-space: nowrap; } .council-tile-title { font-family: var(--font-sans); font-size: 11px; color: var(--on-surface-variant); line-height: 1.35; + white-space: nowrap; } .council-tile-org { font-family: var(--font-sans); @@ -687,30 +713,12 @@ const members = getAllCabMembers(); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--on-surface-variant); + white-space: nowrap; } - .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; } }