Why: pivot the experience from a personal invitation for Project Bifrost
participants to a customer-facing presentation that can be shown to
prospects like Novo Nordisk while still mentioning Bifrost in context.
Major changes:
- Entrance: re-worded title/body away from "invitation" into "introduction"; kept Fenja AI / Project Bifrost definition blocks.
- Timeline: page-sub reworked to also speak to highly-regulated private orgs (data, IP, regulated workflows, US-vendor dependency) alongside public sector.
- "Backed by Innovationsfonden" pairs with new "Part of BioInnovation Institute AI Lab" line on entrance and Scene 1 hero.
- Removed: stack-scene (4 capabilities) and words-scene ("This is why we've invited you") — archived at protected/_archive/stack-scene.html for restore.
- Removed: bifrost-join CTA + Innovationsfonden footer section.
- Inlined the standalone /deepdive architecture explainer into #overview-scroll after #bifrost-meaning; platform.js detects scroller and skips its own Lenis setup when integrated.
- New: Wiki deep-dive section (#wiki-deepdive) — scattered knowledge cluster → Fenja AI Compiler → layered page stack with citations, plus pinned scrubbed beat-by-beat reveal.
- New: Implementation roadmap section (#platform-roadmap) — four stage cards + GOVERN & SCALE band + footer, with click-to-expand card-morph (FLIP-based; same DOM element grows into the featured panel).
- Dot-nav: 4 → 8 entries — Welcome / Timeline / Fenja introduction / Project Bifrost / Architecture / Wiki / Deployment / Roadmap.
- Deployment options: scroll-tied fade-in for the whole section + sticky-damping at centre for a subtle dwell stop.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3583 lines
137 KiB
HTML
3583 lines
137 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||
<title>A Catalog of Sovereignty — 2022–2026</title>
|
||
<link rel="stylesheet" href="/fenja/colors_and_type.css" />
|
||
<link rel="stylesheet" href="/platform.css" />
|
||
<script src="/vendor/d3-array.min.js"></script>
|
||
<script src="/vendor/d3-geo.min.js"></script>
|
||
<script src="/vendor/topojson-client.min.js"></script>
|
||
<style>
|
||
@view-transition { navigation: auto; }
|
||
|
||
:root{
|
||
--paper: #faf6ee;
|
||
--paper-high: #fffcf7;
|
||
--paper-mid: #f4efe2;
|
||
--paper-low: #ece5d2;
|
||
--ink: #383831;
|
||
--ink-soft: #5f5e5e;
|
||
--ink-dim: #8a887f;
|
||
|
||
--copper: #6d8c7c; /* copper green */
|
||
--ochre: #c29d59;
|
||
--terracotta: #b96b58;
|
||
--crimson: #8a3a2f; /* deep crimson */
|
||
|
||
--ease: cubic-bezier(0.2, 0, 0, 1);
|
||
--dur: 240ms;
|
||
}
|
||
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
|
||
html, body {
|
||
margin: 0; padding: 0;
|
||
height: 100%;
|
||
background: var(--paper);
|
||
color: var(--ink);
|
||
font-family: "Manrope", system-ui, sans-serif;
|
||
overflow: hidden;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
body {
|
||
/* Subtle tonal shift across the entire surface — not a gradient on chrome,
|
||
just the paper catching light. */
|
||
background:
|
||
radial-gradient(1200px 800px at 18% 45%, #fffcf7 0%, var(--paper) 55%, #f4efe2 100%);
|
||
view-transition-name: paper;
|
||
}
|
||
|
||
/* ───── Page scaffolding ───── */
|
||
.page {
|
||
position: fixed; inset: 0;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 380ms var(--ease);
|
||
will-change: opacity;
|
||
}
|
||
.page.is-active {
|
||
opacity: 1;
|
||
pointer-events: auto;
|
||
}
|
||
|
||
/* ───────── Site wordmark — top-left masthead, clickable "home" link ───────── */
|
||
.site-mark,
|
||
.site-mark:link,
|
||
.site-mark:visited,
|
||
.site-mark:hover,
|
||
.site-mark:active,
|
||
.site-mark:focus,
|
||
.site-mark:focus-visible {
|
||
text-decoration: none;
|
||
border-bottom: 0;
|
||
}
|
||
.site-mark {
|
||
position: fixed;
|
||
top: 28px;
|
||
left: 36px;
|
||
width: 118px;
|
||
height: auto;
|
||
z-index: 50;
|
||
opacity: 0.85;
|
||
display: block;
|
||
cursor: pointer;
|
||
transition: opacity var(--dur, 200ms) var(--ease, ease);
|
||
}
|
||
.site-mark img {
|
||
display: block;
|
||
width: 100%;
|
||
height: auto;
|
||
pointer-events: none; /* keeps clicks on the anchor, not the image */
|
||
}
|
||
.site-mark:hover,
|
||
.site-mark:focus-visible {
|
||
opacity: 1;
|
||
}
|
||
.site-mark:focus-visible {
|
||
outline: 2px solid var(--walnut, #785f53);
|
||
outline-offset: 6px;
|
||
}
|
||
@media (max-width: 720px) {
|
||
.site-mark { width: 90px; top: 20px; left: 22px; }
|
||
}
|
||
|
||
/* Page overline title — large, sits in the upper third of the viewport
|
||
so the long page-sub body below it has room without clipping. */
|
||
.page-title {
|
||
position: absolute;
|
||
left: 80px; top: 22vh;
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-weight: 400;
|
||
font-size: 54px;
|
||
letter-spacing: -0.022em;
|
||
color: var(--ink);
|
||
line-height: 1.08;
|
||
z-index: 15;
|
||
max-width: 820px;
|
||
text-wrap: pretty;
|
||
opacity: 1;
|
||
transition: opacity 520ms var(--ease), transform 520ms var(--ease);
|
||
}
|
||
.page-title em {
|
||
font-style: italic; font-weight: 700;
|
||
}
|
||
.page-title + .page-sub {
|
||
position: absolute;
|
||
left: 80px; top: calc(22vh + 160px);
|
||
max-width: 720px;
|
||
/* Upright serif editorial body, ink colour, 23px (about 15%
|
||
larger than the welcome-page body) so the long intro reads
|
||
at ease. Only the <em> spans carry italics for emphasis. */
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-weight: 400;
|
||
font-size: 23px;
|
||
line-height: 1.52;
|
||
color: var(--ink);
|
||
z-index: 15;
|
||
opacity: 1;
|
||
transition: opacity 520ms var(--ease), transform 520ms var(--ease);
|
||
}
|
||
.page-sub em { font-style: italic; font-weight: 700; color: var(--ink); }
|
||
/* Final sentence of the front-matter is pulled up in crimson so the
|
||
rhetorical question reads as the emphatic beat of the block. Applied
|
||
to the whole sentence, not just the <em> on "Washington?", so the
|
||
colour change cues the reader's eye before they reach the italic. */
|
||
.page-sub-accent,
|
||
.page-sub-accent em { color: var(--crimson); }
|
||
/* Once the timeline has been advanced, the front matter steps aside */
|
||
.page-timeline.is-scrolled .page-title,
|
||
.page-timeline.is-scrolled .page-sub {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transform: translateY(-12px);
|
||
}
|
||
|
||
/* ───────── First-load scroll hint ─────────
|
||
Right-edge prompt telling the reader to begin scrolling the
|
||
horizontal timeline. Vertically centered, horizontal layout
|
||
(label then arrow), editorial ink colour. Arrow pulses
|
||
rightward to hint at the scroll direction. Fades out as soon
|
||
as the reader advances — same `.is-scrolled` class the
|
||
front-matter uses. */
|
||
.timeline-scroll-hint {
|
||
position: absolute;
|
||
right: clamp(32px, 3.8vw, 72px);
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
z-index: 20;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 22px;
|
||
color: var(--ink);
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
animation: ts-fade-in 700ms 500ms var(--ease) forwards;
|
||
transition: opacity 360ms var(--ease), transform 360ms var(--ease);
|
||
}
|
||
.ts-label {
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-style: italic;
|
||
font-size: clamp(22px, 2.1vw, 30px);
|
||
letter-spacing: -0.005em;
|
||
line-height: 1;
|
||
white-space: nowrap;
|
||
}
|
||
.ts-arrow {
|
||
width: clamp(84px, 8vw, 120px);
|
||
height: auto;
|
||
color: var(--ink);
|
||
animation: ts-arrow-nudge 1800ms cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||
}
|
||
@keyframes ts-fade-in {
|
||
from { opacity: 0; transform: translate(14px, -50%); }
|
||
to { opacity: 1; transform: translate(0, -50%); }
|
||
}
|
||
@keyframes ts-arrow-nudge {
|
||
0%, 100% { transform: translateX(0); opacity: 0.9; }
|
||
50% { transform: translateX(14px); opacity: 1; }
|
||
}
|
||
/* Fade out on the very first wheel tick (`.hint-dismissed` is set
|
||
in timeline.js's onWheel handler, independent of the 40px
|
||
`.is-scrolled` threshold so the hint leaves instantly).
|
||
`animation: none` is required to override the entry ts-fade-in
|
||
animation (which has forwards fill-mode and outranks this rule
|
||
otherwise); ts-arrow-nudge is also stopped so the pulse doesn't
|
||
keep ticking behind the fade. */
|
||
.page-timeline.hint-dismissed .timeline-scroll-hint {
|
||
animation: none;
|
||
opacity: 0;
|
||
transform: translate(14px, -50%);
|
||
}
|
||
.page-timeline.hint-dismissed .ts-arrow {
|
||
animation: none;
|
||
}
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.timeline-scroll-hint { animation: none; opacity: 1; }
|
||
.ts-arrow { animation: none; }
|
||
}
|
||
|
||
/* ───────── Dot-nav ─────────
|
||
5px dots, filled when active, outlined ring otherwise. Labels hidden
|
||
by default and appear as a floating tooltip above the dot on hover.
|
||
|
||
The `.dot-nav-tray` (bottom paper-fade behind the nav) is still
|
||
declared but suppressed on #page-overview so the S6 footer reads
|
||
as a hard terminus — see the #page-overview.is-active rule further
|
||
down. */
|
||
.dot-nav-tray {
|
||
position: fixed;
|
||
left: 0; right: 0; bottom: 0;
|
||
height: 110px;
|
||
z-index: 35;
|
||
pointer-events: none;
|
||
background: linear-gradient(to bottom,
|
||
rgba(250,246,238,0) 0%,
|
||
rgba(250,246,238,0.88) 45%,
|
||
rgba(250,246,238,0.98) 100%);
|
||
transition: opacity var(--dur) var(--ease);
|
||
}
|
||
/* Fade the tray away on the Overview page so the S6 footer meets the
|
||
bottom of the viewport cleanly without a paper wash over the logos. */
|
||
body:has(#page-overview.is-active) .dot-nav-tray { opacity: 0; }
|
||
|
||
.dot-nav {
|
||
position: fixed;
|
||
bottom: 36px; left: 50%;
|
||
transform: translateX(-50%);
|
||
display: flex; gap: 22px;
|
||
z-index: 40;
|
||
}
|
||
.dot-btn {
|
||
all: unset;
|
||
position: relative;
|
||
padding: 10px; /* invisible hit target — the dot itself is 5px */
|
||
cursor: pointer;
|
||
display: flex; align-items: center; justify-content: center;
|
||
}
|
||
.dot-btn .dot {
|
||
width: 10px; height: 10px;
|
||
border-radius: 50%;
|
||
background: transparent;
|
||
box-shadow: inset 0 0 0 1.5px var(--ink-dim); /* outlined ring, default */
|
||
transition: background var(--dur) var(--ease),
|
||
box-shadow var(--dur) var(--ease);
|
||
}
|
||
.dot-btn:hover .dot {
|
||
box-shadow: inset 0 0 0 1.5px var(--ink);
|
||
}
|
||
.dot-btn.is-active .dot {
|
||
background: var(--ink); /* filled ink, active */
|
||
box-shadow: inset 0 0 0 1.5px var(--ink);
|
||
}
|
||
|
||
/* Label tooltip — rises above the dot on hover or keyboard focus. */
|
||
.dot-btn .label {
|
||
position: absolute;
|
||
bottom: calc(100% - 6px); /* sit just above the hit area */
|
||
left: 50%;
|
||
transform: translate(-50%, 4px);
|
||
background: #fffcf7;
|
||
color: var(--ink);
|
||
font-size: 10.5px;
|
||
letter-spacing: 0.22em;
|
||
text-transform: uppercase;
|
||
font-weight: 500;
|
||
font-family: "Manrope", system-ui, sans-serif;
|
||
padding: 7px 11px;
|
||
white-space: nowrap;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
box-shadow:
|
||
0 0 0 0.5px rgba(56,56,49,0.08),
|
||
0 10px 18px -10px rgba(56,56,49,0.2),
|
||
0 2px 6px -3px rgba(56,56,49,0.08);
|
||
transition: opacity var(--dur) var(--ease),
|
||
transform var(--dur) var(--ease);
|
||
}
|
||
.dot-btn:hover .label,
|
||
.dot-btn:focus-visible .label {
|
||
opacity: 1;
|
||
transform: translate(-50%, 0);
|
||
}
|
||
|
||
/* ───────── Globe ghost ───────── */
|
||
.globe-wrap {
|
||
position: absolute;
|
||
/* 15% larger than the original 58vw ≈ 66.7vw.
|
||
Shifted ~20% of its width toward the page center: from left:-8%
|
||
to roughly left:+5%. */
|
||
left: 5%; top: 0;
|
||
width: 66.7vw;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
opacity: 0.5;
|
||
transition: opacity 280ms var(--ease);
|
||
/* Mask top and fade the bottom third so the timeline rests on clean paper */
|
||
-webkit-mask-image: linear-gradient(to bottom,
|
||
transparent 0%, #000 22%, #000 58%, transparent 72%);
|
||
mask-image: linear-gradient(to bottom,
|
||
transparent 0%, #000 22%, #000 58%, transparent 72%);
|
||
}
|
||
.globe-wrap svg {
|
||
width: 100%; height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
/* ───────── Timeline ───────── */
|
||
.timeline-viewport {
|
||
position: absolute; inset: 0;
|
||
z-index: 5;
|
||
}
|
||
|
||
.timeline-track {
|
||
position: absolute;
|
||
top: 0; left: 0; height: 100%;
|
||
will-change: transform;
|
||
transform: translate3d(0,0,0);
|
||
display: flex; align-items: center;
|
||
padding: 0 120px;
|
||
--spine-y: 54%;
|
||
}
|
||
|
||
.spine {
|
||
position: absolute;
|
||
top: var(--spine-y); left: 0;
|
||
height: 1px;
|
||
width: 100%;
|
||
background: linear-gradient(to right,
|
||
transparent 0,
|
||
rgba(56,56,49,0.22) 60px,
|
||
rgba(56,56,49,0.22) calc(100% - 60px),
|
||
transparent);
|
||
z-index: 2;
|
||
}
|
||
|
||
.year-tick {
|
||
position: absolute;
|
||
top: var(--spine-y);
|
||
transform: translate(-50%, -50%);
|
||
display: flex; flex-direction: column; align-items: center;
|
||
gap: 10px;
|
||
z-index: 3;
|
||
color: var(--ink-dim);
|
||
}
|
||
.year-tick::before {
|
||
content: "";
|
||
display: block;
|
||
width: 1px; height: 28px;
|
||
background: rgba(56,56,49,0.28);
|
||
}
|
||
.year-tick .y {
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-style: italic;
|
||
font-size: 22px;
|
||
color: var(--ink-soft);
|
||
letter-spacing: 0;
|
||
font-weight: 400;
|
||
}
|
||
|
||
/* Card */
|
||
.evt {
|
||
position: absolute;
|
||
width: 640px;
|
||
padding: 32px 40px 36px;
|
||
/* Two-column editorial layout: headline on the left (15% wider),
|
||
body paragraph + source stacked on the right. Keeps cards shorter
|
||
so they don't clip below the timeline spine. */
|
||
display: grid;
|
||
grid-template-columns: 1.15fr 0.85fr;
|
||
grid-template-areas:
|
||
"head body"
|
||
"head source";
|
||
column-gap: 32px;
|
||
row-gap: 14px;
|
||
background: var(--paper-high);
|
||
/* Tonal surface shifts instead of 1px borders */
|
||
box-shadow:
|
||
0 0 0 0.5px rgba(56,56,49,0.05),
|
||
0 14px 28px -18px rgba(56,56,49,0.18),
|
||
0 2px 6px -3px rgba(56,56,49,0.08);
|
||
color: var(--ink);
|
||
opacity: 0;
|
||
/* Pop-in: small scale + downward lift for a more tactile entrance */
|
||
transform: translateY(28px) scale(0.96);
|
||
transform-origin: center top;
|
||
}
|
||
.evt.above {
|
||
transform: translateY(-28px) scale(0.96);
|
||
transform-origin: center bottom;
|
||
}
|
||
/* Only animate after first paint — prevents the initial card from
|
||
getting stuck at opacity 0 while the transition starts pre-layout. */
|
||
.evt.can-animate {
|
||
transition:
|
||
opacity 640ms var(--ease),
|
||
transform 640ms cubic-bezier(0.16, 1, 0.3, 1),
|
||
box-shadow 320ms var(--ease);
|
||
}
|
||
.evt.is-near {
|
||
opacity: 1;
|
||
transform: translateY(0) scale(1);
|
||
}
|
||
.evt.above { bottom: calc(100% - var(--spine-y) + 48px); }
|
||
.evt.below { top: calc(var(--spine-y) + 48px); }
|
||
|
||
/* Connector from card to spine */
|
||
.evt::after {
|
||
content: "";
|
||
position: absolute;
|
||
left: 52px;
|
||
width: 1px;
|
||
background: rgba(56,56,49,0.28);
|
||
}
|
||
.evt.above::after { top: 100%; height: 40px; }
|
||
.evt.below::after { bottom: 100%; height: 40px; }
|
||
|
||
/* Node on the spine — tiny dot */
|
||
.evt .node {
|
||
position: absolute;
|
||
left: 46px;
|
||
width: 13px; height: 13px;
|
||
border-radius: 50%;
|
||
background: var(--paper-high);
|
||
z-index: 1;
|
||
}
|
||
.evt.above .node { top: calc(100% + 40px - 6px); }
|
||
.evt.below .node { bottom: calc(100% + 40px - 6px); }
|
||
.evt .node::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 3.5px;
|
||
border-radius: 50%;
|
||
background: var(--ink-soft);
|
||
}
|
||
|
||
.evt[data-accent="copper"] .node::after { background: var(--copper); }
|
||
.evt[data-accent="ochre"] .node::after { background: var(--ochre); }
|
||
.evt[data-accent="terracotta"] .node::after { background: var(--terracotta); }
|
||
.evt[data-accent="crimson"] .node::after { background: var(--crimson); }
|
||
|
||
.evt .tag-row {
|
||
display: flex; gap: 12px; align-items: center;
|
||
margin-bottom: 8px;
|
||
}
|
||
.evt .date {
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-style: italic;
|
||
font-size: 13px;
|
||
color: var(--ink-soft);
|
||
letter-spacing: 0;
|
||
}
|
||
.evt .kind {
|
||
font-size: 9px;
|
||
letter-spacing: 0.22em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-dim);
|
||
font-weight: 600;
|
||
}
|
||
.evt[data-accent="copper"] .kind { color: var(--copper); }
|
||
.evt[data-accent="ochre"] .kind { color: var(--ochre); }
|
||
.evt[data-accent="terracotta"] .kind { color: var(--terracotta); }
|
||
.evt[data-accent="crimson"] .kind { color: var(--crimson); }
|
||
|
||
.evt h3 {
|
||
grid-area: head;
|
||
align-self: start;
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-weight: 400;
|
||
font-size: 41px;
|
||
line-height: 1.12;
|
||
letter-spacing: -0.015em;
|
||
color: var(--ink);
|
||
margin: 0;
|
||
text-wrap: pretty;
|
||
}
|
||
/* Bold-italic emphasis in headlines gets the red accent so each card
|
||
carries a consistent touch of colour while staying editorial. */
|
||
.evt h3 em {
|
||
font-style: italic;
|
||
font-weight: 700;
|
||
color: var(--crimson);
|
||
}
|
||
|
||
.evt p {
|
||
grid-area: body;
|
||
margin: 0;
|
||
font-size: 16px;
|
||
line-height: 1.5;
|
||
color: var(--ink-soft);
|
||
text-wrap: pretty;
|
||
align-self: start;
|
||
}
|
||
|
||
.evt .source {
|
||
grid-area: source;
|
||
align-self: end;
|
||
margin-top: 0;
|
||
font-size: 9.5px;
|
||
letter-spacing: 0.2em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-dim);
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* ───────── Continue button ─────────
|
||
Right-side anchor, vertically centered so readers crossing the
|
||
timeline can't miss it. Larger editorial block with a circular
|
||
icon on the left and the label on the right. Breath animation
|
||
translates horizontally only; `translateY(-50%)` is applied via
|
||
`top: 50%` centering and kept stable across keyframes. */
|
||
.continue-btn {
|
||
all: unset;
|
||
position: absolute;
|
||
right: 72px;
|
||
top: 50%;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 28px;
|
||
padding: 32px 44px;
|
||
/* Inverted palette — crimson field, paper ink — so the button
|
||
pops out against the timeline's warm paper background. */
|
||
background: var(--crimson);
|
||
color: var(--paper);
|
||
cursor: pointer;
|
||
z-index: 30;
|
||
opacity: 0;
|
||
transform: translate(36px, -50%);
|
||
pointer-events: none;
|
||
box-shadow:
|
||
0 0 0 0.5px rgba(138,58,47,0.22),
|
||
0 28px 52px -20px rgba(138,58,47,0.45),
|
||
0 4px 12px -5px rgba(138,58,47,0.24);
|
||
transition:
|
||
opacity 520ms var(--ease),
|
||
transform 520ms var(--ease),
|
||
box-shadow var(--dur) var(--ease),
|
||
background var(--dur) var(--ease);
|
||
}
|
||
.continue-btn.is-visible {
|
||
opacity: 1;
|
||
transform: translate(0, -50%);
|
||
pointer-events: auto;
|
||
animation: continue-breath 2800ms cubic-bezier(0.2, 0, 0, 1) infinite;
|
||
}
|
||
@keyframes continue-breath {
|
||
0%, 100% { transform: translate(0, -50%); }
|
||
50% { transform: translate(6px, -50%); }
|
||
}
|
||
.continue-btn:hover {
|
||
/* Slight darken on hover so the inverted card still signals it's interactive. */
|
||
background: #7a3229;
|
||
box-shadow:
|
||
0 0 0 0.5px rgba(122,50,41,0.32),
|
||
0 34px 60px -20px rgba(122,50,41,0.55),
|
||
0 5px 14px -5px rgba(122,50,41,0.32);
|
||
}
|
||
.continue-btn .c-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 72px;
|
||
height: 72px;
|
||
color: var(--paper);
|
||
flex: 0 0 auto;
|
||
transition: transform var(--dur) var(--ease);
|
||
}
|
||
.continue-btn .c-icon svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
.continue-btn:hover .c-icon {
|
||
transform: translateX(4px);
|
||
}
|
||
.continue-btn .c-label {
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-size: 36px;
|
||
font-weight: 400;
|
||
letter-spacing: -0.015em;
|
||
color: var(--paper);
|
||
line-height: 1.08;
|
||
max-width: 13ch;
|
||
}
|
||
.continue-btn .c-label em {
|
||
font-style: italic;
|
||
font-weight: 700;
|
||
/* Italic emphasis stays on paper colour so it reads against the crimson field. */
|
||
color: var(--paper);
|
||
}
|
||
|
||
/* ───────── Overview page ───────── */
|
||
|
||
/* Topography layer — concentric ring pattern, parallax-scrolled,
|
||
sitting behind the Europe map. Reads as a visual sibling of the
|
||
entrance page's "currents" pattern but rotated and repositioned so
|
||
it doesn't look like a duplicate. The SVG contents are drawn at
|
||
runtime by drawTopography() in bifrost.js.
|
||
|
||
Transform is driven by JS from Lenis's scroll position (parallax
|
||
speed 0.15× — very slow). z-index 0 so it sits behind the map
|
||
(z-index 1) and content (z-index 2+). */
|
||
.overview-topography {
|
||
position: absolute; inset: 0;
|
||
z-index: 0;
|
||
pointer-events: none;
|
||
overflow: hidden;
|
||
opacity: 0;
|
||
transition: opacity 900ms var(--ease);
|
||
}
|
||
.overview-topography svg {
|
||
position: absolute;
|
||
/* Offset to the opposite corner of the entrance-page currents
|
||
(which sit top-right). Here we anchor bottom-left and extend
|
||
well beyond the viewport so parallax translation never reveals
|
||
an edge. */
|
||
left: -20vw;
|
||
top: -10vh;
|
||
width: 140vw;
|
||
height: 140vh;
|
||
display: block;
|
||
/* Rotate 40° so the rings don't read as an exact copy of the
|
||
entrance's pattern; the viewer registers this as "related but
|
||
distinct". */
|
||
transform: rotate(40deg);
|
||
transform-origin: 50% 50%;
|
||
will-change: transform;
|
||
}
|
||
.page-overview.is-active .overview-topography {
|
||
opacity: 1;
|
||
}
|
||
|
||
/* Globe background behind the overview — same SVG style as the timeline's,
|
||
but centered on Europe. It begins at the timeline's size/position so
|
||
that when the page is entered, the CSS transition zooms it into place. */
|
||
.overview-globe {
|
||
position: absolute; inset: 0;
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
overflow: hidden;
|
||
/* Soft fade at top + bottom so the paper reads as the surface, not the sphere */
|
||
-webkit-mask-image: linear-gradient(to bottom,
|
||
transparent 0%, #000 10%, #000 82%, transparent 100%);
|
||
mask-image: linear-gradient(to bottom,
|
||
transparent 0%, #000 10%, #000 82%, transparent 100%);
|
||
}
|
||
.overview-globe svg {
|
||
position: absolute;
|
||
left: 65%; top: 55%;
|
||
/* Smaller than before — 92vmax is enough to show Europe at the framing we want,
|
||
and it paints fast enough not to block the page fade-in. */
|
||
width: 92vmax;
|
||
height: 92vmax;
|
||
max-width: none;
|
||
transform: translate(-50%, -50%) scale(0.78);
|
||
transform-origin: 50% 50%;
|
||
opacity: 0.22;
|
||
transition:
|
||
transform 1200ms cubic-bezier(0.22, 1, 0.36, 1),
|
||
opacity 900ms var(--ease);
|
||
}
|
||
/* When the overview page becomes active, zoom onto Europe */
|
||
.page-overview.is-active .overview-globe svg {
|
||
transform: translate(-50%, -50%) scale(1.35);
|
||
opacity: 0.42;
|
||
}
|
||
|
||
.overview {
|
||
position: absolute; inset: 0;
|
||
overflow: auto;
|
||
padding: 160px 80px 180px;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(56,56,49,0.18) transparent;
|
||
z-index: 5;
|
||
}
|
||
.overview .col-wrap {
|
||
max-width: 1280px; margin: 0 auto;
|
||
/* Text on the left; globe occupies the right half of the spread. */
|
||
display: grid;
|
||
grid-template-columns: minmax(420px, 560px) 1fr;
|
||
column-gap: 80px;
|
||
row-gap: 24px;
|
||
align-items: start;
|
||
}
|
||
.overview h1 {
|
||
grid-column: 1;
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-weight: 400;
|
||
font-size: 56px;
|
||
line-height: 1.05;
|
||
letter-spacing: -0.025em;
|
||
margin: 0 0 18px 0;
|
||
text-wrap: balance;
|
||
color: var(--ink);
|
||
}
|
||
.overview h1 em {
|
||
font-style: italic; font-weight: 700;
|
||
}
|
||
.overview .lede {
|
||
grid-column: 1;
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-style: italic;
|
||
font-size: 20px;
|
||
line-height: 1.5;
|
||
color: var(--ink-soft);
|
||
max-width: 780px;
|
||
margin-bottom: 28px;
|
||
}
|
||
.overview .rule {
|
||
grid-column: 1;
|
||
height: 1px;
|
||
background: rgba(56,56,49,0.18);
|
||
margin: 14px 0 8px 0;
|
||
}
|
||
.overview p {
|
||
grid-column: 1;
|
||
font-size: 15px;
|
||
line-height: 1.7;
|
||
color: var(--ink);
|
||
margin: 0 0 14px 0;
|
||
text-wrap: pretty;
|
||
}
|
||
.overview p.drop::first-letter {
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-weight: 700;
|
||
font-size: 58px;
|
||
line-height: 0.9;
|
||
float: left;
|
||
padding: 4px 10px 0 0;
|
||
color: var(--ink);
|
||
}
|
||
.overview .meta-strip {
|
||
grid-column: 1;
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 28px 40px;
|
||
margin-top: 32px;
|
||
padding-top: 24px;
|
||
border-top: 0;
|
||
background:
|
||
linear-gradient(to right, rgba(56,56,49,0.18), rgba(56,56,49,0.18)) top / 100% 1px no-repeat;
|
||
}
|
||
.overview .meta-strip .cell {
|
||
display: flex; flex-direction: column; gap: 8px;
|
||
}
|
||
.overview .meta-strip .k {
|
||
font-size: 10.5px;
|
||
letter-spacing: 0.24em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-dim);
|
||
font-weight: 600;
|
||
}
|
||
.overview .meta-strip .v {
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-size: 22px;
|
||
letter-spacing: -0.01em;
|
||
color: var(--ink);
|
||
}
|
||
.overview .meta-strip .v em { font-style: italic; font-weight: 700; }
|
||
|
||
/* Short-viewport safety: collapse the page-title block so cards never collide */
|
||
@media (max-height: 620px) {
|
||
.page-title { font-size: 36px; max-width: 640px; top: 18vh; }
|
||
.page-title + .page-sub { font-size: 21px; top: calc(18vh + 160px); }
|
||
}
|
||
@media (max-height: 500px) {
|
||
.page-title { display: none; }
|
||
.page-sub { display: none; }
|
||
}
|
||
.overview::-webkit-scrollbar { width: 6px; }
|
||
.overview::-webkit-scrollbar-thumb {
|
||
background: rgba(56,56,49,0.18);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
/* ============================================================
|
||
BIFROST OVERLAY — scenes inside the Overview page
|
||
============================================================ */
|
||
|
||
/* Internal scroller — sits inside #page-overview. Hosts the six
|
||
scenes. Scrolls vertically. The Europe map (overview-globe)
|
||
stays as fixed-position background behind it. */
|
||
#overview-scroll {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
z-index: 5;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: rgba(56,56,49,0.18) transparent;
|
||
}
|
||
#overview-scroll::-webkit-scrollbar { width: 6px; }
|
||
#overview-scroll::-webkit-scrollbar-thumb {
|
||
background: rgba(56,56,49,0.18);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
/* Site-1 overview-globe base rule kept; bifrost.js drives opacity
|
||
inline after init, so transition is suppressed by JS. Until JS
|
||
runs, CSS handles the 900ms fade-in on page activation. */
|
||
|
||
/* Hero scene anchored over the Europe map. The map's right-of-
|
||
centre framing is preserved from site 1 (overview-globe CSS at
|
||
left:65%, top:55%, scale 1.35 when .is-active). The hero text
|
||
lives in the left column; the map fills the right ~2/3. */
|
||
#page-overview #hero {
|
||
min-height: 100vh;
|
||
padding-inline: var(--edge);
|
||
display: grid;
|
||
align-items: center;
|
||
position: relative;
|
||
/* Balanced block padding so the grid-centered content sits on
|
||
the true vertical midline instead of being pushed upward by a
|
||
big padding-bottom (the previous asymmetric rule was tuned for
|
||
a taller headline + more foot clearance to the dot-nav). */
|
||
padding-top: clamp(3rem, 8vh, 6rem);
|
||
padding-bottom: clamp(4rem, 10vh, 7rem);
|
||
}
|
||
#page-overview #hero .hero-wrap {
|
||
/* Two-column layout: editorial copy on the left, Fenja wordmark
|
||
on the right — the right column anchors the logo at the same
|
||
viewport position the welcome page uses (~75% across). */
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 58%) minmax(0, 42%);
|
||
gap: clamp(2rem, 5vw, 4rem);
|
||
align-items: center;
|
||
max-width: none;
|
||
padding-top: 0;
|
||
}
|
||
#page-overview #hero .hero-copy {
|
||
/* Indent from the left so the text block floats with breathing
|
||
room on both sides of the viewport, mirroring the space that
|
||
the right-column wordmark has around it. */
|
||
padding-left: clamp(2rem, 8vw, 8rem);
|
||
/* Widened ~20% from 58ch so the column gets more horizontal
|
||
room to breathe; the lede follows to 53ch. */
|
||
max-width: 70ch;
|
||
}
|
||
/* Hero type — tighter than --step-hero, with a +10% bump from the
|
||
previous clamp so the headline has a little more presence at
|
||
this wider column width. */
|
||
#page-overview #hero .hero-title {
|
||
font-size: clamp(1.8rem, 4.4vw, 3.75rem);
|
||
line-height: 1.08;
|
||
}
|
||
#page-overview #hero .hero-lede {
|
||
font-size: clamp(1.1rem, 1.87vw, 1.54rem);
|
||
line-height: 1.45;
|
||
max-width: 53ch;
|
||
}
|
||
|
||
/* Right-column wordmark — sized to match the welcome page's
|
||
.welcome-logo (280px at the top end). Decorative only; the
|
||
heading remains the left-column <h1>. */
|
||
#page-overview #hero .hero-mark {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
pointer-events: none;
|
||
}
|
||
#page-overview #hero .hero-mark img {
|
||
width: clamp(200px, 22vw, 320px);
|
||
height: auto;
|
||
display: block;
|
||
opacity: 0.92;
|
||
}
|
||
/* No separate reveal/opacity rule needed: the whole .hero-wrap
|
||
fades in as one via bifrost.js's hero tween, so both columns
|
||
arrive together. */
|
||
|
||
/* Make sure scenes don't accidentally inherit `main { position: relative }` */
|
||
#overview-scroll > section { position: relative; z-index: 2; }
|
||
|
||
|
||
/* ============================================================
|
||
BIFROST SCENES — tokens (scoped to #page-overview only, so
|
||
they never leak to the timeline page).
|
||
Palette reconciled with site 1's Nordic Editorial system.
|
||
============================================================ */
|
||
#page-overview {
|
||
--ink: #383831; /* site 1 --on-surface (charcoal slate) */
|
||
--ink-soft: #5f5e5e; /* site 1 --on-surface-variant */
|
||
--ink-mute: #8a887f; /* site 1 --on-surface-muted */
|
||
--ink-faint: #ddd6c3; /* site 1 --surface-container-highest */
|
||
--paper: #faf6ee; /* site 1 --background */
|
||
--paper-2: #f6f2e8; /* site 1 --surface-container-low */
|
||
--paper-3: #efeadc; /* site 1 --surface-container */
|
||
--accent: #b96b58; /* site 1 --pigment-terracotta */
|
||
--ring: #6d8c7c; /* site 1 --pigment-copper */
|
||
|
||
/* aurora gradient — site-1 Archival Pigments, kept exclusive to Scene 4 */
|
||
--aurora-1: #c29d59; /* site 1 --pigment-ochre */
|
||
--aurora-2: #b96b58; /* site 1 --pigment-terracotta */
|
||
--aurora-3: #5a6d83; /* site 1 --pigment-indigo */
|
||
--aurora-4: #8d7a85; /* site 1 --pigment-heather */
|
||
|
||
--type-body: "Manrope", ui-sans-serif, system-ui, sans-serif;
|
||
--type-display: "Newsreader", Georgia, serif;
|
||
|
||
--step-hero: clamp(2rem, 5.1vw, 4.4rem);
|
||
--step-xl: clamp(1.8rem, 4.8vw, 4rem);
|
||
--step-lg: clamp(1.35rem, 3vw, 2.2rem);
|
||
--step-md: clamp(1rem, 1.4vw, 1.15rem);
|
||
--step-sm: clamp(0.85rem, 1vw, 0.95rem);
|
||
|
||
--edge: clamp(1.5rem, 4vw, 4rem);
|
||
}
|
||
|
||
/* ============================================================
|
||
TOKENS
|
||
============================================================ */
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
html {
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
text-rendering: optimizeLegibility;
|
||
scroll-behavior: auto; /* Lenis handles it */
|
||
}
|
||
|
||
/* Paper-grain noise overlay for tactile warmth */
|
||
/* Faint contour lines in the background for the whole page — Nordic-map motif */
|
||
/* ============================================================
|
||
LAYOUT PRIMITIVES
|
||
============================================================ */
|
||
.scene {
|
||
position: relative;
|
||
min-height: 100vh;
|
||
padding-inline: var(--edge);
|
||
display: grid;
|
||
align-items: center;
|
||
}
|
||
|
||
/* ============================================================
|
||
SCENE 1 — HERO
|
||
============================================================ */
|
||
#hero {
|
||
min-height: 100vh;
|
||
/* Reduced from clamp(7rem, 14vh, 11rem) to pull the hero text up
|
||
into the upper half of the viewport. The original value centered
|
||
the text too low when measured against the site mark at top. */
|
||
padding-top: clamp(3.5rem, 7vh, 5.5rem);
|
||
grid-template-columns: 1fr;
|
||
align-items: start;
|
||
}
|
||
.hero-wrap {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: clamp(2rem, 6vw, 4rem);
|
||
align-items: end;
|
||
max-width: 1600px;
|
||
width: 100%;
|
||
margin-inline: auto;
|
||
padding-top: clamp(2rem, 6vh, 4rem);
|
||
}
|
||
/* Hide the hero on first paint while JS is booting so it doesn't
|
||
flash in raw form during the page-activation transition. The
|
||
Bifrost init fades it in once ScrollTriggers are wired up. */
|
||
.js .hero-wrap { opacity: 0; }
|
||
|
||
.eyebrow {
|
||
font-size: var(--step-sm);
|
||
letter-spacing: 0.22em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-mute);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
margin-bottom: clamp(1.4rem, 4vh, 2.4rem);
|
||
font-weight: 500;
|
||
}
|
||
.eyebrow::before {
|
||
content: "";
|
||
width: 28px; height: 1px;
|
||
background: var(--ink-mute);
|
||
}
|
||
|
||
.hero-title {
|
||
font-family: var(--type-display);
|
||
font-weight: 330;
|
||
font-size: var(--step-hero);
|
||
line-height: 1.06;
|
||
letter-spacing: -0.025em;
|
||
color: var(--ink);
|
||
margin: 0;
|
||
max-width: 30ch;
|
||
}
|
||
.hero-title em {
|
||
font-style: italic;
|
||
font-weight: 340;
|
||
color: var(--accent);
|
||
}
|
||
|
||
.hero-lede {
|
||
max-width: 46ch;
|
||
font-size: var(--step-lg);
|
||
font-weight: 300;
|
||
line-height: 1.35;
|
||
color: var(--ink-soft);
|
||
margin-top: clamp(1.5rem, 4vh, 2.5rem);
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
/* Hero foot row — lives INSIDE the left column at the bottom of the
|
||
paragraph block. Displays "Supported by Innovationsfonden" on the
|
||
left and the scroll-down indicator on the right, sharing a single
|
||
baseline. The row sits immediately after the lede paragraph. */
|
||
.hero-foot {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: baseline;
|
||
gap: 1.5rem;
|
||
margin-top: clamp(2rem, 5vh, 3.5rem);
|
||
font-size: var(--step-sm);
|
||
color: var(--ink-mute);
|
||
letter-spacing: 0.04em;
|
||
}
|
||
.support {
|
||
display: flex;
|
||
align-items: center;
|
||
/* Matched to the welcome page's .welcome-backer: 11px uppercase
|
||
text, 0.18em tracking. The wordmark SVG grows to 24px so the
|
||
Innovationsfonden lockup reads more confidently while the
|
||
accompanying "Backed by" label stays quiet. */
|
||
gap: 10px;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.18em;
|
||
}
|
||
.support svg { height: 24px; width: auto; }
|
||
|
||
/* Two-line backer block: the Innovationsfonden lockup above, the
|
||
"Part of BioInnovation Institute AI Lab" line directly below.
|
||
Mirrors the entrance page's .welcome-backer + .welcome-bii pair. */
|
||
.support-stack {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 6px;
|
||
}
|
||
.support-bii {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.18em;
|
||
color: var(--ink-soft, var(--ink-mute));
|
||
}
|
||
|
||
.scroll-hint {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.7rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.22em;
|
||
/* Bumped from --step-sm for legibility. The hint is the primary
|
||
"what next?" cue at the bottom of the hero and needs to read
|
||
confidently, not whisper. */
|
||
font-size: calc(var(--step-sm) * 1.15);
|
||
font-weight: 600;
|
||
/* Switched from --ink-soft to --ink so the icon reads against the
|
||
paper background. The hint animation still breathes opacity so
|
||
it doesn't shout. */
|
||
color: var(--ink);
|
||
}
|
||
/* Arrow reoriented to point DOWN — a vertical line with a chevron
|
||
cap at the bottom. Animation moved from translateX to translateY so
|
||
the hint visually "drops" downward, matching its meaning. Weight
|
||
and length both bumped (1px → 2px, 28px → 44px) so the icon has
|
||
more visual presence; chevron arms thickened and enlarged to match. */
|
||
.scroll-hint .arrow {
|
||
width: 2px; height: 44px; background: currentColor;
|
||
position: relative;
|
||
animation: hint 2.2s ease-in-out infinite;
|
||
}
|
||
.scroll-hint .arrow::after {
|
||
content: ""; position: absolute; bottom: -1px; left: -5px;
|
||
width: 11px; height: 11px;
|
||
border-right: 2px solid currentColor;
|
||
border-bottom: 2px solid currentColor;
|
||
transform: rotate(45deg);
|
||
}
|
||
@keyframes hint {
|
||
0%, 100% { transform: translateY(0); opacity: 0.75; }
|
||
50% { transform: translateY(8px); opacity: 1; }
|
||
}
|
||
|
||
/* ============================================================
|
||
SCENE 2 — ARCHITECTURE (pinned, scrubbed)
|
||
4 layer-cards that fall in, stack with an offset revealing
|
||
each previous layer's bottom strip, then rearrange into a
|
||
2x2 grid on the right while explanatory copy appears on
|
||
the left.
|
||
============================================================ */
|
||
#stack-scene { position: relative; }
|
||
.stack-pin {
|
||
position: relative;
|
||
height: 100vh;
|
||
padding-inline: var(--edge);
|
||
max-width: none;
|
||
margin-inline: auto;
|
||
display: grid;
|
||
place-items: center;
|
||
padding-top: clamp(6rem, 11vh, 8.5rem); /* keep clear of brand mark */
|
||
}
|
||
|
||
/* Theatre — holds cards absolutely positioned. GSAP drives positions. */
|
||
.layer-theatre {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
max-width: none;
|
||
}
|
||
|
||
/* ───────── Stack scene title bar ─────────
|
||
Sits above the card theatre and rides with the pin so it remains
|
||
visible through all four card landings and the grid rearrange.
|
||
Centered horizontally; positioned lower so the title anchors
|
||
visually to the cards below rather than floating at the top of
|
||
the viewport. Per-card counter (1/4, 2/4, …) now lives inside
|
||
each .layer-card rather than being slaved to scroll progress. */
|
||
.stack-title-bar {
|
||
position: absolute;
|
||
top: clamp(5.5rem, 14vh, 10rem);
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 20;
|
||
text-align: center;
|
||
padding-inline: clamp(1rem, 4vw, 3rem);
|
||
pointer-events: none;
|
||
}
|
||
.stack-title {
|
||
margin: 0;
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-weight: 400;
|
||
font-size: clamp(2rem, 3.6vw, 3rem);
|
||
letter-spacing: -0.015em;
|
||
line-height: 1.12;
|
||
color: var(--ink);
|
||
}
|
||
|
||
/* LEFT COPY (visible only during grid phase) */
|
||
.copy-stage {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 0; /* full theatre height so copy-layer can vertically center */
|
||
width: 42%;
|
||
max-width: 46ch;
|
||
z-index: 10;
|
||
pointer-events: none;
|
||
}
|
||
.copy-layer {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
top: 50%; /* vertically center */
|
||
will-change: opacity, transform;
|
||
}
|
||
.js .copy-layer { opacity: 0; }
|
||
.copy-layer h2 {
|
||
font-family: var(--type-display);
|
||
font-weight: 340;
|
||
font-size: var(--step-xl);
|
||
line-height: 1.04;
|
||
letter-spacing: -0.025em;
|
||
color: var(--ink);
|
||
margin: 0 0 1rem;
|
||
}
|
||
.copy-layer h2 em { font-style: italic; color: var(--accent); font-weight: 400; }
|
||
.copy-layer h2 strong { font-weight: 600; font-style: normal; }
|
||
.copy-layer p {
|
||
font-size: var(--step-lg);
|
||
font-weight: 300;
|
||
line-height: 1.35;
|
||
color: var(--ink-soft);
|
||
margin: 0;
|
||
max-width: 38ch;
|
||
letter-spacing: -0.005em;
|
||
}
|
||
.copy-layer .tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.6rem;
|
||
font-size: var(--step-sm);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.22em;
|
||
color: var(--ink-mute);
|
||
margin-bottom: 1rem;
|
||
font-weight: 500;
|
||
}
|
||
.copy-layer .tag::before {
|
||
content: "";
|
||
width: 20px; height: 1px;
|
||
background: currentColor;
|
||
}
|
||
|
||
/* -------- Layer cards -------- */
|
||
.layer-card {
|
||
position: absolute;
|
||
/* 7.5% margin on each side = 15% total width reduction from the
|
||
original edge-to-edge layout. */
|
||
left: 7.5%;
|
||
right: 7.5%;
|
||
top: 50%;
|
||
width: auto;
|
||
transform: translateY(-50%);
|
||
transform-origin: center center;
|
||
will-change: transform, opacity;
|
||
}
|
||
.layer-card .card-eyebrow {
|
||
display: block;
|
||
font-size: var(--step-sm);
|
||
letter-spacing: 0.28em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-soft);
|
||
margin: 0 0 0.9rem 0.25rem;
|
||
font-weight: 500;
|
||
will-change: opacity;
|
||
}
|
||
|
||
.card-box {
|
||
position: relative;
|
||
border-radius: 22px;
|
||
/* Reduced 15% from the original clamp(1.75rem, 3.2vw, 2.8rem) for a
|
||
slimmer, quieter card presence. */
|
||
padding: clamp(1.5rem, 2.7vw, 2.4rem);
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.9fr);
|
||
gap: clamp(0.85rem, 2.1vw, 1.9rem);
|
||
align-items: center;
|
||
overflow: hidden;
|
||
/* contain: paint forces transformed children (with will-change:
|
||
transform creating compositing layers) to respect this box's
|
||
overflow clipping. Without it, the brain's counter-scale
|
||
transform during the morph escapes the box bounds. */
|
||
contain: paint;
|
||
box-shadow: 0 22px 48px -18px rgba(46,46,40,0.28), 0 8px 22px -8px rgba(46,46,40,0.16);
|
||
/* 15% reduction from the original 240px — matches the lateral shrink */
|
||
min-height: 204px;
|
||
}
|
||
.card-content { min-width: 0; }
|
||
.card-title {
|
||
font-family: var(--type-display);
|
||
font-weight: 330;
|
||
font-size: clamp(2.08rem, 4.3vw, 3.32rem);
|
||
line-height: 1.06;
|
||
letter-spacing: -0.018em;
|
||
margin: 0 0 1.1rem;
|
||
color: #fffcf7;
|
||
}
|
||
.card-title b { font-weight: 640; font-style: normal; }
|
||
.card-title em { font-style: italic; font-weight: 640; }
|
||
.card-body {
|
||
font-size: clamp(1.2rem, 1.5vw, 1.4rem);
|
||
line-height: 1.4;
|
||
color: #fffcf7;
|
||
margin: 0;
|
||
max-width: 38ch;
|
||
font-weight: 400;
|
||
opacity: 0.88;
|
||
will-change: opacity;
|
||
}
|
||
|
||
/* Card illustration — per-layer PNG set via --card-illust custom property. */
|
||
.card-brain {
|
||
width: 100%;
|
||
aspect-ratio: 20 / 17;
|
||
background-image: var(--card-illust);
|
||
background-size: contain;
|
||
background-position: center right;
|
||
background-repeat: no-repeat;
|
||
opacity: 0.95;
|
||
margin-right: clamp(-3.5rem, -3vw, -1.5rem); /* bleed off right edge */
|
||
pointer-events: none;
|
||
will-change: transform;
|
||
}
|
||
|
||
/* Per-layer colours — muted Nordic mid-tones. */
|
||
.layer-card[data-layer="0"] .card-box { background: #7a8c70; } /* sage — AI Model */
|
||
.layer-card[data-layer="1"] .card-box { background: #7b9399; } /* slate — Knowledge */
|
||
.layer-card[data-layer="2"] .card-box { background: #b07556; } /* clay — Tools */
|
||
.layer-card[data-layer="3"] .card-box { background: #8a7a92; } /* plum — Agents */
|
||
|
||
/* Per-layer illustrations — URL-encode spaces in filenames. */
|
||
.layer-card[data-layer="0"] .card-brain { --card-illust: url('/fenja/illustrations/ai.png'); }
|
||
.layer-card[data-layer="1"] .card-brain { --card-illust: url('/fenja/illustrations/lightbulb%20-%20knowledge.png'); }
|
||
.layer-card[data-layer="2"] .card-brain { --card-illust: url('/fenja/illustrations/blocs%20tools.png'); }
|
||
.layer-card[data-layer="3"] .card-brain { --card-illust: url('/fenja/illustrations/agents.png'); }
|
||
|
||
/* z-stacking — later layers appear on top */
|
||
.layer-card[data-layer="0"] { z-index: 1; }
|
||
.layer-card[data-layer="1"] { z-index: 2; }
|
||
.layer-card[data-layer="2"] { z-index: 3; }
|
||
.layer-card[data-layer="3"] { z-index: 4; }
|
||
|
||
/* -------- GRID PHASE — cards become aligned SQUARES -------- */
|
||
/* When the .in-grid class is toggled on .layer-theatre, each card-box
|
||
becomes a 20vw square (via .in-grid .card-box), centered in its
|
||
full-width parent. Inside, the layout switches: the outside eyebrow
|
||
hides; a dedicated grid-label shows at the top; the long title and
|
||
body hide; the brain fills the rest centered.
|
||
|
||
The grid-label is ALWAYS in the DOM (absolutely-positioned inside
|
||
card-box with opacity:0 by default) so GSAP can fade it in smoothly
|
||
during the morph transition, rather than it snapping on when the
|
||
.in-grid class applies. */
|
||
|
||
.card-grid-label {
|
||
position: absolute;
|
||
left: clamp(1rem, 1.4vw, 1.4rem);
|
||
top: clamp(1rem, 1.4vw, 1.4rem);
|
||
font-size: clamp(0.75rem, 0.95vw, 0.95rem);
|
||
letter-spacing: 0.22em;
|
||
text-transform: uppercase;
|
||
color: #fffcf7;
|
||
opacity: 0;
|
||
font-weight: 500;
|
||
text-align: left;
|
||
line-height: 1;
|
||
pointer-events: none;
|
||
z-index: 2;
|
||
}
|
||
|
||
/* Per-card counter — lives in the top-right of each card-box and
|
||
reads "1 / 4" through "4 / 4". Paper-toned to contrast against
|
||
the sage/slate/clay/plum card backgrounds. */
|
||
.card-counter {
|
||
position: absolute;
|
||
top: clamp(1rem, 1.4vw, 1.4rem);
|
||
right: clamp(1rem, 1.4vw, 1.4rem);
|
||
font-family: "Newsreader", Georgia, serif;
|
||
font-weight: 500;
|
||
font-size: clamp(0.85rem, 1.05vw, 1.05rem);
|
||
letter-spacing: 0.04em;
|
||
color: rgba(255, 252, 247, 0.85);
|
||
font-variant-numeric: tabular-nums;
|
||
line-height: 1;
|
||
pointer-events: none;
|
||
z-index: 2;
|
||
}
|
||
.in-grid .card-counter {
|
||
/* Keep the counter visible in the grid phase but smaller so it
|
||
doesn't compete with the grid-label. */
|
||
top: clamp(0.5rem, 0.7vw, 0.8rem);
|
||
right: clamp(0.5rem, 0.7vw, 0.8rem);
|
||
font-size: clamp(0.6rem, 0.7vw, 0.75rem);
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.in-grid .card-box {
|
||
/* 15% reduction from the original 20vw — matches the drop-phase shrink.
|
||
Also matches cellSize and targetW in bifrost.js (both are vw * 0.17). */
|
||
max-width: 17vw;
|
||
width: 17vw;
|
||
aspect-ratio: 1 / 1;
|
||
margin: 0 auto;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
justify-content: flex-start;
|
||
grid-template-columns: unset;
|
||
grid-template-rows: unset;
|
||
padding: clamp(0.85rem, 1.2vw, 1.2rem);
|
||
gap: 0;
|
||
min-height: 0;
|
||
border-radius: 16px;
|
||
}
|
||
|
||
/* In grid state the label is visible; position resets inside the
|
||
flex column */
|
||
.in-grid .card-grid-label {
|
||
opacity: 0.88;
|
||
position: relative;
|
||
left: auto;
|
||
top: auto;
|
||
margin: 0 0 0.5rem;
|
||
}
|
||
|
||
/* Hide long title + body in grid phase */
|
||
.in-grid .card-content { display: none; }
|
||
|
||
/* Illustration fills remaining space, centered. */
|
||
.in-grid .card-brain {
|
||
margin: 0;
|
||
flex: 1 1 auto;
|
||
width: 100%;
|
||
aspect-ratio: auto;
|
||
background-position: center;
|
||
background-size: 90% auto;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
/* Hide the outside-box eyebrow during grid phase */
|
||
.in-grid .layer-card .card-eyebrow {
|
||
opacity: 0 !important;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* ============================================================
|
||
SCENE 3 — SLIDE 11 — words fly in
|
||
============================================================ */
|
||
#words-scene {
|
||
position: relative;
|
||
height: 260vh;
|
||
}
|
||
.words-pin {
|
||
position: sticky;
|
||
top: 0;
|
||
height: 100vh;
|
||
display: grid;
|
||
place-items: center;
|
||
padding-inline: var(--edge);
|
||
}
|
||
.words {
|
||
font-family: var(--type-display);
|
||
font-weight: 320;
|
||
font-size: clamp(2rem, 6vw, 5.2rem);
|
||
line-height: 1.06;
|
||
letter-spacing: -0.025em;
|
||
color: var(--ink);
|
||
max-width: 22ch;
|
||
margin: 0 auto;
|
||
text-align: left;
|
||
}
|
||
.words .w {
|
||
display: inline-block;
|
||
will-change: transform, opacity;
|
||
margin-right: 0.25em;
|
||
}
|
||
.js .words .w { opacity: 0; }
|
||
.words .w.hi {
|
||
font-style: italic;
|
||
color: var(--accent);
|
||
font-weight: 420;
|
||
}
|
||
|
||
/* ============================================================
|
||
SCENE 4 — PROJECT BIFROST REVEAL
|
||
============================================================ */
|
||
#bifrost {
|
||
position: relative;
|
||
min-height: 200vh;
|
||
}
|
||
.bifrost-pin {
|
||
position: sticky;
|
||
top: 0;
|
||
height: 100vh;
|
||
display: grid;
|
||
place-items: center;
|
||
overflow: hidden;
|
||
}
|
||
.bifrost-stage {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: grid;
|
||
place-items: center;
|
||
}
|
||
|
||
/* the arc — bifrost bridge */
|
||
.arc-wrap {
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 50%;
|
||
width: min(120vw, 1400px);
|
||
translate: -50% -50%;
|
||
pointer-events: none;
|
||
will-change: opacity, transform;
|
||
}
|
||
.js .arc-wrap { opacity: 0; }
|
||
.arc-wrap svg { display: block; width: 100%; height: auto; overflow: visible; }
|
||
|
||
.bifrost-text {
|
||
position: relative;
|
||
z-index: 2;
|
||
text-align: center;
|
||
max-width: 90vw;
|
||
padding: 0 var(--edge);
|
||
}
|
||
.bifrost-eyebrow {
|
||
font-size: var(--step-sm);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.32em;
|
||
color: var(--ink-soft);
|
||
margin-bottom: clamp(1rem, 3vh, 1.8rem);
|
||
will-change: opacity, transform;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.8rem;
|
||
}
|
||
.js .bifrost-eyebrow { opacity: 0; }
|
||
.bifrost-eyebrow::before,
|
||
.bifrost-eyebrow::after {
|
||
content: "";
|
||
width: 28px; height: 1px;
|
||
background: currentColor;
|
||
}
|
||
.bifrost-name {
|
||
font-family: var(--type-display);
|
||
font-weight: 320;
|
||
font-size: clamp(3rem, 10vw, 9rem);
|
||
/* Loosened from 0.95 to 1.12 and padded so the italic "Bifrost"
|
||
token's ascenders/descenders clear the .bifrost-pin's
|
||
overflow:hidden (which exists to clip the aurora arc). */
|
||
line-height: 1.12;
|
||
letter-spacing: -0.04em;
|
||
color: var(--ink);
|
||
margin: 0;
|
||
padding: 0.12em 0.08em;
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 0.15em;
|
||
flex-wrap: wrap;
|
||
overflow: visible;
|
||
}
|
||
.bifrost-name .token {
|
||
display: inline-block;
|
||
will-change: transform, opacity, filter;
|
||
}
|
||
.js .bifrost-name .token { opacity: 0; }
|
||
.bifrost-name .token.accent {
|
||
font-style: italic;
|
||
background: linear-gradient(100deg, var(--aurora-1) 0%, var(--aurora-2) 32%, var(--aurora-3) 68%, var(--aurora-4) 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
}
|
||
.bifrost-sub {
|
||
margin-top: clamp(1.4rem, 4vh, 2.2rem);
|
||
font-size: var(--step-lg);
|
||
font-weight: 300;
|
||
color: var(--ink-soft);
|
||
max-width: 44ch;
|
||
margin-inline: auto;
|
||
line-height: 1.35;
|
||
will-change: opacity, transform;
|
||
}
|
||
.js .bifrost-sub { opacity: 0; }
|
||
.bifrost-sub em {
|
||
font-style: italic;
|
||
color: var(--ink);
|
||
}
|
||
|
||
/* Credits */
|
||
.credits {
|
||
position: relative;
|
||
padding: clamp(4rem, 12vh, 8rem) var(--edge) clamp(2rem, 4vh, 3rem);
|
||
border-top: 1px solid rgba(46,46,40,0.1);
|
||
margin-top: 8vh;
|
||
font-size: var(--step-sm);
|
||
color: var(--ink-mute);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 2rem;
|
||
flex-wrap: wrap;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
.credits .col a {
|
||
color: var(--ink-soft);
|
||
text-decoration: none;
|
||
border-bottom: 1px solid rgba(46,46,40,0.2);
|
||
padding-bottom: 1px;
|
||
transition: border-color 0.2s, color 0.2s;
|
||
}
|
||
.credits .col a:hover { color: var(--accent); border-color: var(--accent); }
|
||
|
||
/* ============================================================
|
||
RESPONSIVE
|
||
============================================================ */
|
||
@media (max-width: 900px) {
|
||
#page-overview { --edge: 1.25rem; }
|
||
|
||
.meta { display: none; }
|
||
.rail { display: none; }
|
||
.brand-sub { display: none; } /* too cramped on small screens */
|
||
|
||
.stack-pin {
|
||
padding-top: 5rem;
|
||
}
|
||
.copy-stage {
|
||
width: 100%;
|
||
max-width: 100%;
|
||
position: relative;
|
||
top: auto;
|
||
transform: none;
|
||
}
|
||
.copy-layer h2 { font-size: clamp(1.6rem, 5.5vw, 2.2rem); }
|
||
.copy-layer p { font-size: 1rem; }
|
||
|
||
/* Cards shrink on mobile — single column body + smaller brain */
|
||
.layer-card { width: 92%; }
|
||
.card-box {
|
||
grid-template-columns: 1fr;
|
||
min-height: 0;
|
||
padding: 1.4rem;
|
||
}
|
||
.card-title { font-size: clamp(1.25rem, 5vw, 1.7rem); }
|
||
.card-body { font-size: 0.92rem; }
|
||
.card-brain {
|
||
max-width: 180px;
|
||
justify-self: end;
|
||
margin-right: -1rem;
|
||
aspect-ratio: 20 / 14;
|
||
}
|
||
|
||
.hero-foot { margin-top: 2rem; flex-direction: column; gap: 1rem; align-items: flex-start; }
|
||
#hero { padding-top: 5rem; padding-bottom: 3rem; min-height: auto; }
|
||
/* Narrow viewports: collapse the hero's 2-column grid so the
|
||
wordmark sits below the copy instead of beside it. */
|
||
#page-overview #hero .hero-wrap {
|
||
grid-template-columns: 1fr;
|
||
gap: 2rem;
|
||
}
|
||
#page-overview #hero .hero-mark { justify-content: flex-start; }
|
||
#page-overview #hero .hero-mark img { width: clamp(160px, 40vw, 220px); }
|
||
}
|
||
|
||
@media (max-width: 520px) {
|
||
.hero-title { font-size: clamp(2.2rem, 10vw, 3.2rem); }
|
||
.hero-lede { font-size: 1.05rem; }
|
||
.card-eyebrow { font-size: 0.72rem !important; letter-spacing: 0.2em; }
|
||
}
|
||
|
||
/* ============================================================
|
||
REDUCED MOTION — degraded version reveals all content
|
||
============================================================ */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
#words-scene, #bifrost { height: auto !important; min-height: 0 !important; }
|
||
.stack-pin, .words-pin, .bifrost-pin {
|
||
position: relative !important;
|
||
height: auto !important;
|
||
min-height: auto;
|
||
padding-block: 4rem;
|
||
display: block !important;
|
||
}
|
||
.layer-theatre {
|
||
position: relative !important;
|
||
height: auto !important;
|
||
}
|
||
.layer-card {
|
||
position: relative !important;
|
||
left: auto !important; top: auto !important;
|
||
transform: none !important;
|
||
margin: 0 auto 2rem !important;
|
||
width: 100% !important;
|
||
max-width: 900px;
|
||
}
|
||
.card-body { opacity: 1 !important; }
|
||
.card-eyebrow { opacity: 1 !important; }
|
||
.copy-stage {
|
||
position: relative !important;
|
||
top: auto !important;
|
||
transform: none !important;
|
||
width: 100% !important;
|
||
max-width: 900px;
|
||
margin: 2rem auto 0;
|
||
}
|
||
.copy-layer { position: static !important; opacity: 1 !important; transform: none !important; margin-bottom: 3rem; }
|
||
.brand-sub { opacity: 1 !important; transform: none !important; }
|
||
.words .w { opacity: 1 !important; transform: none !important; }
|
||
.bifrost-eyebrow, .bifrost-sub, .arc-wrap { opacity: 1 !important; transform: translate(-50%, -50%) !important; }
|
||
.arc-wrap { transform: translate(-50%, -50%) !important; }
|
||
.bifrost-name .token { opacity: 1 !important; transform: none !important; filter: none !important; }
|
||
.scroll-hint .arrow { animation: none; }
|
||
}
|
||
/* Illustration data URIs — defined once, referenced by both
|
||
the treasure-map stops and the summary cards below. */
|
||
/* Illustration paths — real SVG files, self-hosted under protected/fenja/illustrations/ */
|
||
#page-overview {
|
||
--illust-community: url("/fenja/illustrations/community.svg");
|
||
--illust-council: url("/fenja/illustrations/council.svg");
|
||
--illust-pilot: url("/fenja/illustrations/pilot.svg");
|
||
}
|
||
/* ============================================================
|
||
SCENE 5 — PROJECT BIFROST · WHAT IT MEANS (treasure-map)
|
||
A meandering path drawn down the page with one intro stop
|
||
and three component stops revealed sequentially as the user
|
||
scrolls. Each component pairs body copy with an illustration
|
||
that fades in alongside it.
|
||
============================================================ */
|
||
#bifrost-meaning {
|
||
position: relative;
|
||
padding: clamp(6rem, 14vh, 12rem) var(--edge) clamp(4rem, 10vh, 8rem);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.map-intro {
|
||
max-width: 60ch;
|
||
margin: 0 auto clamp(5rem, 12vh, 9rem);
|
||
text-align: center;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
.map-intro .map-eyebrow {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
font-size: var(--step-sm);
|
||
letter-spacing: 0.32em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-mute);
|
||
margin-bottom: clamp(1.4rem, 3.5vh, 2rem);
|
||
font-weight: 500;
|
||
}
|
||
.map-intro .map-eyebrow::before,
|
||
.map-intro .map-eyebrow::after {
|
||
content: "";
|
||
width: 28px; height: 1px;
|
||
background: currentColor;
|
||
}
|
||
.map-title {
|
||
font-family: var(--type-display);
|
||
font-weight: 330;
|
||
font-size: var(--step-xl);
|
||
line-height: 1.04;
|
||
letter-spacing: -0.025em;
|
||
color: var(--ink);
|
||
margin: 0 0 clamp(1rem, 2.5vh, 1.5rem);
|
||
}
|
||
.map-title em {
|
||
font-style: italic;
|
||
color: var(--accent);
|
||
font-weight: 400;
|
||
}
|
||
.map-lede {
|
||
font-size: var(--step-lg);
|
||
font-weight: 300;
|
||
line-height: 1.4;
|
||
color: var(--ink-soft);
|
||
margin: 0 auto;
|
||
max-width: 56ch;
|
||
letter-spacing: -0.005em;
|
||
}
|
||
.map-lede em {
|
||
font-style: italic;
|
||
color: var(--ink);
|
||
font-weight: 400;
|
||
}
|
||
|
||
/* The map canvas — relative container holding the path SVG and stops */
|
||
.map-canvas {
|
||
position: relative;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
/* Wandering path — SVG stretched to canvas dimensions */
|
||
.map-path {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 0;
|
||
overflow: visible;
|
||
}
|
||
.map-path .path-bg {
|
||
fill: none;
|
||
stroke: var(--ink);
|
||
stroke-opacity: 0.18;
|
||
stroke-width: 1.2;
|
||
stroke-dasharray: 4 6;
|
||
stroke-linecap: round;
|
||
}
|
||
.map-path .path-draw {
|
||
fill: none;
|
||
stroke: var(--accent);
|
||
stroke-opacity: 0.7;
|
||
stroke-width: 1.6;
|
||
stroke-linecap: round;
|
||
}
|
||
|
||
/* A stop — three-column grid: text | dot | image (alternating sides) */
|
||
.map-stop {
|
||
position: relative;
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||
align-items: center;
|
||
gap: clamp(2rem, 5vw, 4.5rem);
|
||
margin-bottom: clamp(7rem, 14vh, 11rem);
|
||
z-index: 2;
|
||
}
|
||
.map-stop:last-child { margin-bottom: 0; }
|
||
|
||
/* Intro stop is single-column, centered, no image */
|
||
.map-stop--intro {
|
||
grid-template-columns: 1fr;
|
||
text-align: center;
|
||
margin-bottom: clamp(7rem, 14vh, 11rem);
|
||
justify-items: center;
|
||
}
|
||
.map-stop--intro .stop-content {
|
||
max-width: 46ch;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
/* Dot anchor — sits on the path */
|
||
.dot-anchor {
|
||
position: relative;
|
||
width: 16px;
|
||
height: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
z-index: 3;
|
||
}
|
||
.map-stop[data-side="left"] .dot-anchor { grid-column: 2; }
|
||
.map-stop[data-side="right"] .dot-anchor { grid-column: 2; }
|
||
|
||
.dot {
|
||
position: relative;
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: 50%;
|
||
background: var(--paper);
|
||
border: 2px solid var(--accent);
|
||
/* paper-coloured ring masks the path passing under the dot */
|
||
box-shadow: 0 0 0 6px var(--paper);
|
||
z-index: 2;
|
||
}
|
||
/* Soft pulse halo on the dot */
|
||
.dot::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: -10px;
|
||
border-radius: 50%;
|
||
border: 1px solid var(--accent);
|
||
opacity: 0.35;
|
||
z-index: -1;
|
||
}
|
||
|
||
.map-stop--intro .dot-anchor {
|
||
margin-bottom: clamp(1.5rem, 4vh, 2.5rem);
|
||
}
|
||
|
||
/* Text and image columns — alternating sides */
|
||
.map-stop[data-side="left"] .stop-content { grid-column: 1; text-align: left; }
|
||
.map-stop[data-side="left"] .stop-image { grid-column: 3; justify-self: start; }
|
||
.map-stop[data-side="right"] .stop-image { grid-column: 1; justify-self: end; }
|
||
.map-stop[data-side="right"] .stop-content { grid-column: 3; text-align: left; }
|
||
|
||
.stop-content {
|
||
font-family: var(--type-body);
|
||
}
|
||
.stop-eyebrow {
|
||
font-size: var(--step-sm);
|
||
letter-spacing: 0.22em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-mute);
|
||
font-weight: 500;
|
||
display: block;
|
||
margin-bottom: 0.6rem;
|
||
}
|
||
.stop-title {
|
||
font-family: var(--type-display);
|
||
font-weight: 340;
|
||
font-size: clamp(2rem, 4.2vw, 3.2rem);
|
||
line-height: 1.04;
|
||
letter-spacing: -0.025em;
|
||
color: var(--ink);
|
||
margin: 0 0 clamp(0.6rem, 1.5vh, 1rem);
|
||
}
|
||
.stop-title em {
|
||
font-style: italic;
|
||
color: var(--accent);
|
||
font-weight: 400;
|
||
}
|
||
.stop-sub {
|
||
font-family: var(--type-display);
|
||
font-style: italic;
|
||
font-size: clamp(1.15rem, 1.8vw, 1.5rem);
|
||
font-weight: 300;
|
||
color: var(--ink-soft);
|
||
margin: 0 0 1.1rem;
|
||
letter-spacing: -0.005em;
|
||
line-height: 1.3;
|
||
}
|
||
.stop-body {
|
||
font-size: var(--step-md);
|
||
line-height: 1.55;
|
||
color: var(--ink-soft);
|
||
margin: 0;
|
||
max-width: 42ch;
|
||
font-weight: 400;
|
||
}
|
||
.stop-intro-text {
|
||
font-family: var(--type-display);
|
||
font-style: italic;
|
||
font-weight: 300;
|
||
font-size: clamp(1.4rem, 2.4vw, 2rem);
|
||
line-height: 1.35;
|
||
color: var(--ink-soft);
|
||
margin: 0;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
.stop-intro-text em {
|
||
font-style: normal;
|
||
color: var(--accent);
|
||
font-weight: 400;
|
||
}
|
||
|
||
.stop-image {
|
||
width: 100%;
|
||
max-width: 380px;
|
||
}
|
||
.stop-image img {
|
||
display: block;
|
||
width: 100%;
|
||
height: auto;
|
||
/* faint blend with the cream paper */
|
||
mix-blend-mode: multiply;
|
||
}
|
||
|
||
/* Initial hidden state — only when JS is enabled */
|
||
.js .map-stop .dot {
|
||
opacity: 0;
|
||
transform: scale(0.2);
|
||
transform-origin: center;
|
||
will-change: opacity, transform;
|
||
}
|
||
.js .map-stop .stop-content > *,
|
||
.js .map-stop .stop-image {
|
||
opacity: 0;
|
||
transform: translateY(28px);
|
||
will-change: opacity, transform;
|
||
}
|
||
|
||
/* ============================================================
|
||
SCENE 6 — PROJECT BIFROST · JOIN
|
||
A large call-to-action that, on click, crossfades to a
|
||
confirmation panel listing what happens next. Below, a
|
||
three-column footer row: "Project Bifrost" wordmark (left),
|
||
Fenja AI logo (centre), Innovationsfonden mark (right).
|
||
============================================================ */
|
||
#bifrost-join {
|
||
position: relative;
|
||
padding: clamp(5rem, 12vh, 10rem) var(--edge) clamp(2rem, 5vh, 3.5rem);
|
||
overflow: hidden;
|
||
min-height: 90vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* Stage holds BOTH the CTA and the confirmation panel, stacked in
|
||
the SAME grid cell. The cell auto-sizes to whichever panel is
|
||
taller (on mobile the confirmation list is much taller than the
|
||
CTA), so neither panel ever overflows into the footer. GSAP's
|
||
opacity/y tweens handle the crossfade. */
|
||
.join-stage {
|
||
position: relative;
|
||
flex: 1 1 auto;
|
||
max-width: 1100px;
|
||
margin: 0 auto;
|
||
width: 100%;
|
||
display: grid;
|
||
place-items: center;
|
||
padding: clamp(1rem, 4vh, 3rem) 0;
|
||
}
|
||
|
||
.join-panel {
|
||
grid-column: 1;
|
||
grid-row: 1;
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
text-align: center;
|
||
}
|
||
|
||
/* ---------- CTA state ---------- */
|
||
.join-cta .join-eyebrow {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
font-size: var(--step-sm);
|
||
letter-spacing: 0.32em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-mute);
|
||
margin-bottom: clamp(1.4rem, 3.5vh, 2rem);
|
||
font-weight: 500;
|
||
}
|
||
.join-cta .join-eyebrow::before,
|
||
.join-cta .join-eyebrow::after {
|
||
content: "";
|
||
width: 28px; height: 1px;
|
||
background: currentColor;
|
||
}
|
||
|
||
.join-cta .join-headline {
|
||
font-family: var(--type-display);
|
||
font-weight: 320;
|
||
font-size: clamp(2.4rem, 6.2vw, 5.4rem);
|
||
line-height: 1.04;
|
||
letter-spacing: -0.035em;
|
||
color: var(--ink);
|
||
margin: 0 auto clamp(2.6rem, 6vh, 4rem);
|
||
max-width: 20ch;
|
||
}
|
||
.join-cta .join-headline em {
|
||
font-style: italic;
|
||
background: linear-gradient(100deg, var(--aurora-1) 0%, var(--aurora-2) 32%, var(--aurora-3) 68%, var(--aurora-4) 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
font-weight: 340;
|
||
}
|
||
|
||
/* The button itself — pill shape with the terracotta accent */
|
||
.join-button {
|
||
font-family: var(--type-body);
|
||
font-size: clamp(1.02rem, 1.35vw, 1.18rem);
|
||
font-weight: 600;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--paper);
|
||
background: var(--accent);
|
||
border: none;
|
||
padding: clamp(1.1rem, 2.2vh, 1.45rem) clamp(2rem, 3.8vw, 2.8rem);
|
||
border-radius: 100px;
|
||
cursor: pointer;
|
||
position: relative;
|
||
overflow: hidden;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.85rem;
|
||
box-shadow: 0 14px 34px -14px rgba(164, 85, 59, 0.55),
|
||
0 4px 12px -4px rgba(46, 46, 40, 0.2);
|
||
transition: transform 0.25s cubic-bezier(0.2, 0.8, 0.2, 1),
|
||
box-shadow 0.25s ease,
|
||
background-color 0.25s ease;
|
||
}
|
||
.join-button:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 22px 44px -14px rgba(164, 85, 59, 0.65),
|
||
0 8px 18px -4px rgba(46, 46, 40, 0.25);
|
||
background: #b55e42;
|
||
}
|
||
.join-button:active {
|
||
transform: translateY(0);
|
||
}
|
||
.join-button:focus-visible {
|
||
outline: 2px solid var(--ring);
|
||
outline-offset: 4px;
|
||
}
|
||
.join-button:disabled {
|
||
cursor: default;
|
||
}
|
||
.join-button .arrow {
|
||
display: inline-block;
|
||
width: 18px; height: 1.5px;
|
||
background: currentColor;
|
||
position: relative;
|
||
transition: transform 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||
}
|
||
.join-button .arrow::after {
|
||
content: "";
|
||
position: absolute;
|
||
right: -1px; top: -4px;
|
||
width: 9px; height: 9px;
|
||
border-right: 1.5px solid currentColor;
|
||
border-bottom: 1.5px solid currentColor;
|
||
transform: rotate(-45deg);
|
||
}
|
||
.join-button:hover .arrow {
|
||
transform: translateX(4px);
|
||
}
|
||
|
||
.join-cta .join-subtext {
|
||
margin: clamp(1.6rem, 4vh, 2.4rem) auto 0;
|
||
font-size: var(--step-sm);
|
||
color: var(--ink-mute);
|
||
letter-spacing: 0.04em;
|
||
max-width: 40ch;
|
||
}
|
||
|
||
/* ---------- Confirmation state ---------- */
|
||
.join-confirmation {
|
||
pointer-events: none; /* enabled by JS after fade-in completes */
|
||
}
|
||
.join-confirmation .confirm-eyebrow {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
font-size: var(--step-sm);
|
||
letter-spacing: 0.32em;
|
||
text-transform: uppercase;
|
||
color: var(--accent);
|
||
margin-bottom: clamp(1.4rem, 3vh, 1.8rem);
|
||
font-weight: 500;
|
||
}
|
||
.join-confirmation .confirm-eyebrow::before,
|
||
.join-confirmation .confirm-eyebrow::after {
|
||
content: "";
|
||
width: 22px; height: 1px;
|
||
background: currentColor;
|
||
opacity: 0.7;
|
||
}
|
||
.join-confirmation .confirm-headline {
|
||
font-family: var(--type-display);
|
||
/* Matched to .join-cta .join-headline so pressing the CTA doesn't
|
||
shrink the page's visual anchor — the confirmation keeps the
|
||
same stature, only the copy changes. */
|
||
font-weight: 320;
|
||
font-size: clamp(2.4rem, 6.2vw, 5.4rem);
|
||
line-height: 1.04;
|
||
letter-spacing: -0.035em;
|
||
color: var(--ink);
|
||
margin: 0 auto;
|
||
max-width: 20ch;
|
||
}
|
||
.join-confirmation .confirm-headline em {
|
||
/* Italics preserved for emphasis; accent colour keeps the editorial
|
||
weight without the aurora gradient (which is reserved for S4
|
||
and the pre-click CTA). */
|
||
font-style: italic;
|
||
color: var(--accent);
|
||
font-weight: 380;
|
||
}
|
||
|
||
.confirm-list {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: clamp(2rem, 5vh, 3.2rem) auto 0;
|
||
max-width: 62ch;
|
||
text-align: left;
|
||
}
|
||
.confirm-list li {
|
||
padding: clamp(1rem, 2.2vh, 1.4rem) 0 clamp(1rem, 2.2vh, 1.4rem) clamp(2.6rem, 4vw, 3.2rem);
|
||
position: relative;
|
||
font-size: var(--step-md);
|
||
line-height: 1.55;
|
||
color: var(--ink-soft);
|
||
border-top: 1px solid rgba(46, 46, 40, 0.12);
|
||
}
|
||
.confirm-list li:first-child { border-top: none; }
|
||
.confirm-list li em {
|
||
font-family: var(--type-display);
|
||
font-style: italic;
|
||
font-weight: 400;
|
||
color: var(--ink);
|
||
}
|
||
/* Terracotta circle marker + cream check — staged with a CSS
|
||
transition that fires when JS adds `.is-checked` to each <li>. */
|
||
.confirm-list li::before {
|
||
content: "";
|
||
position: absolute;
|
||
left: 0;
|
||
top: clamp(0.95rem, 2.2vh, 1.35rem);
|
||
width: clamp(1.4rem, 2.3vw, 1.7rem);
|
||
height: clamp(1.4rem, 2.3vw, 1.7rem);
|
||
background: var(--accent);
|
||
border-radius: 50%;
|
||
opacity: 0;
|
||
transform: scale(0.4);
|
||
transition: opacity 0.35s ease,
|
||
transform 0.4s cubic-bezier(0.3, 1.5, 0.5, 1);
|
||
}
|
||
.confirm-list li::after {
|
||
content: "";
|
||
position: absolute;
|
||
left: clamp(0.42rem, 0.7vw, 0.55rem);
|
||
top: clamp(1.5rem, 3vh, 1.95rem);
|
||
width: clamp(0.58rem, 0.9vw, 0.72rem);
|
||
height: clamp(0.3rem, 0.5vw, 0.38rem);
|
||
border-left: 2px solid var(--paper);
|
||
border-bottom: 2px solid var(--paper);
|
||
transform: rotate(-45deg) scale(0.4);
|
||
transform-origin: center;
|
||
opacity: 0;
|
||
transition: opacity 0.3s ease 0.15s,
|
||
transform 0.3s cubic-bezier(0.3, 1.5, 0.5, 1) 0.15s;
|
||
}
|
||
.confirm-list li.is-checked::before {
|
||
opacity: 1;
|
||
transform: scale(1);
|
||
}
|
||
.confirm-list li.is-checked::after {
|
||
opacity: 1;
|
||
transform: rotate(-45deg) scale(1);
|
||
}
|
||
|
||
/* ---------- Footer row (three brand marks, equal weight) ---------- */
|
||
.join-footer {
|
||
margin-top: auto;
|
||
padding-top: clamp(2.5rem, 6vh, 4rem);
|
||
/* Generous bottom padding — the dot-nav sits 36px from the bottom of
|
||
the viewport, plus its own hit area; logos need clear room below
|
||
them. Without this, the rightmost footer items can appear to slide
|
||
under the nav on short viewports. */
|
||
padding-bottom: clamp(5rem, 10vh, 8rem);
|
||
border-top: 1px solid rgba(46, 46, 40, 0.1);
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr;
|
||
align-items: center;
|
||
gap: clamp(1rem, 3vw, 3rem);
|
||
max-width: 1200px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
width: 100%;
|
||
/* Single source of truth for how tall each footer item should be.
|
||
All three items are sized against this — the Fenja SVG fills it,
|
||
the Innovationsfonden mark scales its icon and text against it,
|
||
and the "Project Bifrost" text picks a font-size from it. */
|
||
--foot-h: clamp(34px, 4.4vh, 52px);
|
||
}
|
||
.join-footer > * {
|
||
height: var(--foot-h);
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
/* Left: "Project Bifrost" in Newsreader, italic accent on Bifrost */
|
||
.join-footer .foot-project {
|
||
justify-self: start;
|
||
font-family: var(--type-display);
|
||
font-weight: 340;
|
||
font-size: calc(var(--foot-h) * 0.54);
|
||
letter-spacing: -0.01em;
|
||
color: var(--ink);
|
||
white-space: nowrap;
|
||
line-height: 1;
|
||
}
|
||
.join-footer .foot-project em {
|
||
font-style: italic;
|
||
color: var(--accent);
|
||
font-weight: 360;
|
||
margin-left: 0.2em;
|
||
}
|
||
|
||
/* Centre: the Fenja AI SVG logo.
|
||
Same height target (--foot-h) as the "Project Bifrost" wordmark on
|
||
the left and the Innovationsfonden mark on the right, so all three
|
||
read as equal-weight brand marks. */
|
||
.join-footer .foot-fenja {
|
||
justify-self: center;
|
||
}
|
||
.join-footer .foot-fenja img,
|
||
.join-footer .foot-fenja svg {
|
||
height: 100%;
|
||
width: auto;
|
||
display: block;
|
||
}
|
||
|
||
/* Right: Innovationsfonden — hybrid of a small SVG slanted "I" mark
|
||
plus HTML text. Using HTML text instead of SVG <text> avoids
|
||
text-metric overflow clipping at the section's right edge. */
|
||
.join-footer .foot-innov {
|
||
justify-self: end;
|
||
gap: calc(var(--foot-h) * 0.12);
|
||
color: #0e3a48;
|
||
font-family: var(--type-body);
|
||
font-weight: 700;
|
||
font-size: calc(var(--foot-h) * 0.46);
|
||
letter-spacing: -0.015em;
|
||
line-height: 1;
|
||
white-space: nowrap;
|
||
}
|
||
.join-footer .foot-innov .innov-mark {
|
||
height: calc(var(--foot-h) * 0.88);
|
||
width: auto;
|
||
display: block;
|
||
fill: currentColor;
|
||
}
|
||
|
||
/* Hidden initial states when JS enabled (scroll-triggered reveals) */
|
||
.js .join-cta,
|
||
.js .join-confirmation,
|
||
.js .join-footer > * {
|
||
opacity: 0;
|
||
transform: translateY(22px);
|
||
will-change: opacity, transform;
|
||
}
|
||
|
||
/* ============================================================
|
||
RESPONSIVE — additions for the new sections
|
||
(independent of the existing @media block above)
|
||
============================================================ */
|
||
@media (max-width: 900px) {
|
||
/* Treasure map collapses to a centred vertical timeline */
|
||
.map-stop,
|
||
.map-stop--intro {
|
||
grid-template-columns: 1fr;
|
||
text-align: center;
|
||
margin-bottom: clamp(4.5rem, 10vh, 7rem);
|
||
gap: clamp(1.2rem, 3vw, 2rem);
|
||
justify-items: center;
|
||
}
|
||
.map-stop .dot-anchor {
|
||
grid-column: 1 !important;
|
||
margin: 0 auto;
|
||
order: 1;
|
||
}
|
||
.map-stop .stop-image {
|
||
grid-column: 1 !important;
|
||
justify-self: center !important;
|
||
max-width: 280px;
|
||
margin: 0 auto;
|
||
order: 2;
|
||
/* Paper-coloured backdrop hides the centred rail behind the
|
||
illustration on mobile. The illustration uses multiply blend
|
||
which then composites against this paper colour (same as the
|
||
page background) — visually unchanged, but no rail bleed. */
|
||
background: var(--paper);
|
||
}
|
||
.map-stop .stop-content {
|
||
grid-column: 1 !important;
|
||
text-align: center !important;
|
||
order: 3;
|
||
/* Same trick for the text block — keeps the rail from showing
|
||
through inter-line spacing. Generous vertical padding so the
|
||
rail "ducks under" the whole text region cleanly. */
|
||
background: var(--paper);
|
||
padding: 0.75rem 0.5rem;
|
||
max-width: 90%;
|
||
}
|
||
.stop-body {
|
||
max-width: 42ch;
|
||
margin: 0 auto !important;
|
||
}
|
||
/* Same backdrop for the intro paragraph */
|
||
.map-stop--intro .stop-content {
|
||
background: var(--paper);
|
||
padding: 0.75rem 1rem;
|
||
}
|
||
/* Dot already has a paper-coloured ring (box-shadow) so the
|
||
rail doesn't show through it — no extra work needed there. */
|
||
|
||
/* Replace the curving SVG path with a clean vertical rail */
|
||
.map-path { display: none; }
|
||
.map-canvas::before {
|
||
content: "";
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 0;
|
||
bottom: 0;
|
||
width: 1px;
|
||
background: rgba(46, 46, 40, 0.18);
|
||
transform: translateX(-50%);
|
||
z-index: 0;
|
||
}
|
||
.map-canvas::after {
|
||
/* the "drawn" overlay rail in accent — height set by JS */
|
||
content: "";
|
||
position: absolute;
|
||
left: 50%;
|
||
top: 0;
|
||
width: 1.5px;
|
||
height: var(--rail-progress, 0%);
|
||
background: var(--accent);
|
||
opacity: 0.7;
|
||
transform: translateX(-50%);
|
||
z-index: 1;
|
||
transition: none;
|
||
}
|
||
|
||
/* Join footer stacks vertically on mobile, each mark centred */
|
||
.join-footer {
|
||
grid-template-columns: 1fr;
|
||
gap: clamp(1.8rem, 4vh, 2.4rem);
|
||
justify-items: center;
|
||
text-align: center;
|
||
}
|
||
.join-footer > * {
|
||
justify-self: center !important;
|
||
}
|
||
|
||
/* CTA headline + button tighter on phones */
|
||
.join-cta .join-headline {
|
||
font-size: clamp(2rem, 7vw, 3rem);
|
||
}
|
||
.confirm-list {
|
||
max-width: 100%;
|
||
padding: 0 0.25rem;
|
||
}
|
||
#bifrost-join {
|
||
min-height: auto;
|
||
padding: clamp(4rem, 10vh, 7rem) var(--edge) clamp(2rem, 4vh, 3rem);
|
||
}
|
||
.join-stage {
|
||
/* Mobile content (esp. confirmation with 4 wrapping bullets) is
|
||
taller than on desktop; size for the tallest panel so neither
|
||
one overflows into the footer below. */
|
||
min-height: clamp(560px, 82vh, 720px);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 520px) {
|
||
.stop-title { font-size: clamp(1.6rem, 7vw, 2.2rem); }
|
||
.stop-sub { font-size: 1.05rem; }
|
||
.stop-intro-text { font-size: clamp(1.1rem, 4.5vw, 1.4rem); }
|
||
}
|
||
|
||
/* Reduced motion — show everything statically */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.map-stop .dot,
|
||
.map-stop .stop-content > *,
|
||
.map-stop .stop-image,
|
||
.join-cta,
|
||
.join-confirmation,
|
||
.join-footer > *,
|
||
.confirm-list li::before,
|
||
.confirm-list li::after {
|
||
opacity: 1 !important;
|
||
transform: none !important;
|
||
}
|
||
.map-path .path-draw { stroke-dashoffset: 0 !important; }
|
||
.map-canvas::after { height: 100% !important; }
|
||
}
|
||
|
||
/* Bind illustration custom properties to the rendered surfaces.
|
||
Each surface uses background-image so the underlying base64 data
|
||
stays defined once in :root. */
|
||
.stop-illust {
|
||
width: 100%;
|
||
aspect-ratio: 1 / 1;
|
||
background-repeat: no-repeat;
|
||
background-position: center;
|
||
background-size: contain;
|
||
mix-blend-mode: multiply;
|
||
}
|
||
.stop-illust[data-illust="community"] { background-image: var(--illust-community); }
|
||
.stop-illust[data-illust="council"] { background-image: var(--illust-council); }
|
||
.stop-illust[data-illust="pilot"] { background-image: var(--illust-pilot); }
|
||
|
||
|
||
</style>
|
||
</head>
|
||
<body data-screen-label="01 Timeline">
|
||
|
||
<a class="site-mark" href="/" aria-label="Back to the front page">
|
||
<img src="/fenja/fenja-wordmark-black.svg" alt="Fenja" />
|
||
</a>
|
||
|
||
<!-- ───── Page 1 : TIMELINE ───── -->
|
||
<section class="page page-timeline is-active" id="page-timeline" data-screen-label="01 Timeline">
|
||
<div class="page-title">When AI runs Europe, who runs the <em>AI?</em></div>
|
||
<div class="page-sub">
|
||
We’ve spent years building data and AI across Denmark and Europe, watching one dependency harden after another. AI is different. The United States has made that clear. China has made that clear. You cannot stand strong in this century on AI you do not control — and for the first time in a generation, Europe has both the reason and the moment to build its own. The window is closing faster than most realise. It is open now. It will not be open long.<br/><br/>
|
||
<span class="page-sub-accent">As AI moves into our hospitals, our laboratories, our boardrooms, our regulated workflows — into the data and the intellectual property our organisations have spent decades protecting — can we afford for the switch to sit in <em>Washington?</em></span>
|
||
</div>
|
||
|
||
<!-- Globe ghost -->
|
||
<div class="globe-wrap" id="globe-wrap"></div>
|
||
|
||
<!-- Continue to the next page -->
|
||
<button class="continue-btn" id="continue-btn" type="button">
|
||
<span class="c-icon" aria-hidden="true">
|
||
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.4">
|
||
<circle cx="24" cy="24" r="22.5"/>
|
||
<path d="M16 24 H32 M26 17.5 L32.5 24 L26 30.5"
|
||
stroke-linecap="round" stroke-linejoin="round"/>
|
||
</svg>
|
||
</span>
|
||
<span class="c-label">How Fenja AI <em>addresses</em> this</span>
|
||
</button>
|
||
|
||
<div class="timeline-viewport" id="tl-viewport">
|
||
<div class="timeline-track" id="tl-track">
|
||
<div class="spine" id="spine"></div>
|
||
<!-- Year ticks and events injected by JS -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- First-load scroll hint. Vertically centered on the right edge;
|
||
fades out the moment the reader starts scrolling the timeline
|
||
(piggybacks on `.is-scrolled`, set in timeline.js after ~40px
|
||
of scroll travel). -->
|
||
<div class="timeline-scroll-hint" aria-hidden="true">
|
||
<span class="ts-label">Scroll to begin</span>
|
||
<svg class="ts-arrow" viewBox="0 0 56 14" fill="none"
|
||
stroke="currentColor" stroke-width="1.6"
|
||
stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M2 7 H50"/>
|
||
<path d="M44 2 L50 7 L44 12"/>
|
||
</svg>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ───── Page 2 : OVERVIEW ───── -->
|
||
<section class="page page-overview" id="page-overview" data-screen-label="02 Overview">
|
||
<!-- Topography background — concentric rings, parallax-scrolling behind
|
||
the Europe map. Drawn at runtime by bifrost.js's drawTopography()
|
||
into the SVG slot. Lives at z-index 0 so it sits behind the map
|
||
(z-index 1) and all content (z-index 2+). -->
|
||
<div class="overview-topography" id="overview-topography" aria-hidden="true"></div>
|
||
<div class="overview-globe" id="overview-globe"></div>
|
||
|
||
<!-- Internal scroller: the six Project Bifrost scenes live inside this.
|
||
Lenis and ScrollTrigger are wired to this element, not the window. -->
|
||
<div id="overview-scroll">
|
||
|
||
<!-- ============================================================
|
||
SCENE 1 — HERO
|
||
============================================================ -->
|
||
<section id="hero" class="scene" aria-labelledby="hero-title">
|
||
<div class="hero-wrap">
|
||
<!-- Left column: headline + lede + foot row. The right column
|
||
(.hero-mark) holds the Fenja wordmark, mirroring the
|
||
welcome page's right-side lockup. No eyebrow here — the
|
||
headline + logo pairing is enough to anchor the scene. -->
|
||
<div class="hero-copy">
|
||
<h1 id="hero-title" class="hero-title" data-reveal-lines>
|
||
Trusted & <em>Sovereign AI</em><br/>
|
||
built in Denmark, for <em>Europe.</em>
|
||
</h1>
|
||
<p class="hero-lede" data-reveal>
|
||
Fenja AI is both our company and our platform — one mission, one name. An entirely client-managed AI platform built in Denmark, so Danish and European organisations can take full control of their own AI.
|
||
</p>
|
||
|
||
<!-- Hero foot: "Backed by Innovationsfonden" on the left and
|
||
the scroll-down indicator on the right, both inside the
|
||
left column at the bottom of the paragraph block. Shared
|
||
baseline via display:flex + align-items:baseline on
|
||
.hero-foot. The scroll arrow points DOWN and gently bounces
|
||
downward (see @keyframes hint below). -->
|
||
<div class="hero-foot">
|
||
<div class="support-stack" data-reveal>
|
||
<div class="support" aria-label="Backed by Innovationsfonden">
|
||
<span>Backed by</span>
|
||
<!-- Simplified Innovationsfonden wordmark (redrawn — not their official logo, a respectful representation) -->
|
||
<svg viewBox="0 0 190 20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||
<g fill="#3c6b6b">
|
||
<path d="M4 2 L12 18 L10 2 Z" />
|
||
<text x="18" y="15" font-family="Manrope, sans-serif" font-weight="600" font-size="13" letter-spacing="0.2" fill="#3c6b6b">nnovationsfonden</text>
|
||
</g>
|
||
</svg>
|
||
</div>
|
||
<div class="support-bii">Part of BioInnovation Institute AI Lab</div>
|
||
</div>
|
||
<div class="scroll-hint" aria-hidden="true" data-reveal>
|
||
<span>Scroll</span>
|
||
<span class="arrow"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Right column: the Fenja wordmark, anchored to the right
|
||
half of the viewport — same placement the welcome page
|
||
uses for its .welcome-logo. Decorative; the <h1> above
|
||
is still the semantic heading. -->
|
||
<div class="hero-mark" aria-hidden="true" data-reveal>
|
||
<img src="/fenja/fenja-wordmark-black.svg" alt="" />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============================================================
|
||
SCENE 4 — PROJECT BIFROST REVEAL
|
||
============================================================ -->
|
||
<section id="bifrost" aria-labelledby="bifrost-head">
|
||
<div class="bifrost-pin">
|
||
<div class="bifrost-stage">
|
||
|
||
<!-- The bridge arc. Uses a restrained aurora gradient — the ONLY
|
||
place colour appears in the entire site. Norse mythology:
|
||
Bifrost is the bridge between worlds, rendered here as a
|
||
single luminous arc spanning the stage. -->
|
||
<div class="arc-wrap" aria-hidden="true">
|
||
<svg viewBox="0 0 1400 500" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<linearGradient id="auroraGrad" x1="0" x2="1" y1="0" y2="0">
|
||
<stop offset="0%" stop-color="#b48755" stop-opacity="0"/>
|
||
<stop offset="15%" stop-color="#b48755" stop-opacity="0.95"/>
|
||
<stop offset="40%" stop-color="#a4553b" stop-opacity="0.95"/>
|
||
<stop offset="65%" stop-color="#5c7b8e" stop-opacity="0.95"/>
|
||
<stop offset="85%" stop-color="#6e5a86" stop-opacity="0.95"/>
|
||
<stop offset="100%" stop-color="#6e5a86" stop-opacity="0"/>
|
||
</linearGradient>
|
||
<linearGradient id="auroraGradSoft" x1="0" x2="1" y1="0" y2="0">
|
||
<stop offset="0%" stop-color="#b48755" stop-opacity="0"/>
|
||
<stop offset="15%" stop-color="#b48755" stop-opacity="0.35"/>
|
||
<stop offset="40%" stop-color="#a4553b" stop-opacity="0.35"/>
|
||
<stop offset="65%" stop-color="#5c7b8e" stop-opacity="0.35"/>
|
||
<stop offset="85%" stop-color="#6e5a86" stop-opacity="0.35"/>
|
||
<stop offset="100%" stop-color="#6e5a86" stop-opacity="0"/>
|
||
</linearGradient>
|
||
<filter id="softGlow" x="-20%" y="-50%" width="140%" height="200%">
|
||
<feGaussianBlur stdDeviation="8"/>
|
||
</filter>
|
||
</defs>
|
||
|
||
<!-- soft halo -->
|
||
<path id="arcHalo" d="M 60 420 Q 700 -40 1340 420"
|
||
fill="none"
|
||
stroke="url(#auroraGradSoft)"
|
||
stroke-width="24"
|
||
stroke-linecap="round"
|
||
filter="url(#softGlow)"/>
|
||
|
||
<!-- main arc -->
|
||
<path id="arcMain" d="M 60 420 Q 700 -40 1340 420"
|
||
fill="none"
|
||
stroke="url(#auroraGrad)"
|
||
stroke-width="3"
|
||
stroke-linecap="round"/>
|
||
|
||
<!-- secondary thin highlight arc -->
|
||
<path id="arcThin" d="M 80 420 Q 700 -20 1320 420"
|
||
fill="none"
|
||
stroke="url(#auroraGrad)"
|
||
stroke-width="1"
|
||
stroke-linecap="round"
|
||
opacity="0.6"/>
|
||
</svg>
|
||
</div>
|
||
|
||
<div class="bifrost-text">
|
||
<div class="bifrost-eyebrow">Introducing</div>
|
||
<h2 id="bifrost-head" class="bifrost-name">
|
||
<span class="token">Project</span>
|
||
<span class="token accent">Bifrost</span>
|
||
</h2>
|
||
<p class="bifrost-sub">
|
||
The bridge <em>between</em> an industrial-grade AI platform and the realities of regulated organisations — built <em>with</em> them, not just for them.
|
||
</p>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============================================================
|
||
SCENE 5 — PROJECT BIFROST · WHAT IT MEANS
|
||
A treasure-map of participation: an intro stop and three
|
||
component stops revealed sequentially as the user scrolls
|
||
a meandering ink path down the page.
|
||
============================================================ -->
|
||
<section id="bifrost-meaning" aria-labelledby="bifrost-meaning-head">
|
||
<div class="map-intro">
|
||
<span class="map-eyebrow">The invitation</span>
|
||
<h2 id="bifrost-meaning-head" class="map-title">
|
||
What being part of <em>Project Bifrost</em> means
|
||
</h2>
|
||
<p class="map-lede">
|
||
Three ways to <em>shape</em>, to <em>influence</em>, and to <em>build with</em> the platform from the inside — a journey through what participation actually looks like.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="map-canvas">
|
||
|
||
<!-- Wandering path. Stretched to fill the canvas via
|
||
preserveAspectRatio="none". The accent overlay is drawn
|
||
as the user scrolls down through the stops. -->
|
||
<svg class="map-path" viewBox="0 0 100 200" preserveAspectRatio="none" aria-hidden="true">
|
||
<!-- The d attributes are computed at runtime by buildMapPath()
|
||
based on the rendered Y positions of the dots, so the path
|
||
always passes through them regardless of content height.
|
||
The placeholder values below are valid fallback geometry
|
||
that ships if JS fails. -->
|
||
<path id="mapPathBg" class="path-bg"
|
||
vector-effect="non-scaling-stroke"
|
||
d="M 50 6 C 72 28, 72 52, 50 70 C 28 88, 28 112, 50 130 C 72 148, 72 172, 50 194"/>
|
||
<path id="mapPathDraw" class="path-draw"
|
||
vector-effect="non-scaling-stroke"
|
||
d="M 50 6 C 72 28, 72 52, 50 70 C 28 88, 28 112, 50 130 C 72 148, 72 172, 50 194"/>
|
||
</svg>
|
||
|
||
<!-- INTRO STOP -->
|
||
<article class="map-stop map-stop--intro" data-stop="0">
|
||
<div class="dot-anchor"><span class="dot"></span></div>
|
||
<div class="stop-content">
|
||
<p class="stop-intro-text">
|
||
Being part of <em>Project Bifrost</em> means <em>three</em> things — a community to shape the future with, a council to influence the platform through, and pilot projects that put it in your hands first.
|
||
</p>
|
||
</div>
|
||
</article>
|
||
|
||
<!-- STOP 1 — Community (text on left, image on right) -->
|
||
<article class="map-stop" data-stop="1" data-side="left" aria-labelledby="stop-1-title">
|
||
<div class="stop-content">
|
||
<span class="stop-eyebrow">Be part of a</span>
|
||
<h3 id="stop-1-title" class="stop-title"><em>Community</em></h3>
|
||
<p class="stop-sub">Shape the future together</p>
|
||
<p class="stop-body">Join a select community of organisations helping define the future of trusted sovereign AI in Denmark and Europe. At a time when Europe needs greater technological independence, this is an opportunity to contribute to an AI platform built on trust, shared ambition, and a common mission.</p>
|
||
</div>
|
||
<div class="dot-anchor"><span class="dot"></span></div>
|
||
<div class="stop-image">
|
||
<div class="stop-illust" data-illust="community" role="img" aria-label="Six people in discussion around a table"></div>
|
||
</div>
|
||
</article>
|
||
|
||
<!-- STOP 2 — Advisory Council (image on left, text on right) -->
|
||
<article class="map-stop" data-stop="2" data-side="right" aria-labelledby="stop-2-title">
|
||
<div class="stop-image">
|
||
<div class="stop-illust" data-illust="council" role="img" aria-label="A man and a woman in conversation"></div>
|
||
</div>
|
||
<div class="dot-anchor"><span class="dot"></span></div>
|
||
<div class="stop-content">
|
||
<span class="stop-eyebrow">Be part of an</span>
|
||
<h3 id="stop-2-title" class="stop-title"><em>Advisory Council</em></h3>
|
||
<p class="stop-sub">Turn insight into influence</p>
|
||
<p class="stop-body">Take part in regular advisory council sessions where your input directly shapes the product and platform roadmap. Gain first-hand insight into cutting-edge AI developments and help influence what is built, which capabilities are prioritised, and how the platform evolves to meet real organisational needs.</p>
|
||
</div>
|
||
</article>
|
||
|
||
<!-- STOP 3 — Pilot Projects (text on left, image on right) -->
|
||
<article class="map-stop" data-stop="3" data-side="left" aria-labelledby="stop-3-title">
|
||
<div class="stop-content">
|
||
<span class="stop-eyebrow">Be part of</span>
|
||
<h3 id="stop-3-title" class="stop-title"><em>Pilot Projects</em></h3>
|
||
<p class="stop-sub">Access the platform before others</p>
|
||
<p class="stop-body">A select number of Project Bifrost participants will have the opportunity to join pilot projects and gain early access to the platform at a significantly reduced price, subsidised by the Innovation Fund. This gives your organisation the chance to explore cutting-edge sovereign AI early, realise value at low cost, and help shape the platform through real-world use.</p>
|
||
</div>
|
||
<div class="dot-anchor"><span class="dot"></span></div>
|
||
<div class="stop-image">
|
||
<div class="stop-illust" data-illust="pilot" role="img" aria-label="Two people working together at a computer"></div>
|
||
</div>
|
||
</article>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============================================================
|
||
ARCHITECTURE — Fenja AI Platform, simply explained
|
||
Inlined from the former standalone /deepdive page so the
|
||
reader can scroll straight from Project Bifrost into the
|
||
architecture explainer. Same DOM as deepdive.html's three
|
||
sections; same /platform.css. platform.js detects that it's
|
||
running inside #overview-scroll and skips its own Lenis
|
||
setup (bifrost.js owns that here).
|
||
============================================================ -->
|
||
<section id="platform-question" aria-labelledby="platform-question-head">
|
||
<div class="pq-wrap">
|
||
<h2 id="platform-question-head" class="pq-title">
|
||
Renting a few AI capabilities from American companies isn't enough.<br>
|
||
Installing an open-source language model isn't enough.
|
||
</h2>
|
||
<p class="pq-body">
|
||
You need a <em>platform you control</em> — with the
|
||
tools, the knowledge, and the framework to make AI
|
||
actually do the work your organization needs done.
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="platform-layers" aria-labelledby="platform-layers-head">
|
||
<h2 id="platform-layers-head" class="sr-only" style="position:absolute;left:-9999px;">The Fenja architecture, layer by layer</h2>
|
||
<div class="pl-pin">
|
||
|
||
<header class="pl-pin-header">
|
||
<p class="pl-pin-title">Fenja AI Platform Architecture</p>
|
||
<p class="pl-pin-subtitle">Simply Explained</p>
|
||
</header>
|
||
|
||
<div class="pl-pin-body">
|
||
|
||
<div class="pl-copy-stage" aria-live="polite">
|
||
|
||
<div class="pl-copy-step" data-beat="1">
|
||
<p class="pl-eyebrow">The foundation</p>
|
||
<h3 class="pl-headline"><em>A model in your environment.</em></h3>
|
||
<p class="pl-body">
|
||
A state-of-the-art open-source language model, running
|
||
entirely on your hardware. No data leaves your
|
||
perimeter. The starting point — but not yet
|
||
Fenja.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="pl-copy-step" data-beat="2">
|
||
<p class="pl-eyebrow">The foundation</p>
|
||
<h3 class="pl-headline"><em>Knowledge.</em></h3>
|
||
<p class="pl-body">
|
||
What makes the model <em>Fenja</em> — an
|
||
understanding of your organization, captured in a wiki
|
||
your team can read and edit. Plus the routines and
|
||
working memory that turn Fenja into a coworker who
|
||
knows how things get done.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="pl-copy-step" data-beat="3">
|
||
<p class="pl-eyebrow">What Fenja can do</p>
|
||
<h3 class="pl-headline"><em>Tools.</em></h3>
|
||
<p class="pl-body">
|
||
How knowledge becomes work. Fenja uses tools to find
|
||
documents, query data, take action across your
|
||
systems. Some are obvious; others depend on what your
|
||
work needs.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="pl-copy-step" data-beat="4">
|
||
<p class="pl-eyebrow">When one becomes a team</p>
|
||
<h3 class="pl-headline"><em>Agents.</em></h3>
|
||
<p class="pl-body">
|
||
Real work isn't one task. Fenja becomes a team
|
||
— a supervisor and specialists, each focused,
|
||
each governed, all dispatched by workflows you've
|
||
designed.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="pl-copy-step" data-beat="5">
|
||
<p class="pl-eyebrow">The full picture</p>
|
||
<h3 class="pl-headline"><em>Everything you need and with full control.</em></h3>
|
||
<p class="pl-body">
|
||
Fenja brings together all the pieces to solve simple
|
||
and complex AI use cases across your organisation.
|
||
Every component hosted in your infrastructure with
|
||
full traceability and governance. Secure and sovereign
|
||
by design.
|
||
</p>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="pl-canvas-wrap">
|
||
<div class="pl-canvas">
|
||
|
||
<div class="pl-canvas-frame" aria-hidden="true">
|
||
<span class="pl-canvas-frame-label">Everything Client-Managed</span>
|
||
</div>
|
||
|
||
<section class="pl-group" data-layer="foundation" aria-hidden="true">
|
||
<header class="pl-group-head">
|
||
<span class="pl-group-label">Foundation</span>
|
||
<span class="pl-group-caption">Sovereign by design</span>
|
||
</header>
|
||
<div class="pl-cards pl-cards--3 pl-cards--stretch">
|
||
<article class="pl-card" data-card="lm">
|
||
<h4 class="pl-card-name">Language model</h4>
|
||
<p class="pl-card-italic">State-of-the-art, open-source</p>
|
||
<p class="pl-card-mono">On-prem</p>
|
||
</article>
|
||
<article class="pl-card" data-card="wiki">
|
||
<h4 class="pl-card-name">Wiki</h4>
|
||
<p class="pl-card-italic">Company and domain knowledge</p>
|
||
<p class="pl-card-mono">Organizational · Departmental · Personal</p>
|
||
</article>
|
||
<article class="pl-card" data-card="routines">
|
||
<h4 class="pl-card-name">Routines & memory</h4>
|
||
<p class="pl-card-italic">How Fenja works inside it</p>
|
||
<p class="pl-card-mono">Stand-ups · Recurring tasks · Working memory</p>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="pl-group" data-layer="tools" aria-hidden="true">
|
||
<header class="pl-group-head">
|
||
<span class="pl-group-label">Tools</span>
|
||
<span class="pl-group-caption">How Fenja acts</span>
|
||
</header>
|
||
<div class="pl-cards pl-cards--4 pl-cards--stretch">
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Document retrieval</h4>
|
||
<p class="pl-card-italic">Find and cite</p>
|
||
<p class="pl-card-mono">RAG</p>
|
||
</article>
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Structured data (ie SQL)</h4>
|
||
<p class="pl-card-italic">Query and extract</p>
|
||
<p class="pl-card-mono">NL → SQL</p>
|
||
</article>
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">System actions</h4>
|
||
<p class="pl-card-italic">Read and write</p>
|
||
<p class="pl-card-mono">APIs · integrations</p>
|
||
</article>
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Custom tools</h4>
|
||
<p class="pl-card-italic">Your specific work</p>
|
||
<p class="pl-card-mono">Defined by you</p>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="pl-group" data-layer="agents" aria-hidden="true">
|
||
<header class="pl-group-head">
|
||
<span class="pl-group-label">Agents</span>
|
||
<span class="pl-group-caption">How Fenja scales</span>
|
||
</header>
|
||
<div class="pl-cards pl-cards--4 pl-cards--stretch">
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Supervisor</h4>
|
||
<p class="pl-card-italic">Plan and dispatch</p>
|
||
<p class="pl-card-mono">Orchestration</p>
|
||
</article>
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Specialists</h4>
|
||
<p class="pl-card-italic">Focused expertise</p>
|
||
<p class="pl-card-mono">Subagents</p>
|
||
</article>
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Skills</h4>
|
||
<p class="pl-card-italic">Reusable capability</p>
|
||
<p class="pl-card-mono">Portable across specialists</p>
|
||
</article>
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Workflows</h4>
|
||
<p class="pl-card-italic">Composed by you</p>
|
||
<p class="pl-card-mono">Governed end-to-end</p>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /.pl-pin-body -->
|
||
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============================================================
|
||
WIKI DEEP-DIVE — from scattered knowledge to one structured
|
||
source of truth. Pinned scrubbed five-beat section,
|
||
mirroring #platform-layers's structure (.pl-pin shell,
|
||
pl-pin-header for title, then a body of three columns).
|
||
|
||
Beats:
|
||
0 Anchor — the Wiki pl-card from the architecture grid
|
||
scales up to centre as the section enters.
|
||
1 Left — "Scattered knowledge". Document and tacit-
|
||
knowledge icons reveal in a jittered cluster.
|
||
2 Middle — "Fenja AI Compiler". Compiler block fades in
|
||
and three flow lines draw from the scatter into it.
|
||
3 Right — "Fenja Wiki" mock (nav + article + citations).
|
||
Three flow lines draw from the compiler into it; the
|
||
article's inline <sup> citation markers fade in.
|
||
4 Trust — citation [1] lights up in walnut, a faint arc
|
||
traces back to a specific document on the left. Light
|
||
touch; rewards attention.
|
||
|
||
Content invariants — do not soften:
|
||
• Only the brand name "Fenja Wiki" is used. No generic
|
||
encyclopedia-style brand names are referenced anywhere
|
||
(copy, alt text, filenames, or this comment).
|
||
• Fenja Wiki is described as the *default* structured
|
||
output — other outputs are possible (sub-caption).
|
||
• Left side stays visually chaotic, right side stays
|
||
calm. The contrast is the storytelling point.
|
||
• The Compiler is the only element earning the walnut
|
||
accent. Left is muted; right is neutral except for
|
||
citation markers (also walnut, threading the trust
|
||
story to the only other accent on the slide).
|
||
============================================================ -->
|
||
<section id="wiki-deepdive" aria-labelledby="wiki-deepdive-head">
|
||
<h2 id="wiki-deepdive-head" class="sr-only" style="position:absolute;left:-9999px;">
|
||
Wiki — from scattered knowledge to one structured source of truth
|
||
</h2>
|
||
<div class="wd-pin">
|
||
|
||
<header class="pl-pin-header">
|
||
<p class="pl-pin-title">From scattered knowledge to <em>one structured source of truth.</em></p>
|
||
<p class="pl-pin-subtitle">Sources you already have, structured the way you decide — with every fact traceable back to where it came from.</p>
|
||
</header>
|
||
|
||
<!-- Beat-0 anchor: a 1:1 copy of the Wiki pl-card from the
|
||
architecture grid, positioned over the centre column.
|
||
platform.js fades it out as Beat 1 fires. Decorative,
|
||
hidden from AT — the real content is in .wd-body. -->
|
||
<div class="wd-anchor" aria-hidden="true">
|
||
<article class="pl-card">
|
||
<h4 class="pl-card-name">Wiki</h4>
|
||
<p class="pl-card-italic">Company and domain knowledge</p>
|
||
<p class="pl-card-mono">Organizational · Departmental · Personal</p>
|
||
</article>
|
||
</div>
|
||
|
||
<div class="wd-body">
|
||
|
||
<!-- LEFT — Scattered knowledge ---------------------- -->
|
||
<div class="wd-zone wd-zone--scatter">
|
||
<p class="wd-zone-eyebrow">What you have today</p>
|
||
<h3 class="wd-zone-name">Scattered knowledge</h3>
|
||
<p class="wd-zone-sub">Documents · Emails · Notes · Knowledge in people’s heads</p>
|
||
<!-- Bounded scatter cluster.
|
||
Positions follow a loose 4-row × 4-column grid that
|
||
we then jitter from, so density is even across the
|
||
bounded zone — no top-heavy clumps or middle voids.
|
||
Foreground items (full opacity) and background-pile
|
||
items (--o ≈ 0.45) interleave row-by-row so the
|
||
layering is also even rather than stacked.
|
||
|
||
Icon vocabulary unchanged from the previous pass
|
||
(PDF / DOC / slide / note / mail outlines kept as-is);
|
||
only the tacit-knowledge symbol is new — see below. -->
|
||
<div class="wd-scatter" aria-hidden="true">
|
||
|
||
<!-- Row 1 (ty ≈ 6–10%) -->
|
||
<span class="wd-doc" data-doc="pdf" style="--r:-7deg; --tx:6%; --ty:10%; --s:1.05">
|
||
<svg viewBox="0 0 48 60" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M 6 4 H 30 L 42 16 V 56 H 6 Z M 30 4 V 16 H 42" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
|
||
<line x1="12" y1="26" x2="36" y2="26" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="32" x2="36" y2="32" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="38" x2="28" y2="38" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<rect x="9" y="46" width="18" height="8" rx="2" fill="currentColor" opacity="0.18"/>
|
||
<text x="18" y="52.5" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="5.4" font-weight="600" fill="currentColor">PDF</text>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc" data-doc="doc" style="--r:5deg; --tx:34%; --ty:6%; --s:0.96">
|
||
<svg viewBox="0 0 48 60" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M 6 4 H 30 L 42 16 V 56 H 6 Z M 30 4 V 16 H 42" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
|
||
<line x1="12" y1="26" x2="36" y2="26" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="32" x2="36" y2="32" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="38" x2="30" y2="38" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<rect x="9" y="46" width="18" height="8" rx="2" fill="currentColor" opacity="0.18"/>
|
||
<text x="18" y="52.5" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="5.4" font-weight="600" fill="currentColor">DOC</text>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc wd-doc--note" data-doc="note" style="--r:10deg; --tx:68%; --ty:8%; --s:0.78; --o:0.45">
|
||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="5" y="5" width="38" height="38" rx="1.5" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<line x1="11" y1="16" x2="37" y2="16" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="23" x2="33" y2="23" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="30" x2="29" y2="30" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
</svg>
|
||
</span>
|
||
|
||
<!-- Row 2 (ty ≈ 26–32%) -->
|
||
<span class="wd-doc wd-doc--slide" data-doc="ppt" style="--r:6deg; --tx:2%; --ty:28%; --s:0.80; --o:0.45">
|
||
<svg viewBox="0 0 60 44" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="4" y="4" width="52" height="36" rx="2" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<line x1="10" y1="14" x2="30" y2="14" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" opacity="0.75"/>
|
||
<rect x="10" y="20" width="20" height="14" rx="1.5" fill="none" stroke="currentColor" stroke-width="1" opacity="0.55"/>
|
||
<rect x="34" y="20" width="16" height="14" rx="1.5" fill="none" stroke="currentColor" stroke-width="1" opacity="0.55"/>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc" data-doc="pdf" style="--r:11deg; --tx:26%; --ty:32%; --s:0.86; --o:0.45">
|
||
<svg viewBox="0 0 48 60" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M 6 4 H 30 L 42 16 V 56 H 6 Z M 30 4 V 16 H 42" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
|
||
<line x1="12" y1="26" x2="36" y2="26" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="32" x2="36" y2="32" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="38" x2="28" y2="38" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<rect x="9" y="46" width="18" height="8" rx="2" fill="currentColor" opacity="0.18"/>
|
||
<text x="18" y="52.5" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="5.4" font-weight="600" fill="currentColor">PDF</text>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc wd-doc--slide" data-doc="ppt" style="--r:-3deg; --tx:48%; --ty:26%; --s:1.0">
|
||
<svg viewBox="0 0 60 44" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="4" y="4" width="52" height="36" rx="2" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<line x1="10" y1="14" x2="30" y2="14" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" opacity="0.75"/>
|
||
<rect x="10" y="20" width="20" height="14" rx="1.5" fill="none" stroke="currentColor" stroke-width="1" opacity="0.55"/>
|
||
<rect x="34" y="20" width="16" height="14" rx="1.5" fill="none" stroke="currentColor" stroke-width="1" opacity="0.55"/>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc" data-doc="doc" style="--r:-9deg; --tx:72%; --ty:30%; --s:0.84; --o:0.50">
|
||
<svg viewBox="0 0 48 60" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M 6 4 H 30 L 42 16 V 56 H 6 Z M 30 4 V 16 H 42" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
|
||
<line x1="12" y1="26" x2="36" y2="26" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="32" x2="36" y2="32" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="38" x2="30" y2="38" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<rect x="9" y="46" width="18" height="8" rx="2" fill="currentColor" opacity="0.18"/>
|
||
<text x="18" y="52.5" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="5.4" font-weight="600" fill="currentColor">DOC</text>
|
||
</svg>
|
||
</span>
|
||
|
||
<!-- Row 3 (ty ≈ 46–52%) -->
|
||
<span class="wd-doc wd-doc--note" data-doc="note" style="--r:9deg; --tx:10%; --ty:50%; --s:0.98">
|
||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="5" y="5" width="38" height="38" rx="1.5" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<line x1="11" y1="16" x2="37" y2="16" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="23" x2="33" y2="23" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="30" x2="29" y2="30" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="37" x2="25" y2="37" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc wd-doc--mail" data-doc="mail" style="--r:-5deg; --tx:30%; --ty:52%; --s:1.0">
|
||
<svg viewBox="0 0 56 40" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="4" y="6" width="48" height="28" rx="2" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<path d="M 4 10 L 28 24 L 52 10" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" opacity="0.8"/>
|
||
</svg>
|
||
</span>
|
||
<!-- Tacit knowledge: clean person silhouette paired
|
||
with a plain rounded-rectangle "think box". Two
|
||
small connector dots between them act as the
|
||
thought trail. Same stroke weight (1.4) as every
|
||
other icon — drops into the icon family without
|
||
introducing a new shape vocabulary. -->
|
||
<span class="wd-doc wd-doc--tacit" data-doc="tacit" style="--r:3deg; --tx:64%; --ty:48%; --s:1.0">
|
||
<svg viewBox="0 0 60 44" xmlns="http://www.w3.org/2000/svg">
|
||
<!-- person: head + shoulders -->
|
||
<circle cx="14" cy="18" r="7" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<path d="M 4 40 Q 14 30 24 40" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
|
||
<!-- connector dots -->
|
||
<circle cx="26" cy="14" r="1.1" fill="currentColor" opacity="0.7"/>
|
||
<circle cx="31" cy="9" r="0.85" fill="currentColor" opacity="0.55"/>
|
||
<!-- think box: plain rounded rectangle -->
|
||
<rect x="34" y="2" width="22" height="14" rx="2" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
</svg>
|
||
</span>
|
||
|
||
<!-- Row 4 (ty ≈ 68–72%) -->
|
||
<span class="wd-doc wd-doc--note" data-doc="note" style="--r:-4deg; --tx:8%; --ty:72%; --s:0.82; --o:0.50">
|
||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="5" y="5" width="38" height="38" rx="1.5" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<line x1="11" y1="16" x2="37" y2="16" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="23" x2="33" y2="23" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="30" x2="29" y2="30" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="11" y1="37" x2="25" y2="37" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc wd-doc--mail" data-doc="mail" style="--r:8deg; --tx:36%; --ty:70%; --s:0.88; --o:0.45">
|
||
<svg viewBox="0 0 56 40" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="4" y="6" width="48" height="28" rx="2" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4"/>
|
||
<path d="M 4 10 L 28 24 L 52 10" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" opacity="0.8"/>
|
||
</svg>
|
||
</span>
|
||
<span class="wd-doc" data-doc="pdf" style="--r:-6deg; --tx:66%; --ty:72%; --s:0.82; --o:0.50">
|
||
<svg viewBox="0 0 48 60" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M 6 4 H 30 L 42 16 V 56 H 6 Z M 30 4 V 16 H 42" fill="var(--surface-container-lowest)" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/>
|
||
<line x1="12" y1="26" x2="36" y2="26" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="32" x2="36" y2="32" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<line x1="12" y1="38" x2="28" y2="38" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.7"/>
|
||
<rect x="9" y="46" width="18" height="8" rx="2" fill="currentColor" opacity="0.18"/>
|
||
<text x="18" y="52.5" text-anchor="middle" font-family="JetBrains Mono, monospace" font-size="5.4" font-weight="600" fill="currentColor">PDF</text>
|
||
</svg>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Chevron between cluster and compiler. Same SVG mark
|
||
used in #platform-roadmap; reinforces left → right
|
||
reading without bringing back curving flow lines. -->
|
||
<span class="wd-chevron" aria-hidden="true"></span>
|
||
|
||
<!-- MIDDLE — Fenja AI Compiler ---------------------- -->
|
||
<div class="wd-zone wd-zone--compiler">
|
||
<!-- The labels and the card are positioned together
|
||
so the card's vertical centre lines up with the
|
||
chevron midline on either side. The labels are
|
||
grouped in .wd-compiler-head so they can be
|
||
anchored just above the card. -->
|
||
<div class="wd-compiler-head">
|
||
<p class="wd-zone-eyebrow">Fenja Compiler</p>
|
||
<h3 class="wd-zone-name">AI Compiler</h3>
|
||
<p class="wd-zone-sub">Apply your rules and structure to fit your requirements</p>
|
||
</div>
|
||
<!-- Rules card. Outline + paper fill; brand accent is
|
||
reserved for the trust beat. Card centre is held
|
||
at zone vertical centre via absolute positioning
|
||
so it lines up exactly with the chevrons. -->
|
||
<div class="wd-compiler" aria-hidden="true">
|
||
<span class="wd-compiler-label">Rules</span>
|
||
<ul class="wd-compiler-rules">
|
||
<li><span class="wd-rule-toggle"></span><span class="wd-rule-line"></span></li>
|
||
<li><span class="wd-rule-toggle is-on"></span><span class="wd-rule-line"></span></li>
|
||
<li><span class="wd-rule-toggle"></span><span class="wd-rule-line"></span></li>
|
||
<li><span class="wd-rule-toggle is-on"></span><span class="wd-rule-line"></span></li>
|
||
<li><span class="wd-rule-toggle is-on"></span><span class="wd-rule-line"></span></li>
|
||
<li><span class="wd-rule-toggle"></span><span class="wd-rule-line"></span></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Chevron between compiler and stack. -->
|
||
<span class="wd-chevron" aria-hidden="true"></span>
|
||
|
||
<!-- RIGHT — abstract layered page stack -------------- -->
|
||
<div class="wd-zone wd-zone--wiki">
|
||
<p class="wd-zone-eyebrow">Fenja Wiki</p>
|
||
<h3 class="wd-zone-name">Structured output</h3>
|
||
<p class="wd-zone-sub">Structured output · easy for humans and AIs to read.</p>
|
||
<!-- Three abstract knowledge-document cards stacked
|
||
with depth. ALL THREE share the same internal
|
||
layout — title bar, two body sections with body
|
||
lines, subtitle between them, divider, three
|
||
source entries at the bottom. The front card adds
|
||
small superscript citation markers inline within
|
||
the body lines (the trust-beat payoff visible at
|
||
Beat 4); the mid and back cards skip the citation
|
||
markers so they're not legible through the blur,
|
||
but their layout matches so the format reads
|
||
consistently across the stack. -->
|
||
<div class="wd-stack" aria-hidden="true">
|
||
|
||
<div class="wd-stack-card" data-depth="back">
|
||
<span class="wd-stack-rail" aria-hidden="true"></span>
|
||
<div class="wd-stack-content">
|
||
<span class="wd-stack-title-bar"></span>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:30%"></span>
|
||
<span class="wd-stack-bracket"><span style="--bw:16px"></span></span>
|
||
<span class="wd-stack-block" style="--w:24%"></span>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:42%"></span>
|
||
<span class="wd-stack-block" style="--w:24%"></span>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:24%"></span>
|
||
<span class="wd-stack-bracket"><span style="--bw:10px"></span></span>
|
||
<span class="wd-stack-block" style="--w:20%"></span>
|
||
</div>
|
||
<span class="wd-stack-subhead"></span>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:38%"></span>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:30%"></span>
|
||
<span class="wd-stack-block" style="--w:28%"></span>
|
||
</div>
|
||
<hr class="wd-stack-divider"/>
|
||
<div class="wd-stack-sources">
|
||
<div class="wd-stack-source"><sup>1</sup><span class="wd-stack-source-line"></span></div>
|
||
<div class="wd-stack-source"><sup>2</sup><span class="wd-stack-source-line"></span></div>
|
||
<div class="wd-stack-source"><sup>3</sup><span class="wd-stack-source-line"></span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wd-stack-card" data-depth="mid">
|
||
<span class="wd-stack-rail" aria-hidden="true"></span>
|
||
<div class="wd-stack-content">
|
||
<span class="wd-stack-title-bar"></span>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:34%"></span>
|
||
<span class="wd-stack-bracket"><span style="--bw:18px"></span></span>
|
||
<span class="wd-stack-block" style="--w:20%"></span>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:38%"></span>
|
||
<span class="wd-stack-block" style="--w:28%"></span>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:28%"></span>
|
||
<span class="wd-stack-bracket"><span style="--bw:12px"></span></span>
|
||
<span class="wd-stack-block" style="--w:18%"></span>
|
||
</div>
|
||
<span class="wd-stack-subhead"></span>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:44%"></span>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:26%"></span>
|
||
<span class="wd-stack-block" style="--w:30%"></span>
|
||
</div>
|
||
<hr class="wd-stack-divider"/>
|
||
<div class="wd-stack-sources">
|
||
<div class="wd-stack-source"><sup>1</sup><span class="wd-stack-source-line"></span></div>
|
||
<div class="wd-stack-source"><sup>2</sup><span class="wd-stack-source-line"></span></div>
|
||
<div class="wd-stack-source"><sup>3</sup><span class="wd-stack-source-line"></span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wd-stack-card" data-depth="front">
|
||
<span class="wd-stack-rail" aria-hidden="true"></span>
|
||
<div class="wd-stack-content">
|
||
<span class="wd-stack-title-bar"></span>
|
||
<!-- Body block 1: 3 lines with internal-link
|
||
brackets ([ ── ]) and a citation marker. -->
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:30%"></span>
|
||
<span class="wd-stack-bracket"><span style="--bw:14px"></span></span>
|
||
<span class="wd-stack-block" style="--w:22%"></span>
|
||
<sup class="wd-cite" data-cite="1">1</sup>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:40%"></span>
|
||
<span class="wd-stack-block" style="--w:22%"></span>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:26%"></span>
|
||
<span class="wd-stack-bracket"><span style="--bw:18px"></span></span>
|
||
<span class="wd-stack-block" style="--w:18%"></span>
|
||
</div>
|
||
<!-- Subtitle (shorter and darker than body). -->
|
||
<span class="wd-stack-subhead"></span>
|
||
<!-- Body block 2: 2 lines with citation markers. -->
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:42%"></span>
|
||
<sup class="wd-cite" data-cite="2">2</sup>
|
||
</div>
|
||
<div class="wd-stack-line">
|
||
<span class="wd-stack-block" style="--w:28%"></span>
|
||
<span class="wd-stack-block" style="--w:24%"></span>
|
||
<sup class="wd-cite" data-cite="3">3</sup>
|
||
</div>
|
||
<hr class="wd-stack-divider"/>
|
||
<!-- Source list: numbered horizontal lines.
|
||
data-source on each entry lets Beat 4 pair
|
||
the lit in-text citation with its bottom
|
||
entry (the source that the arc traces
|
||
back to in the scatter cluster). -->
|
||
<div class="wd-stack-sources">
|
||
<div class="wd-stack-source" data-source="1"><sup>1</sup><span class="wd-stack-source-line"></span></div>
|
||
<div class="wd-stack-source" data-source="2"><sup>2</sup><span class="wd-stack-source-line"></span></div>
|
||
<div class="wd-stack-source" data-source="3"><sup>3</sup><span class="wd-stack-source-line"></span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
<section id="platform-cards" aria-labelledby="platform-cards-head">
|
||
<header class="platform-cards-head">
|
||
<p class="platform-eyebrow">Deployment options</p>
|
||
<h2 id="platform-cards-head" class="platform-title">Choose your <em>Capability.</em></h2>
|
||
</header>
|
||
|
||
<div class="platform-card-grid" role="list">
|
||
<article class="platform-card" role="listitem">
|
||
<h3 class="platform-card-name">Fenja <em>Core.</em></h3>
|
||
<p class="platform-card-tier">Foundational</p>
|
||
<p class="platform-card-body">Essential LLM capabilities with Fenja Semantic. Your safe and custom chatbot that understands your organization.</p>
|
||
</article>
|
||
|
||
<article class="platform-card" role="listitem">
|
||
<h3 class="platform-card-name">Fenja <em>Dev.</em></h3>
|
||
<p class="platform-card-tier">Developer toolset</p>
|
||
<p class="platform-card-body">Code faster and better with your own secure AI-supported development platform.</p>
|
||
<p class="platform-card-includes">+ Core</p>
|
||
</article>
|
||
|
||
<article class="platform-card" role="listitem">
|
||
<h3 class="platform-card-name">Fenja <em>Analyze.</em></h3>
|
||
<p class="platform-card-tier">Strategic intel</p>
|
||
<p class="platform-card-body">Bring real insights to your people. You ask for an insight, and your agents will find, analyze, and present the relevant data.</p>
|
||
<p class="platform-card-includes">+ Core</p>
|
||
</article>
|
||
|
||
<article class="platform-card is-dark" role="listitem">
|
||
<h3 class="platform-card-name">Fenja <em>Agentic.</em></h3>
|
||
<p class="platform-card-tier">Automation</p>
|
||
<p class="platform-card-body">The complete framework. Fully governed and controlled agents collaborate to solve your most important processes.</p>
|
||
<p class="platform-card-includes">+ Core. Dev. Analyze.</p>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============================================================
|
||
IMPLEMENTATION ROADMAP
|
||
A horizontal sequence of four stages followed by a
|
||
cross-cutting band that runs underneath all of them. The
|
||
four stages are bounded waves of use-case delivery; the
|
||
band is continuous infrastructure work that does NOT end.
|
||
|
||
Content-correctness note (deliberate, do not "tidy"):
|
||
Stages 2–4 are called "Wave" (not "Phase"). The platform
|
||
is installed ONCE at Setup; later waves bring deeper
|
||
layers (knowledge → tools → agents) into ACTIVE USE.
|
||
Card subtitles describe what is now live and in use,
|
||
not what is being deployed. An earlier "Phase 1 =
|
||
Foundation, Phase 2 = Knowledge…" framing was wrong.
|
||
============================================================ -->
|
||
<section id="platform-roadmap" aria-labelledby="platform-roadmap-head">
|
||
<header class="platform-cards-head">
|
||
<p class="platform-eyebrow">Implementation roadmap</p>
|
||
<h2 id="platform-roadmap-head" class="platform-title">
|
||
Set up the platform once, then deliver value in
|
||
<em>waves of use cases.</em>
|
||
</h2>
|
||
</header>
|
||
|
||
<!-- Row of four stage cards + chevrons between each pair. The
|
||
::after chevron on each card except the last gives the
|
||
"sequence" reading; aria-hidden because the cards' DOM
|
||
order already conveys it to assistive tech. -->
|
||
<ol class="rm-row" role="list">
|
||
<!-- Each card is the same DOM element in two states: a
|
||
collapsed face (title / subtitle / meta-at-bottom) and
|
||
an expanded panel (meta moved to the top via flex
|
||
order, then title, subtitle, intro paragraph, key
|
||
activities, all on the same walnut surface). The
|
||
transition between the two is a FLIP layout animation
|
||
driven by initRoadmap → setupRoadmapMorph in
|
||
platform.js — see that file for the animation logic. -->
|
||
<li class="rm-card" role="button" tabindex="0"
|
||
aria-expanded="false" data-detail="setup">
|
||
<h3 class="rm-name">Setup</h3>
|
||
<p class="rm-italic">Platform live in your environment</p>
|
||
<p class="rm-mono">Once · 1–2 weeks</p>
|
||
<div class="rm-card-body" aria-hidden="true">
|
||
<p class="rm-card-intro">The one-time foundation. In a single sprint, the platform goes live inside your infrastructure — model deployed, identity wired in, brand voice applied, baseline policies enforced. After this, the platform is ready to receive any use case.</p>
|
||
<p class="rm-card-section-label">Key activities</p>
|
||
<ul class="rm-card-list">
|
||
<li>Foundation model installed in your environment</li>
|
||
<li>SSO and identity provider connected</li>
|
||
<li>Brand voice, tone, and visual style applied</li>
|
||
<li>Baseline governance and security policies in place</li>
|
||
</ul>
|
||
</div>
|
||
<button class="rm-card-close" type="button" aria-label="Close" tabindex="-1">
|
||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true">
|
||
<path d="M3 3 L11 11"/>
|
||
<path d="M11 3 L3 11"/>
|
||
</svg>
|
||
</button>
|
||
</li>
|
||
|
||
<li class="rm-card" role="button" tabindex="0"
|
||
aria-expanded="false" data-detail="wave-1">
|
||
<h3 class="rm-name">Wave 1</h3>
|
||
<p class="rm-italic">Knowledge captured</p>
|
||
<p class="rm-mono">2–4 weeks per use case</p>
|
||
<div class="rm-card-body" aria-hidden="true">
|
||
<p class="rm-card-intro">The first body of use cases captures what your organisation already knows. For each use case, the team scopes the target output, ingests the right files, and runs AI-led interviews to surface the knowledge that today lives only in people’s heads.</p>
|
||
<p class="rm-card-section-label">Key activities</p>
|
||
<ul class="rm-card-list">
|
||
<li>Use case scope and target output defined</li>
|
||
<li>Relevant files ingested and structured</li>
|
||
<li>AI-led interviews capture tacit expert knowledge</li>
|
||
<li>Outputs tested and validated against real work</li>
|
||
</ul>
|
||
</div>
|
||
<button class="rm-card-close" type="button" aria-label="Close" tabindex="-1">
|
||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true">
|
||
<path d="M3 3 L11 11"/>
|
||
<path d="M11 3 L3 11"/>
|
||
</svg>
|
||
</button>
|
||
</li>
|
||
|
||
<li class="rm-card" role="button" tabindex="0"
|
||
aria-expanded="false" data-detail="wave-2">
|
||
<h3 class="rm-name">Wave 2</h3>
|
||
<p class="rm-italic">Systems connected</p>
|
||
<p class="rm-mono">1–4 weeks per use case</p>
|
||
<div class="rm-card-body" aria-hidden="true">
|
||
<p class="rm-card-intro">Use cases that reach beyond knowledge into your systems. Each tool implementation wires the platform into a specific source or destination — a data warehouse, a SharePoint repository, an API, a structured report. The platform stops being read-only and starts acting on your behalf.</p>
|
||
<p class="rm-card-section-label">Key activities</p>
|
||
<ul class="rm-card-list">
|
||
<li>Ongoing retrieval from data warehouses and SharePoint</li>
|
||
<li>Read and write integrations to specific APIs</li>
|
||
<li>Custom report outputs and structured deliverables</li>
|
||
<li>Each tool scoped, built, and tested for one specific job</li>
|
||
</ul>
|
||
</div>
|
||
<button class="rm-card-close" type="button" aria-label="Close" tabindex="-1">
|
||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true">
|
||
<path d="M3 3 L11 11"/>
|
||
<path d="M11 3 L3 11"/>
|
||
</svg>
|
||
</button>
|
||
</li>
|
||
|
||
<li class="rm-card" role="button" tabindex="0"
|
||
aria-expanded="false" data-detail="wave-3">
|
||
<h3 class="rm-name">Wave 3+</h3>
|
||
<p class="rm-italic">Agents at work</p>
|
||
<p class="rm-mono">1–4 weeks per use case</p>
|
||
<div class="rm-card-body" aria-hidden="true">
|
||
<p class="rm-card-intro">Use cases that compose multiple steps into one governed workflow. For each agent use case, the team defines the task, builds the specialist agents that handle it, and configures monitoring, human checkpoints, and governance at every step. The platform now does work end to end — under your control.</p>
|
||
<p class="rm-card-section-label">Key activities</p>
|
||
<ul class="rm-card-list">
|
||
<li>Agent tasks defined and scoped per workflow</li>
|
||
<li>Specialist agents built for specific jobs</li>
|
||
<li>Monitoring and audit trails configured</li>
|
||
<li>Human-in-the-loop checkpoints placed where they matter</li>
|
||
<li>Governance and security checks enforced at each step</li>
|
||
</ul>
|
||
</div>
|
||
<button class="rm-card-close" type="button" aria-label="Close" tabindex="-1">
|
||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true">
|
||
<path d="M3 3 L11 11"/>
|
||
<path d="M11 3 L3 11"/>
|
||
</svg>
|
||
</button>
|
||
</li>
|
||
</ol>
|
||
|
||
<!-- Cross-cutting band — continuous infrastructure work that
|
||
spans all four stages. Visually neutral (paper surface,
|
||
not the walnut accent) to read as "always on", not as a
|
||
fifth deliverable. -->
|
||
<div class="rm-band" role="group" aria-label="Continuous work alongside every stage">
|
||
<p class="rm-band-name">Govern & scale</p>
|
||
<p class="rm-band-italic">Security · compliance · change management · training · advisory council feedback</p>
|
||
<!-- Speaker note: Continuous from day one — security and
|
||
compliance, change management and training, governance
|
||
cadence (audit, model risk, policy), and (for Bifrost
|
||
members) the advisory council loop feeding back into
|
||
the roadmap. -->
|
||
</div>
|
||
|
||
<p class="rm-foot">
|
||
Setup is bounded · waves of use cases continue as your needs evolve.
|
||
</p>
|
||
</section>
|
||
|
||
|
||
</div><!-- /#overview-scroll -->
|
||
</section>
|
||
|
||
<!-- Dot-nav tray + nav (shared across all pages)
|
||
Eight entries — one per major section of the customer
|
||
presentation, in scroll order:
|
||
1. Welcome — external; routes to /
|
||
2. Timeline — Timeline page (P1)
|
||
3. Fenja introduction — Overview page (P2), scene #hero
|
||
4. Project Bifrost — Overview page (P2), scene #bifrost
|
||
(also covers #bifrost-meaning, the
|
||
treasure-map continuation)
|
||
5. Architecture — Overview page (P2), scene
|
||
#platform-layers (also covers
|
||
#platform-question, the framing
|
||
lead-in)
|
||
6. Wiki — Overview page (P2), scene
|
||
#wiki-deepdive
|
||
7. Deployment — Overview page (P2), scene
|
||
#platform-cards
|
||
8. Roadmap — Overview page (P2), scene
|
||
#platform-roadmap
|
||
|
||
data-target : page id to activate, OR `external-*` for a
|
||
cross-page navigation (uses data-href).
|
||
data-scroll-to : (optional, Overview only) element id inside
|
||
#overview-scroll to scroll to AFTER the page
|
||
switch. Scroll runs on the Overview's internal
|
||
scroller via Lenis (if booted) or
|
||
scroller.scrollTo() as a fallback. The
|
||
sceneOrder / sceneToDot maps in bifrost.js
|
||
must include every scrollable scene so the
|
||
scroll-spy highlights the right dot as the
|
||
user moves through. -->
|
||
<div class="dot-nav-tray"></div>
|
||
<nav class="dot-nav">
|
||
<button class="dot-btn" data-target="external-welcome" data-href="/" aria-label="Return to welcome page">
|
||
<span class="dot"></span>
|
||
<span class="label">Welcome</span>
|
||
</button>
|
||
<button class="dot-btn is-active" data-target="page-timeline">
|
||
<span class="dot"></span>
|
||
<span class="label">Timeline</span>
|
||
</button>
|
||
<button class="dot-btn" data-target="page-overview" data-scroll-to="hero">
|
||
<span class="dot"></span>
|
||
<span class="label">Fenja introduction</span>
|
||
</button>
|
||
<button class="dot-btn" data-target="page-overview" data-scroll-to="bifrost">
|
||
<span class="dot"></span>
|
||
<span class="label">Project Bifrost</span>
|
||
</button>
|
||
<button class="dot-btn" data-target="page-overview" data-scroll-to="platform-layers">
|
||
<span class="dot"></span>
|
||
<span class="label">Architecture</span>
|
||
</button>
|
||
<button class="dot-btn" data-target="page-overview" data-scroll-to="wiki-deepdive">
|
||
<span class="dot"></span>
|
||
<span class="label">Wiki</span>
|
||
</button>
|
||
<button class="dot-btn" data-target="page-overview" data-scroll-to="platform-cards">
|
||
<span class="dot"></span>
|
||
<span class="label">Deployment</span>
|
||
</button>
|
||
<button class="dot-btn" data-target="page-overview" data-scroll-to="platform-roadmap">
|
||
<span class="dot"></span>
|
||
<span class="label">Roadmap</span>
|
||
</button>
|
||
</nav>
|
||
|
||
<script src="/vendor/lenis.min.js" defer></script>
|
||
<script src="/vendor/gsap.min.js" defer></script>
|
||
<script src="/vendor/scrolltrigger.min.js" defer></script>
|
||
<script src="/bifrost.js" defer></script>
|
||
<script src="/platform.js" defer></script>
|
||
<script src="/timeline.js" defer></script>
|
||
|
||
</body>
|
||
</html>
|