refactor: rebuild home as welcome and pitch page
This commit is contained in:
parent
4bed3a5fe0
commit
d9c75a1921
1 changed files with 406 additions and 139 deletions
|
|
@ -1,190 +1,457 @@
|
|||
---
|
||||
import AppLayout from '../layouts/AppLayout.astro';
|
||||
import ProjectLockup from '../components/ProjectLockup.astro';
|
||||
import { hasJoinRequest } from '../lib/db';
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
const user = Astro.locals.user;
|
||||
const firstName = user.name.split(' ')[0];
|
||||
const alreadyJoined = hasJoinRequest(user.id);
|
||||
const innofoundarLogoExists = existsSync(join(process.cwd(), 'public/innofounder-logo.svg'));
|
||||
---
|
||||
<AppLayout title="Welcome" user={user}>
|
||||
<AppLayout title="Home" user={user}>
|
||||
<div class="page">
|
||||
|
||||
<!-- Greeting -->
|
||||
<section class="greeting-zone">
|
||||
<p class="label-md eyebrow">Project Bifrost</p>
|
||||
<h1 class="display-lg greeting">
|
||||
Welcome, <em class="name">{user.name.split(' ')[0]}.</em>
|
||||
</h1>
|
||||
<p class="lead framing">
|
||||
This is the private working space for the Bifrost pilot — where you follow what we are building,
|
||||
shape it with your experience, and meet the people building it with you.
|
||||
<!-- ── Hero ──────────────────────────────────────────────────── -->
|
||||
<section class="hero">
|
||||
<ProjectLockup size="hero" alignment="left" />
|
||||
<p class="hero-greeting">Welcome, <em>{firstName}.</em></p>
|
||||
</section>
|
||||
|
||||
<!-- ── Opening statement ─────────────────────────────────────── -->
|
||||
<section class="opening">
|
||||
<p class="opening-statement">
|
||||
Secure and sovereign AI for regulated environments.
|
||||
Project Bifrost is where we build it — together with the organisations
|
||||
who will depend on it.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Navigation cards -->
|
||||
<nav class="cards" aria-label="Quick navigation">
|
||||
<a href="/updates" class="card">
|
||||
<span class="label-sm card-label">Latest update</span>
|
||||
<h2 class="card-title">
|
||||
See what <em class="card-em">changed.</em>
|
||||
</h2>
|
||||
<p class="body-sm card-body">
|
||||
Progress notes from Fenja — what shipped, what shifted, what is next.
|
||||
<!-- ── What Fenja is ─────────────────────────────────────────── -->
|
||||
<section class="section fenja-section">
|
||||
<div class="section-text">
|
||||
<h2 class="section-heading label-sm">What Fenja is</h2>
|
||||
<div class="prose">
|
||||
<p class="body-lg">
|
||||
Fenja is a platform for running advanced AI inside the customer's own infrastructure.
|
||||
We are building the premier solution for public authorities and organisations in
|
||||
heavily regulated industries — where trust, auditability, and data residency are not
|
||||
preferences but legal requirements.
|
||||
</p>
|
||||
<span class="card-arrow" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<p class="body-lg">
|
||||
Standard AI solutions hosted on foreign-owned public clouds are simply not a viable
|
||||
or compliant option for organisations in the public sector, defence, pharmaceuticals,
|
||||
or finance. Fenja enables advanced, customer-hosted AI within the client's own secure
|
||||
infrastructure. Data remains under absolute, localised control, with the traceability
|
||||
and documentation the market demands.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="/calendar" class="card">
|
||||
<span class="label-sm card-label">Next meeting</span>
|
||||
<h2 class="card-title">
|
||||
The CAB <em class="card-em">calendar.</em>
|
||||
</h2>
|
||||
<p class="body-sm card-body">
|
||||
Upcoming sessions, agendas, and notes from past meetings.
|
||||
</p>
|
||||
<span class="card-arrow" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<figure class="stat-figure" aria-label="Key statistic">
|
||||
<p class="stat-figure__number">97%</p>
|
||||
<figcaption class="stat-figure__label">
|
||||
of AI foundational model usage falls outside EU jurisdiction
|
||||
</figcaption>
|
||||
<p class="stat-source label-sm">— Stanford AI Index, 2024</p>
|
||||
</figure>
|
||||
</section>
|
||||
|
||||
<a href="/contribute" class="card">
|
||||
<span class="label-sm card-label">Contribute</span>
|
||||
<h2 class="card-title">
|
||||
Share an <em class="card-em">idea.</em>
|
||||
</h2>
|
||||
<p class="body-sm card-body">
|
||||
Post an idea, a question, or something that inspired you. Everyone in the hub sees it.
|
||||
<!-- ── What Project Bifrost is ───────────────────────────────── -->
|
||||
<section class="section bifrost-section">
|
||||
<h2 class="section-heading label-sm">What Project Bifrost is</h2>
|
||||
<div class="prose">
|
||||
<p class="body-lg">
|
||||
Project Bifrost is the first pilot — a working collaboration between Fenja and five
|
||||
organisations who are shaping the platform they will ultimately rely on. Two are running
|
||||
paid-but-subsidised pilots; the remaining three are on the Customer Advisory Board,
|
||||
following the work closely and shaping direction through quarterly conversations.
|
||||
</p>
|
||||
<span class="card-arrow" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<p class="body-lg">
|
||||
This is not a focus group. Participants are involved in real decisions — about what
|
||||
the minimum viable product looks like, how the traceability layer works, what the
|
||||
knowledge base needs to understand. Their input is built in, not bolted on.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<a href="/roadmap" class="card">
|
||||
<span class="label-sm card-label">Roadmap</span>
|
||||
<h2 class="card-title">
|
||||
What is <em class="card-em">next.</em>
|
||||
</h2>
|
||||
<p class="body-sm card-body">
|
||||
In progress, coming soon, and further out — the full picture of where we are going.
|
||||
<!-- ── Backed by Innofounder ──────────────────────────────────── -->
|
||||
<section class="section innofounder-section">
|
||||
<div class="innofounder-header">
|
||||
{innofoundarLogoExists ? (
|
||||
<img src="/innofounder-logo.svg" alt="Innofounder — Innovation Fund Denmark" class="innofounder-logo" />
|
||||
) : (
|
||||
<div class="innofounder-placeholder" aria-label="Innofounder logo — add file">
|
||||
<span class="label-sm">Innofounder logo — add <code>public/innofounder-logo.svg</code></span>
|
||||
</div>
|
||||
)}
|
||||
<h2 class="section-heading label-sm">Backed by Innofounder</h2>
|
||||
</div>
|
||||
<div class="prose">
|
||||
<p class="body-lg">
|
||||
Fenja is backed by Innofounder — Innovation Fund Denmark's programme for
|
||||
early-stage deep-tech ventures. This matters for you directly: because this
|
||||
work is publicly funded, we are using that funding to subsidise pilot
|
||||
participants' own projects.
|
||||
</p>
|
||||
<span class="card-arrow" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<p class="body-lg">
|
||||
Participants in Project Bifrost are not just getting early access to the platform.
|
||||
They are helping to define what the Danish standard for sovereign AI looks like —
|
||||
and in return, they receive a substantially discounted sovereign AI deployment for
|
||||
their own organisation once we reach the agreed MVP. The public funding creates the
|
||||
conditions for a genuine win-win: you shape the platform, and the platform works for you.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<a href="/preview" class="card">
|
||||
<span class="label-sm card-label">Product preview</span>
|
||||
<h2 class="card-title">
|
||||
See the <em class="card-em">platform.</em>
|
||||
</h2>
|
||||
<p class="body-sm card-body">
|
||||
Screenshots and walkthroughs of the sovereign AI platform you are piloting.
|
||||
</p>
|
||||
<span class="card-arrow" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
<!-- ── What we ask ───────────────────────────────────────────── -->
|
||||
<section class="section ask-section">
|
||||
<h2 class="section-heading label-sm">What we ask</h2>
|
||||
<div class="ask-grid">
|
||||
<div class="ask-card">
|
||||
<h3 class="ask-card-title body-lg">Pilot participants</h3>
|
||||
<ul class="ask-list body-md">
|
||||
<li>A few hours a month over three to four months</li>
|
||||
<li>Running the software in your own environment</li>
|
||||
<li>Direct feedback on what works and what does not</li>
|
||||
<li>Input into the minimum viable shape of the product</li>
|
||||
<li>A fraction of the real value of the deployment, once we reach agreed MVP</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="ask-card">
|
||||
<h3 class="ask-card-title body-lg">Advisory Board members</h3>
|
||||
<ul class="ask-list body-md">
|
||||
<li>Quarterly conversations to shape direction</li>
|
||||
<li>Access to all updates, roadmap, and meetings in this hub</li>
|
||||
<li>No software deployment required</li>
|
||||
<li>Advisory Board participation is free</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<a href="/participants" class="card">
|
||||
<span class="label-sm card-label">Participants</span>
|
||||
<h2 class="card-title">
|
||||
The <em class="card-em">people.</em>
|
||||
</h2>
|
||||
<p class="body-sm card-body">
|
||||
Everyone in the pilot — who they are, where they are from, and what they bring.
|
||||
<!-- ── Join CTA ───────────────────────────────────────────────── -->
|
||||
<section class="join-section" id="join-section">
|
||||
{alreadyJoined ? (
|
||||
<div class="join-confirmed">
|
||||
<h2 class="join-confirmed-title">Welcome to Project Bifrost.</h2>
|
||||
<p class="body-lg join-confirmed-body">
|
||||
We will be in touch shortly to arrange the next step.
|
||||
</p>
|
||||
<span class="card-arrow" aria-hidden="true">↗</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
) : (
|
||||
<div class="join-cta" id="join-cta">
|
||||
<button class="join-btn" id="join-btn" type="button">
|
||||
I want to join Project Bifrost.
|
||||
</button>
|
||||
<p class="join-hint body-sm">
|
||||
We will follow up personally to discuss the right level of involvement for your organisation.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</AppLayout>
|
||||
|
||||
<script>
|
||||
const btn = document.getElementById('join-btn');
|
||||
if (btn) {
|
||||
btn.addEventListener('click', async () => {
|
||||
btn.setAttribute('disabled', 'true');
|
||||
btn.textContent = 'Registering...';
|
||||
try {
|
||||
const res = await fetch('/api/join', { method: 'POST' });
|
||||
if (res.ok) {
|
||||
const section = document.getElementById('join-cta');
|
||||
if (section) {
|
||||
section.innerHTML = `
|
||||
<div class="join-confirmed">
|
||||
<h2 class="join-confirmed-title">Welcome to Project Bifrost.</h2>
|
||||
<p class="join-confirmed-body">
|
||||
We will be in touch shortly to arrange the next step.
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
} else {
|
||||
btn.removeAttribute('disabled');
|
||||
btn.textContent = 'I want to join Project Bifrost.';
|
||||
}
|
||||
} catch {
|
||||
btn.removeAttribute('disabled');
|
||||
btn.textContent = 'I want to join Project Bifrost.';
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.page {
|
||||
padding: var(--space-12) var(--space-20) var(--space-16);
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--space-20) var(--space-16);
|
||||
}
|
||||
|
||||
/* ── Greeting ─────────────────────────────────────────────────── */
|
||||
.greeting-zone {
|
||||
max-width: 44rem;
|
||||
margin-bottom: var(--space-12);
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
color: var(--on-surface-muted);
|
||||
letter-spacing: var(--tracking-wider);
|
||||
text-transform: uppercase;
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.greeting {
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.framing {
|
||||
max-width: var(--reading-max);
|
||||
color: var(--on-surface-variant);
|
||||
}
|
||||
|
||||
/* ── Navigation cards ─────────────────────────────────────────── */
|
||||
.cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
/* ── Hero ────────────────────────────────────────────────────────── */
|
||||
.hero {
|
||||
padding-top: var(--space-16);
|
||||
padding-bottom: var(--space-10);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
padding: var(--space-6);
|
||||
background: var(--surface-container-lowest);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--on-surface);
|
||||
border-bottom: none;
|
||||
text-decoration: none;
|
||||
transition: background var(--duration-med) var(--ease-standard);
|
||||
}
|
||||
.card:hover {
|
||||
background: var(--surface-container-low);
|
||||
border-bottom: none;
|
||||
color: var(--on-surface);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
|
||||
.card-label {
|
||||
color: var(--on-surface-muted);
|
||||
letter-spacing: var(--tracking-wide);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: var(--text-headline-sm);
|
||||
.hero-greeting {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--text-headline-md);
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
color: var(--on-surface-variant);
|
||||
margin: 0;
|
||||
letter-spacing: var(--tracking-snug);
|
||||
}
|
||||
|
||||
/* ── Opening statement ───────────────────────────────────────────── */
|
||||
.opening {
|
||||
padding-bottom: var(--space-12);
|
||||
border-bottom: var(--ghost-border);
|
||||
max-width: 52rem;
|
||||
}
|
||||
|
||||
.opening-statement {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--text-headline-md);
|
||||
font-weight: 400;
|
||||
letter-spacing: var(--tracking-snug);
|
||||
line-height: var(--leading-snug);
|
||||
margin: 0;
|
||||
color: var(--on-surface);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card-em {
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
/* ── Sections ────────────────────────────────────────────────────── */
|
||||
.section {
|
||||
padding: var(--space-12) 0;
|
||||
border-bottom: var(--ghost-border);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
.section-heading {
|
||||
letter-spacing: var(--tracking-wider);
|
||||
text-transform: uppercase;
|
||||
color: var(--on-surface-muted);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
/* ── Fenja section — two-column layout ──────────────────────────── */
|
||||
.fenja-section {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 18rem;
|
||||
gap: var(--space-12);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.section-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.section-text .section-heading {
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
/* ── Prose ───────────────────────────────────────────────────────── */
|
||||
.prose {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
|
||||
.prose .body-lg {
|
||||
margin: 0;
|
||||
color: var(--on-surface-variant);
|
||||
flex: 1;
|
||||
line-height: var(--leading-relaxed);
|
||||
}
|
||||
|
||||
.card-arrow {
|
||||
/* ── Stat figure ─────────────────────────────────────────────────── */
|
||||
.stat-figure {
|
||||
margin: var(--space-8) 0 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.stat-figure__number {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--text-body-sm);
|
||||
font-size: var(--text-display-xl);
|
||||
font-weight: 400;
|
||||
letter-spacing: var(--tracking-tight);
|
||||
line-height: 1;
|
||||
color: var(--on-surface-muted);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.stat-figure__label {
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-body-md);
|
||||
color: var(--on-surface-variant);
|
||||
max-width: 16rem;
|
||||
line-height: var(--leading-relaxed);
|
||||
}
|
||||
|
||||
.stat-source {
|
||||
color: var(--on-surface-muted);
|
||||
letter-spacing: var(--tracking-wide);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── Innofounder section ─────────────────────────────────────────── */
|
||||
.innofounder-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.innofounder-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-5);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.innofounder-logo {
|
||||
height: 32px;
|
||||
width: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.innofounder-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 32px;
|
||||
padding: 0 var(--space-4);
|
||||
background: var(--surface-container);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.innofounder-placeholder .label-sm {
|
||||
color: var(--on-surface-muted);
|
||||
letter-spacing: var(--tracking-wide);
|
||||
}
|
||||
|
||||
.innofounder-placeholder code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.9em;
|
||||
color: var(--on-surface-variant);
|
||||
}
|
||||
|
||||
.innofounder-section .section-heading {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.innofounder-section .prose {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* ── What we ask — two cards ─────────────────────────────────────── */
|
||||
.ask-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--space-6);
|
||||
max-width: 52rem;
|
||||
}
|
||||
|
||||
.ask-card {
|
||||
background: var(--surface-container-lowest);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.ask-card-title {
|
||||
font-family: var(--font-serif);
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
letter-spacing: var(--tracking-snug);
|
||||
color: var(--on-surface);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ask-list {
|
||||
padding-left: var(--space-5);
|
||||
margin: 0;
|
||||
color: var(--on-surface-variant);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
line-height: var(--leading-relaxed);
|
||||
}
|
||||
|
||||
/* ── Join CTA ────────────────────────────────────────────────────── */
|
||||
.join-section {
|
||||
padding: var(--space-16) 0 var(--space-12);
|
||||
max-width: 44rem;
|
||||
}
|
||||
|
||||
.join-cta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.join-btn {
|
||||
display: inline-block;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--text-headline-lg);
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
letter-spacing: var(--tracking-tight);
|
||||
line-height: var(--leading-snug);
|
||||
color: var(--secondary);
|
||||
align-self: flex-end;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
transition: color var(--duration-fast) var(--ease-standard);
|
||||
}
|
||||
.card:hover .card-arrow {
|
||||
.join-btn:hover {
|
||||
color: var(--secondary-dim);
|
||||
}
|
||||
.join-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.join-hint {
|
||||
color: var(--on-surface-muted);
|
||||
margin: 0;
|
||||
max-width: 36rem;
|
||||
line-height: var(--leading-relaxed);
|
||||
}
|
||||
|
||||
/* Confirmed state (injected by JS or server-rendered) */
|
||||
.join-confirmed {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.join-confirmed-title {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--text-headline-lg);
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
letter-spacing: var(--tracking-tight);
|
||||
color: var(--on-surface);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.join-confirmed-body {
|
||||
color: var(--on-surface-variant);
|
||||
margin: 0;
|
||||
line-height: var(--leading-relaxed);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue